Merge from 0.9.18
authorunc0rr
Sun, 18 Nov 2012 23:10:26 +0400
changeset 8061 c08e9c3e0737
parent 8060 341fa76d0749 (diff)
parent 7958 c031c3e2eb2a (current diff)
child 8066 1a61fe7c160d
Merge from 0.9.18
hedgewars/GSHandlers.inc
--- a/.hgignore	Sun Nov 18 23:09:29 2012 +0400
+++ b/.hgignore	Sun Nov 18 23:10:26 2012 +0400
@@ -41,7 +41,7 @@
 glob:*.rej
 glob:project_files/Android-build/SDL-android-project/jni/**
 glob:project_files/Android-build/SDL-android-project/obj
-glob:project_files/Android-build/SDL-android-project/libs
+glob:project_files/Android-build/SDL-android-project/libs/armeabi*
 glob:project_files/Android-build/SDL-android-project/bin
 glob:project_files/Android-build/SDL-android-project/gen
 glob:project_files/Android-build/SDL-android-project/local.properties
--- a/CMakeLists.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/CMakeLists.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -12,7 +12,7 @@
 
 
 #detect Mercurial revision (if present)
-set(version_suffix "") #UNSET THIS VARIABLE AT RELEASE TIME
+set(version_suffix "-dev") #UNSET THIS VARIABLE AT RELEASE TIME
 set(HGCHANGED "")
 IF(version_suffix MATCHES "-dev")
     set(HW_DEV true)
@@ -43,8 +43,8 @@
 #versioning
 set(CPACK_PACKAGE_VERSION_MAJOR 0)
 set(CPACK_PACKAGE_VERSION_MINOR 9)
-set(CPACK_PACKAGE_VERSION_PATCH 18${version_suffix})
-set(HEDGEWARS_PROTO_VER 43)
+set(CPACK_PACKAGE_VERSION_PATCH 19${version_suffix})
+set(HEDGEWARS_PROTO_VER 44)
 set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
 
 
@@ -55,7 +55,6 @@
 
 option(BUILD_ENGINE_LIBRARY "Enable hwengine library [default: off]" OFF)
 option(ANDROID "Enable Android build [default: off]" OFF)
-
 option(NOAUTOUPDATE "Disable OS X Sparkle update checking" OFF)
 option(CROSSAPPLE "Enable OSX when not on OSX [default: off]" OFF)
 option(MINIMAL_FLAGS "Respect system flags as much as possible [default: off]" OFF)
@@ -248,6 +247,10 @@
 #main engine
 add_subdirectory(hedgewars)
 
+# physfs library
+add_subdirectory(misc/physfs)
+add_subdirectory(misc/physfs/extras)
+
 #Android related build scripts
 if(ANDROID)
     #run cmake -DANDROID=1 to enable this
@@ -257,7 +260,6 @@
 #TODO: when ANDROID, BUILD_ENGINE_LIBRARY should be set
 if(NOT (BUILD_ENGINE_LIBRARY OR ANDROID))
     add_subdirectory(bin)
-    add_subdirectory(misc/quazip)
     add_subdirectory(QTfrontend)
     add_subdirectory(share)
     add_subdirectory(tools)
--- a/QTfrontend/CMakeLists.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/CMakeLists.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -15,16 +15,6 @@
     include(${QT_USE_FILE})
 endif()
 
-# Check if we need zlib
-check_library_exists("${QT_QTCORE_LIBRARY}" inflateInit2_ ${QT_LIBRARY_DIR} QT_PROVIDES_ZLIB_FUNCTIONS)
-
-if(NOT QT_PROVIDES_ZLIB_FUNCTIONS)
-    find_package(ZLIB REQUIRED)
-
-    set(HW_LINK_LIBS ${ZLIB_LIBRARIES} ${HW_LINK_LIBS})
-endif()
-
-
 # Configure for SDL
 find_package(SDL REQUIRED)
 find_package(SDL_mixer REQUIRED)
@@ -43,7 +33,8 @@
 include_directories(${SDL_INCLUDE_DIR})
 include_directories(${SDLMIXER_INCLUDE_DIR})
 include_directories(${FFMPEG_INCLUDE_DIR})
-include_directories(${CMAKE_SOURCE_DIR}/misc/quazip)
+include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src)
+include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/extras)
 if(UNIX)
     # HACK: in freebsd cannot find iconv.h included via SDL.h
     include_directories("/usr/local/include")
@@ -140,7 +131,6 @@
     achievements.h
     binds.h
     ui_hwform.h
-    KB.h
     hwconsts.h
     sdlkeys.h
     campaign.h
@@ -177,7 +167,8 @@
 
 
 set(HW_LINK_LIBS
-    quazip
+    physfs
+    physfsrwops
     ${QT_LIBRARIES}
     ${SDL_LIBRARY}
     ${SDLMIXER_LIBRARY}
@@ -201,7 +192,7 @@
 
 
 if (CROSSAPPLE)
-    add_dependencies(hedgewars quazip)
+
 else()
     target_link_libraries(hedgewars ${HW_LINK_LIBS})
 endif()
--- a/QTfrontend/campaign.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/campaign.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -56,7 +56,7 @@
 
 QStringList getCampMissionList(QString & campaign)
 {
-    QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0);
+    QSettings campfile("physfs://Missions/Campaign/" + campaign + "/campaign.ini", QSettings::IniFormat, 0);
     campfile.setIniCodec("UTF-8");
     unsigned int mNum = campfile.value("MissionNum", 0).toInt();
     
@@ -77,7 +77,7 @@
 
 QString getCampaignScript(QString campaign, unsigned int mNum)
 {
-    QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0);
+    QSettings campfile("physfs://Missions/Campaign/" + campaign + "/campaign.ini", QSettings::IniFormat, 0);
     campfile.setIniCodec("UTF-8");
     return campfile.value(QString("Mission %1/Script").arg(mNum)).toString();
 }
--- a/QTfrontend/game.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/game.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -28,7 +28,6 @@
 #include "gameuiconfig.h"
 #include "gamecfgwidget.h"
 #include "teamselect.h"
-#include "KB.h"
 #include "proto.h"
 #include "campaign.h"
 
@@ -230,20 +229,6 @@
             emit ErrorMessage(QString("Last two engine messages:\n") + QString().append(msg.mid(2)).left(size - 4));
             return;
         }
-        case 'K':
-        {
-            ulong kb = msg.mid(2).toULong();
-            if (kb==1)
-            {
-                qWarning("%s", KBMessages[kb - 1].toLocal8Bit().constData());
-                return;
-            }
-            if (kb && kb <= KBmsgsCount)
-            {
-                emit ErrorMessage(KBMessages[kb - 1]);
-            }
-            return;
-        }
         case 'i':
         {
             emit GameStats(msg.at(2), QString::fromUtf8(msg.mid(3)));
@@ -269,7 +254,6 @@
             int size = msg.size();
             QString msgbody = QString::fromUtf8(msg.mid(2).left(size - 4));
             emit SendChat(msgbody);
-            // FIXME: /me command doesn't work here
             QByteArray buf;
             HWProto::addStringToBuffer(buf, "s" + HWProto::formatChatMsg(config->netNick(), msgbody) + "\x20\x20");
             demo.append(buf);
@@ -296,8 +280,7 @@
             {
                 emit SendNet(msg);
             }
-            if (msg.at(1) != 's')
-                demo.append(msg);
+            demo.append(msg);
         }
     }
 }
--- a/QTfrontend/hwform.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/hwform.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -122,9 +122,7 @@
     , hwnet(0)
 {
     // set music track
-    SDLInteraction::instance().setMusicTrack(
-        DataManager::instance().findFileForRead("Music/main_theme.ogg")
-    );
+    SDLInteraction::instance().setMusicTrack("/Music/main_theme.ogg");
 
 #ifdef USE_XFIRE
     xfire_init();
@@ -189,10 +187,8 @@
     connect(ui.pageMain->BtnSetup, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageMain->BtnSetup, ID_PAGE_SETUP);
 
-#if 0
     connect(ui.pageMain->BtnFeedback, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageMain->BtnFeedback, ID_PAGE_FEEDBACK);
-#endif
 
     connect(ui.pageMain->BtnNet, SIGNAL(clicked()), pageSwitchMapper, SLOT(map()));
     pageSwitchMapper->setMapping(ui.pageMain->BtnNet, ID_PAGE_NETTYPE);
--- a/QTfrontend/main.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/main.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -33,6 +33,7 @@
 #include "newnetclient.h"
 
 #include "DataManager.h"
+#include "FileEngine.h"
 
 #ifdef _WIN32
 #include <Shlobj.h>
@@ -106,6 +107,8 @@
 {
     HWApplication app(argc, argv);
 
+    FileEngineHandler engine(argv[0]);
+
     app.setAttribute(Qt::AA_DontShowIconsInMenus,false);
 
     QStringList arguments = app.arguments();
@@ -147,7 +150,7 @@
         custom_config = true;
     }
 
-    app.setStyle(new QPlastiqueStyle);
+    app.setStyle(new QPlastiqueStyle());
 
     QDateTime now = QDateTime::currentDateTime();
     srand(now.toTime_t());
@@ -218,21 +221,23 @@
         return 1;
     }
 
-    DataManager & dataMgr = DataManager::instance();
+    // setup PhysFS
+    engine.mount(datadir->absolutePath());
+    engine.mount(cfgdir->absolutePath() + "/Data");
+    engine.mount(cfgdir->absolutePath(), "/config");
+    engine.setWriteDir(cfgdir->absolutePath());
+    engine.mountPacks();
 
     QTranslator Translator;
     {
-        QSettings settings(cfgdir->absolutePath() + "/hedgewars.ini", QSettings::IniFormat);
+        QSettings settings("physfs://config/hedgewars.ini", QSettings::IniFormat);
         QString cc = settings.value("misc/locale", QString()).toString();
         if(cc.isEmpty())
             cc = QLocale::system().name();
 
         // load locale file into translator
-        Translator.load(
-            dataMgr.findFileForRead(
-                QString("Locale/hedgewars_" + cc)
-            )
-        );
+        if(!Translator.load(QString("physfs://Locale/hedgewars_%1").arg(cc)))
+            qWarning("Failed to install translation");
         app.installTranslator(&Translator);
     }
 
@@ -274,7 +279,7 @@
     }
 
     // load external stylesheet if there is any
-    QFile extFile(dataMgr.findFileForRead("css/" + fname));
+    QFile extFile("physfs://css/" + fname);
 
     QFile resFile(":/res/css/" + fname);
 
--- a/QTfrontend/model/GameStyleModel.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/model/GameStyleModel.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -55,8 +55,7 @@
     {
         script = script.remove(".lua", Qt::CaseInsensitive);
 
-        QFile scriptCfgFile(DataManager::instance().findFileForRead(
-                            QString("Scripts/Multiplayer/%2.cfg").arg(script)));
+        QFile scriptCfgFile(QString("physfs://Scripts/Multiplayer/%2.cfg").arg(script));
 
         QString name = script;
         name = name.replace("_", " ");
--- a/QTfrontend/model/HatModel.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/model/HatModel.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -46,9 +46,7 @@
 
     DataManager & dataMgr = DataManager::instance();
 
-    QPixmap hhpix = QPixmap(
-                        dataMgr.findFileForRead("Graphics/Hedgehog/Idle.png")
-                    ).copy(0, 0, 32, 32);
+    QPixmap hhpix = QPixmap("physfs://Graphics/Hedgehog/Idle.png").copy(0, 0, 32, 32);
 
     // my reserved hats
     QStringList hatsList = dataMgr.entryList(
@@ -76,11 +74,9 @@
 
         QString str = hatsList.at(i);
         str = str.remove(QRegExp("\\.png$"));
-        QPixmap pix(
-            dataMgr.findFileForRead(
-                "Graphics/Hats/" + QString(isReserved?"Reserved/":"") + str +
-                ".png"
-            )
+        QPixmap pix(            
+                "physfs://Graphics/Hats/" + QString(isReserved?"Reserved/":"") + str +
+                ".png"           
         );
 
         // rename properly
--- a/QTfrontend/model/MapModel.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/model/MapModel.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -62,10 +62,8 @@
     // add mission/static maps to lists
     foreach (QString map, maps)
     {
-        mapCfgFile.setFileName(
-            datamgr.findFileForRead(QString("Maps/%1/map.cfg").arg(map)));
-        mapLuaFile.setFileName(
-            datamgr.findFileForRead(QString("Maps/%1/map.lua").arg(map)));
+        mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map));
+        mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map));
 
 
         if (mapCfgFile.open(QFile::ReadOnly))
--- a/QTfrontend/model/ThemeModel.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/model/ThemeModel.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -66,8 +66,7 @@
     foreach (QString theme, themes)
     {
         // themes without icon are supposed to be hidden
-        QString iconpath =
-            datamgr.findFileForRead(QString("Themes/%1/icon.png").arg(theme));
+        QString iconpath = QString("physfs://Themes/%1/icon.png").arg(theme);
 
         if (!QFile::exists(iconpath))
             continue;
@@ -79,10 +78,11 @@
 
         // load and set icon
         QIcon icon(iconpath);
+
         dataset.insert(Qt::DecorationRole, icon);
 
         // load and set preview icon
-        QIcon preview(datamgr.findFileForRead(QString("Themes/%1/icon@2x.png").arg(theme)));
+        QIcon preview(QString("physfs://Themes/%1/icon@2x.png").arg(theme));
         dataset.insert(Qt::UserRole, preview);
 
         m_data.append(dataset);
--- a/QTfrontend/net/newnetclient.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/net/newnetclient.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -380,11 +380,13 @@
         {
             flags.remove(0, 1);
             char c = flags[0].toAscii();
+            bool inRoom = (netClientState == InRoom || netClientState == InGame);
 
             switch(c)
             {
                 // flag indicating if a player is ready to start a game
                 case 'r':
+                    if(inRoom)
                         foreach (const QString & nick, nicks)
                         {
                             if (nick == mynick)
@@ -401,14 +403,16 @@
                         foreach(const QString & nick, nicks)
                             m_playersModel->setFlag(nick, PlayersListModel::Registered, setFlag);
                         break;
-
+                // flag indicating if a player has engine running
                 case 'g':
+                    if(inRoom)
                         foreach(const QString & nick, nicks)
                             m_playersModel->setFlag(nick, PlayersListModel::InGame, setFlag);
                         break;
 
                 // flag indicating if a player is the host/master of the room
                 case 'h':
+                    if(inRoom)
                         foreach (const QString & nick, nicks)
                         {
                             if (nick == mynick)
--- a/QTfrontend/net/newnetclient.h	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/net/newnetclient.h	Sun Nov 18 23:10:26 2012 +0400
@@ -74,27 +74,6 @@
         QSortFilterProxyModel * m_lobbyPlayersModel;
         QSortFilterProxyModel * m_roomPlayersModel;
 
-        template <typename T>
-        void SendCfgStrNet(T a)
-        {
-            QByteArray strmsg;
-            strmsg.append(a);
-            quint8 sz = strmsg.size();
-            QByteArray enginemsg = QByteArray((char *)&sz, 1) + strmsg;
-            QString _msg = delimeter + QString(enginemsg.toBase64());
-            RawSendNet(_msg);
-        }
-
-        template <typename T>
-        void SendCfgStrLoc(T a)
-        {
-            QByteArray strmsg;
-            strmsg.append(QString(a).toUtf8());
-            quint8 sz = strmsg.size();
-            QByteArray enginemsg = QByteArray((char *)&sz, 1) + strmsg;
-            emit FromNet(enginemsg);
-        }
-
         QStringList cmdbuf;
 
         void RawSendNet(const QString & buf);
--- a/QTfrontend/team.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/team.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -169,7 +169,7 @@
 
 bool HWTeam::loadFromFile()
 {
-    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt", QSettings::IniFormat, 0);
+    QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
     teamfile.setIniCodec("UTF-8");
     m_name = teamfile.value("Team/Name", m_name).toString();
     m_grave = teamfile.value("Team/Grave", "Statue").toString();
@@ -202,7 +202,7 @@
 
 bool HWTeam::fileExists()
 {
-    QFile f(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt");
+    QFile f(QString("physfs://config/Teams/%1.hwt").arg(m_name));
     return f.exists();
 }
 
@@ -210,7 +210,7 @@
 {
     if(m_isNetTeam)
         return false;
-    QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt");
+    QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(m_name));
     cfgfile.remove();
     return true;
 }
@@ -219,11 +219,11 @@
 {
     if (OldTeamName != m_name)
     {
-        QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + OldTeamName + ".hwt");
+        QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(OldTeamName));
         cfgfile.remove();
         OldTeamName = m_name;
     }
-    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt", QSettings::IniFormat, 0);
+    QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0);
     teamfile.setIniCodec("UTF-8");
     teamfile.setValue("Team/Name", m_name);
     teamfile.setValue("Team/Grave", m_grave);
--- a/QTfrontend/ui/mouseoverfilter.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/mouseoverfilter.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -41,8 +41,7 @@
         QTabWidget * tab = dynamic_cast<QTabWidget*>(dist);
         if (HWForm::config->isFrontendSoundEnabled() && (button || textfield || checkbox || droplist || slider || tab))
         {
-            DataManager & dataMgr = DataManager::instance();
-            SDLInteraction::instance().playSoundFile(dataMgr.findFileForRead("Sounds/steps.ogg"));
+            SDLInteraction::instance().playSoundFile("/Sounds/steps.ogg");
         }
 
         return true;
--- a/QTfrontend/ui/page/pagedata.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/page/pagedata.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -31,9 +31,7 @@
 #include "databrowser.h"
 #include "hwconsts.h"
 #include "DataManager.h"
-
-#include "quazip.h"
-#include "quazipfile.h"
+#include "FileEngine.h"
 
 QLayout * PageDataDownload::bodyLayoutDefinition()
 {
@@ -74,7 +72,7 @@
     else
         finalUrl = url;
 
-    if(url.path().endsWith(".zip"))
+    if(url.path().endsWith(".hwp") || url.path().endsWith(".zip"))
     {
         qWarning() << "Download Request" << url.toString();
         QString fileName = QFileInfo(url.toString()).fileName();
@@ -128,7 +126,6 @@
 
     if(reply)
     {
-        QByteArray fileContents = reply->readAll();
         QProgressBar *progressBar = progressBars.value(reply, 0);
 
         if(progressBar)
@@ -137,7 +134,26 @@
             progressBar->deleteLater();
         }
 
-        extractDataPack(&fileContents);
+        QDir extractDir(*cfgdir);
+        extractDir.cd("Data");
+
+        QString fileName = extractDir.filePath(QFileInfo(reply->url().path()).fileName());
+        if(fileName.endsWith(".zip"))
+            fileName = fileName.left(fileName.length() - 4) + ".hwp";
+
+        QFile out(fileName);
+        if(!out.open(QFile::WriteOnly))
+        {
+            qWarning() << "out.open():" << out.errorString();
+            return ;
+        }
+
+        out.write(reply->readAll());
+
+        out.close();
+
+        // now mount it
+        FileEngineHandler::mount(fileName);
     }
 }
 
@@ -162,83 +178,6 @@
     request(QUrl("http://hedgewars.org/content.html"));
 }
 
-bool PageDataDownload::extractDataPack(QByteArray * buf)
-{
-    QBuffer buffer;
-    buffer.setBuffer(buf);
-
-    QuaZip zip;
-    zip.setIoDevice(&buffer);
-    if(!zip.open(QuaZip::mdUnzip))
-    {
-        qWarning("testRead(): zip.open(): %d", zip.getZipError());
-        return false;
-    }
-
-    QuaZipFile file(&zip);
-
-    QDir extractDir(*cfgdir);
-    extractDir.cd("Data");
-
-    for(bool more = zip.goToFirstFile(); more; more = zip.goToNextFile())
-    {
-        if(!file.open(QIODevice::ReadOnly))
-        {
-            qWarning("file.open(): %d", file.getZipError());
-            return false;
-        }
-
-
-        QString fileName = file.getActualFileName();
-        QString filePath = extractDir.filePath(fileName);
-        if (fileName.endsWith("/"))
-        {
-            QFileInfo fi(filePath);
-            QDir().mkpath(fi.filePath());
-        }
-        else
-        {
-            qDebug() << "Extracting" << filePath;
-            QFile out(filePath);
-            if(!out.open(QFile::WriteOnly))
-            {
-                qWarning() << "out.open():" << out.errorString();
-                return false;
-            }
-
-            out.write(file.readAll());
-
-            out.close();
-
-            if(file.getZipError() != UNZ_OK)
-            {
-                qWarning("file.getFileName(): %d", file.getZipError());
-                return false;
-            }
-
-            if(!file.atEnd())
-            {
-                qWarning("read all but not EOF");
-                return false;
-            }
-
-            m_contentDownloaded = true;
-        }
-
-        file.close();
-
-        if(file.getZipError()!=UNZ_OK)
-        {
-            qWarning("file.close(): %d", file.getZipError());
-            return false;
-        }
-    }
-
-    zip.close();
-
-    return true;
-}
-
 
 void PageDataDownload::onPageLeave()
 {
--- a/QTfrontend/ui/page/pagedata.h	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/page/pagedata.h	Sun Nov 18 23:10:26 2012 +0400
@@ -48,8 +48,6 @@
 
         bool m_contentDownloaded; ///< true if something was downloaded since last page leave
 
-        bool extractDataPack(QByteArray * buf);
-
     private slots:
         void request(const QUrl &url);
 
--- a/QTfrontend/ui/page/pageeditteam.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/page/pageeditteam.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -270,7 +270,7 @@
 
     foreach (QString file, list)
     {
-        QPixmap pix(dataMgr.findFileForRead("Graphics/Graves/" + file));
+        QPixmap pix("physfs://Graphics/Graves/" + file);
         if ((pix.height() > 32) || pix.width() > 32)
             pix = pix.copy(0, 0, 32, 32);
         QIcon icon(pix);
@@ -297,7 +297,7 @@
         list.removeAt(idx);
 
     // add the default flag
-    QPixmap hwFlag(dataMgr.findFileForRead("Graphics/Flags/hedgewars.png"));
+    QPixmap hwFlag("physfs://Graphics/Flags/hedgewars.png");
     CBFlag->addItem(QIcon(hwFlag.copy(0, 0, 22, 15)), "Hedgewars", "hedgewars");
 
     // add seperator after
@@ -308,7 +308,7 @@
     // add all country flags
     foreach (const QString & file, list)
     {
-        QIcon icon(QPixmap(dataMgr.findFileForRead("Graphics/Flags/" + file)));
+        QIcon icon(QPixmap("physfs://Graphics/Flags/" + file));
 
         QString flag = QString(file).remove(pngSuffix);
 
@@ -337,8 +337,7 @@
 
 void PageEditTeam::CBFort_activated(const QString & fortname)
 {
-    DataManager & dataMgr = DataManager::instance();
-    QPixmap pix(dataMgr.findFileForRead("Forts/" + fortname + "L.png"));
+    QPixmap pix("physfs://Forts/" + fortname + "L.png");
     FortPreview->setPixmap(pix);
 }
 
@@ -360,10 +359,8 @@
                        );
 
     if (!list.isEmpty())
-        SDLInteraction::instance().playSoundFile(
-            dataMgr.findFileForRead(voiceDir + "/" +
-                                    list[rand() % list.size()])
-        );
+        SDLInteraction::instance().playSoundFile("physfs://" + voiceDir + "/" +
+                                    list[rand() % list.size()]);
 }
 
 void PageEditTeam::createTeam(const QString & name, const QString & playerHash)
--- a/QTfrontend/ui/page/pagemain.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/page/pagemain.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -58,11 +58,9 @@
     BtnInfo->setWhatsThis(tr("Read about who is behind the Hedgewars Project"));
     pageLayout->setAlignment(BtnInfo, Qt::AlignHCenter);
 
-#if 0
     BtnFeedback = addButton("Feedback", pageLayout, 4, 0, 1, 4, false);
     BtnFeedback->setWhatsThis(tr("Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars"));
     pageLayout->setAlignment(BtnFeedback, Qt::AlignHCenter);
-#endif
 
     BtnDataDownload = addButton(tr("Downloadable Content"), pageLayout, 5, 0, 1, 4, false);
     //BtnDataDownload->setToolTip(tr(Downloadable Content"));
--- a/QTfrontend/ui/page/pagetraining.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/page/pagetraining.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -125,17 +125,15 @@
     if (loc.isEmpty())
         loc = QLocale::system().name();
 
-    QString infoFile = dataMgr.findFileForRead(
-                           QString("Locale/missions_" + loc + ".txt"));
+    QString infoFile = QString("physfs://Locale/missions_" + loc + ".txt");
 
     // if file is non-existant try with language only
     if (!QFile::exists(infoFile))
-        infoFile = dataMgr.findFileForRead(QString(
-                                               "Locale/missions_" + loc.remove(QRegExp("_.*$")) + ".txt"));
+        infoFile = QString("physfs://Locale/missions_" + loc.remove(QRegExp("_.*$")) + ".txt");
 
     // fallback if file for current locale is non-existant
     if (!QFile::exists(infoFile))
-        infoFile = dataMgr.findFileForRead(QString("Locale/missions_en.txt"));
+        infoFile = QString("physfs://Locale/missions_en.txt");
 
 
     // preload mission info for current locale
@@ -186,15 +184,12 @@
 
 void PageTraining::updateInfo()
 {
-    DataManager & dataMgr = DataManager::instance();
-
     if (lstMissions->currentItem())
     {
         // TODO also use .pngs in userdata folder
-        QString thumbFile = dataMgr.findFileForRead(
-                                "Graphics/Missions/Training/" +
+        QString thumbFile =     "physfs://Graphics/Missions/Training/" +
                                 lstMissions->currentItem()->data(Qt::UserRole).toString() +
-                                "@2x.png");
+                                "@2x.png";
 
         if (QFile::exists(thumbFile))
             btnPreview->setIcon(QIcon(thumbFile));
--- a/QTfrontend/ui/widget/chatwidget.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/widget/chatwidget.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -64,7 +64,7 @@
     if (orgStyleSheet.isEmpty())
     {
         // load external stylesheet if there is any
-        QFile extFile(DataManager::instance().findFileForRead("css/chat.css"));
+        QFile extFile("physfs://css/chat.css");
 
         QFile resFile(":/res/css/chat.css");
 
@@ -194,12 +194,10 @@
 
         foreach (QString vp, vpList)
         {
-            m_helloSounds.append(DataManager::instance().findFileForRead(
-                               QString("Sounds/voices/%1/Hello.ogg").arg(vp)));
+            m_helloSounds.append(QString("physfs://Sounds/voices/%1/Hello.ogg").arg(vp));
         }
 
-        m_hilightSound = DataManager::instance().findFileForRead(
-                             "Sounds/beep.ogg");
+        m_hilightSound = "physfs://Sounds/beep.ogg";
 
     }
 
@@ -762,8 +760,7 @@
 
 void HWChatWidget::saveStyleSheet()
 {
-    QString dest =
-        DataManager::instance().findFileForWrite("css/chat.css");
+    QString dest = "physfs://css/chat.css";
 
     QFile file(dest);
     if (file.open(QIODevice::WriteOnly | QIODevice::Text))
--- a/QTfrontend/ui/widget/mapContainer.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/widget/mapContainer.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -606,10 +606,7 @@
             break;
         default:
             QPixmap mapImage;
-            bool success = mapImage.load(
-                DataManager::instance().findFileForRead(
-                    "Maps/" + m_mapInfo.name + "/preview.png")
-            );
+            bool success = mapImage.load("physfs://Maps/" + m_mapInfo.name + "/preview.png");
 
             if(!success)
             {
--- a/QTfrontend/ui/widget/qpushbuttonwithsound.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/ui/widget/qpushbuttonwithsound.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -36,8 +36,6 @@
     if ( !isSoundEnabled || !HWForm::config->isFrontendSoundEnabled())
         return;
 
-    DataManager & dataMgr = DataManager::instance();
-
     if (this->isEnabled())
-        SDLInteraction::instance().playSoundFile(dataMgr.findFileForRead("Sounds/roperelease.ogg"));
+        SDLInteraction::instance().playSoundFile("/Sounds/roperelease.ogg");
 }
--- a/QTfrontend/util/DataManager.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/util/DataManager.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -39,12 +39,6 @@
 
 DataManager::DataManager()
 {
-    m_userData = new QDir(cfgdir->absolutePath());
-    if (!m_userData->cd("Data"))
-        m_userData = NULL;
-
-    m_defaultData = new QDir(datadir->absolutePath());
-
     m_hatModel = NULL;
     m_mapModel = NULL;
     m_themeModel = NULL;
@@ -66,20 +60,8 @@
     const QStringList & nameFilters
 ) const
 {
-    QStringList result;
-
-    if (m_userData != NULL)
-    {
-        QDir tmpDir(*m_userData);
-        if (tmpDir.cd(subDirectory))
-            result.append(tmpDir.entryList(nameFilters, filters));
-    }
-
-    QDir tmpDir(*m_defaultData);
-    if (tmpDir.cd(subDirectory))
-        result.append(tmpDir.entryList(nameFilters, filters));
-
-    result.removeDuplicates();
+    QDir tmpDir(QString("physfs://%1").arg(subDirectory));
+    QStringList result = tmpDir.entryList(nameFilters, filters);
 
     // sort case-insensitive
     QMap<QString, QString> sortedFileNames;
@@ -92,40 +74,6 @@
     return result;
 }
 
-
-QString DataManager::findFileForRead(
-    const QString & relativeDataFilePath) const
-{
-    QString path;
-
-    if (m_userData != NULL)
-        path = m_userData->absolutePath()+"/"+relativeDataFilePath;
-
-    if ((!path.isEmpty()) && (!QFile::exists(path)))
-        path = m_defaultData->absolutePath()+"/"+relativeDataFilePath;
-
-    return path;
-}
-
-
-QString DataManager::findFileForWrite(
-    const QString & relativeDataFilePath) const
-{
-    if (m_userData != NULL)
-    {
-        QString path = m_userData->absolutePath()+"/"+relativeDataFilePath;
-
-        // create folders if needed
-        QDir tmp;
-        tmp.mkpath(QFileInfo(path).absolutePath());
-
-        return path;
-    }
-
-
-    return "";
-}
-
 GameStyleModel * DataManager::gameStyleModel()
 {
     if (m_gameStyleModel == NULL) {
--- a/QTfrontend/util/DataManager.h	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/util/DataManager.h	Sun Nov 18 23:10:26 2012 +0400
@@ -70,28 +70,6 @@
                              ) const;
 
         /**
-         * @brief Returns the path for the desires data file.
-         *
-         * Use this method if you want to read an existing data file.
-         *
-         * @param relativeDataFilePath relative path of the data file.
-         * @return real path to the file.
-         */
-        QString findFileForRead(const QString & relativeDataFilePath) const;
-
-
-        /**
-         * @brief Returns the path for the data file that is to be written.
-         *
-         * Use this method if you want to create or write into a data file.
-         *
-         * @param relativeDataFilePath relative path of data file write path.
-         * @return destination of path data file.
-         */
-        QString findFileForWrite(const QString & relativeDataFilePath) const;
-
-
-        /**
          * @brief Returns pointer to a model of available game styles.
          *
          * The model is updated automatically on data reload.
@@ -152,9 +130,6 @@
          */
         DataManager();
 
-        QDir * m_defaultData; ///< directory of the installed data
-        QDir * m_userData;    ///< directory of custom data in the user's directory
-
         GameStyleModel * m_gameStyleModel; ///< game style model instance
         HatModel * m_hatModel; ///< hat model instance
         MapModel * m_mapModel; ///< map model instance
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/FileEngine.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,306 @@
+/* borrowed from https://github.com/skhaz/qt-physfs-wrapper
+ * TODO: add copyright header, determine license
+ */
+
+
+#include "hwpacksmounter.h"
+#include "FileEngine.h"
+
+
+const QString FileEngineHandler::scheme = "physfs:/";
+
+FileEngine::FileEngine(const QString& filename)
+: _handler(NULL)
+, _flags(0)
+{
+    setFileName(filename);
+}
+
+FileEngine::~FileEngine()
+{
+    close();
+}
+
+bool FileEngine::open(QIODevice::OpenMode openMode)
+{
+    close();
+
+    if (openMode & QIODevice::WriteOnly) {
+        _handler = PHYSFS_openWrite(_filename.toUtf8().constData());
+        _flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType;
+    }
+
+    else if (openMode & QIODevice::ReadOnly) {
+        _handler = PHYSFS_openRead(_filename.toUtf8().constData());
+    }
+
+    else if (openMode & QIODevice::Append) {
+        _handler = PHYSFS_openAppend(_filename.toUtf8().constData());
+    }
+
+    else {
+        qWarning("Bad file open mode: %d", (int)openMode);
+    }
+
+    if (!_handler) {
+        qWarning("Failed to open %s, reason: %s", _filename.toUtf8().constData(), PHYSFS_getLastError());
+        return false;
+    }
+
+    return true;
+}
+
+bool FileEngine::close()
+{
+    if (isOpened()) {
+        int result = PHYSFS_close(_handler);
+        _handler = NULL;
+        return result != 0;
+    }
+
+    return true;
+}
+
+bool FileEngine::flush()
+{
+    return PHYSFS_flush(_handler) != 0;
+}
+
+qint64 FileEngine::size() const
+{
+    return _size;
+}
+
+qint64 FileEngine::pos() const
+{
+    return PHYSFS_tell(_handler);
+}
+
+bool FileEngine::seek(qint64 pos)
+{
+    return PHYSFS_seek(_handler, pos) != 0;
+}
+
+bool FileEngine::isSequential() const
+{
+    return false;
+}
+
+bool FileEngine::remove()
+{
+    return PHYSFS_delete(_filename.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const
+{
+    Q_UNUSED(createParentDirectories);
+    return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
+{
+    Q_UNUSED(recurseParentDirectories);
+    return PHYSFS_delete(dirName.toUtf8().constData()) != 0;
+}
+
+bool FileEngine::caseSensitive() const
+{
+    return true;
+}
+
+bool FileEngine::isRelativePath() const
+{
+    return true;
+}
+
+QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+{
+    return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames));
+}
+
+QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
+{
+    Q_UNUSED(filters);
+
+    QString file;
+    QStringList result;
+    char **files = PHYSFS_enumerateFiles(_filename.toUtf8().constData());
+
+    for (char **i = files; *i != NULL; i++) {
+        file = QString::fromUtf8(*i);
+
+        if (filterNames.isEmpty() || QDir::match(filterNames, file)) {
+            result << file;
+        }
+    }
+
+    PHYSFS_freeList(files);
+
+    return result;
+}
+
+QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const
+{
+    return type & _flags;
+}
+
+QString FileEngine::fileName(FileName file) const
+{
+    if (file == QAbstractFileEngine::AbsolutePathName)
+        return PHYSFS_getWriteDir();
+
+    return QString("physfs://%1").arg(_filename);
+}
+
+QDateTime FileEngine::fileTime(FileTime time) const
+{
+
+    switch (time)
+    {
+        case QAbstractFileEngine::ModificationTime:
+        default:
+            return _datetime;
+            break;
+    };
+}
+
+void FileEngine::setFileName(const QString &file)
+{
+    if(file.startsWith(FileEngineHandler::scheme))
+        _filename = file.mid(FileEngineHandler::scheme.size());
+    else
+        _filename = file;
+
+    PHYSFS_Stat stat;
+    if (PHYSFS_stat(_filename.toUtf8().constData(), &stat) != 0) {
+        _size = stat.filesize;
+        _datetime = QDateTime::fromTime_t(stat.modtime);
+//        _flags |= QAbstractFileEngine::WriteUserPerm;
+        _flags |= QAbstractFileEngine::ReadUserPerm;
+        _flags |= QAbstractFileEngine::ExistsFlag;
+
+        switch (stat.filetype)
+        {
+            case PHYSFS_FILETYPE_REGULAR:
+                _flags |= QAbstractFileEngine::FileType;
+                break;
+
+            case PHYSFS_FILETYPE_DIRECTORY:
+                _flags |= QAbstractFileEngine::DirectoryType;
+                break;
+            case PHYSFS_FILETYPE_SYMLINK:
+                _flags |= QAbstractFileEngine::LinkType;
+                break;
+            default: ;
+        }
+    }
+}
+
+bool FileEngine::atEnd() const
+{
+    return PHYSFS_eof(_handler) != 0;
+}
+
+qint64 FileEngine::read(char *data, qint64 maxlen)
+{
+    return PHYSFS_readBytes(_handler, data, maxlen);
+}
+
+qint64 FileEngine::write(const char *data, qint64 len)
+{
+    return PHYSFS_writeBytes(_handler, data, len);
+}
+
+bool FileEngine::isOpened() const
+{
+    return _handler != NULL;
+}
+
+QFile::FileError FileEngine::error() const
+{
+    return QFile::UnspecifiedError;
+}
+
+QString FileEngine::errorString() const
+{
+    return PHYSFS_getLastError();
+}
+
+bool FileEngine::supportsExtension(Extension extension) const
+{
+    return extension == QAbstractFileEngine::AtEndExtension;
+}
+
+
+
+FileEngineHandler::FileEngineHandler(char *argv0)
+{
+    PHYSFS_init(argv0);
+}
+
+FileEngineHandler::~FileEngineHandler()
+{
+    PHYSFS_deinit();
+}
+
+QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const
+{
+    if (filename.startsWith(scheme))
+        return new FileEngine(filename.mid(scheme.size()));
+    else
+        return NULL;
+}
+
+void FileEngineHandler::mount(const QString &path)
+{
+    PHYSFS_mount(path.toUtf8().constData(), NULL, 1);
+}
+
+void FileEngineHandler::mount(const QString & path, const QString & mountPoint)
+{
+    PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1);
+}
+
+void FileEngineHandler::setWriteDir(const QString &path)
+{
+    PHYSFS_setWriteDir(path.toUtf8().constData());
+}
+
+void FileEngineHandler::mountPacks()
+{
+    hedgewarsMountPackages();
+}
+
+
+FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries)
+    : QAbstractFileEngineIterator(filters, nameFilters)
+{
+    m_entries = entries;
+
+    /* heck.. docs are unclear on this
+     * QDirIterator puts iterator before first entry
+     * but QAbstractFileEngineIterator example puts iterator on first entry
+     * though QDirIterator approach seems to be the right one
+     */
+
+    m_index = -1;
+}
+
+bool FileEngineIterator::hasNext() const
+{
+    return m_index < m_entries.size() - 1;
+}
+
+QString FileEngineIterator::next()
+{
+   if (!hasNext())
+       return QString();
+
+   ++m_index;
+   return currentFilePath();
+}
+
+QString FileEngineIterator::currentFileName() const
+{
+    return m_entries.at(m_index);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/util/FileEngine.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,88 @@
+#ifndef _FileEngine_h
+#define _FileEngine_h
+
+#include <QAbstractFileEngine>
+#include <QAbstractFileEngineHandler>
+#include <QAbstractFileEngineIterator>
+#include <QDateTime>
+
+#include "physfs.h"
+
+
+
+class FileEngine : public QAbstractFileEngine
+{
+    public:
+        FileEngine(const QString& filename);
+
+        virtual ~FileEngine();
+
+        virtual bool open(QIODevice::OpenMode openMode);
+        virtual bool close();
+        virtual bool flush();
+        virtual qint64 size() const;
+        virtual qint64 pos() const;
+        virtual bool seek(qint64 pos);
+        virtual bool isSequential() const;
+        virtual bool remove();
+        virtual bool mkdir(const QString &dirName, bool createParentDirectories) const;
+        virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const;
+        virtual bool caseSensitive() const;
+        virtual bool isRelativePath() const;
+        QAbstractFileEngineIterator *beginEntryList(QDir::Filters filters, const QStringList & filterNames);
+        virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const;
+        virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const;
+        virtual QString fileName(FileName file=DefaultName) const;
+        virtual QDateTime fileTime(FileTime time) const;
+        virtual void setFileName(const QString &file);
+        bool atEnd() const;
+
+        virtual qint64 read(char *data, qint64 maxlen);
+        virtual qint64 write(const char *data, qint64 len);
+
+        bool isOpened() const;
+
+        QFile::FileError error() const;
+        QString errorString() const;
+
+        virtual bool supportsExtension(Extension extension) const;
+
+    private:
+        PHYSFS_file *_handler;
+        qint64 _size;
+        FileFlags _flags;
+        QString _filename;
+        QDateTime _datetime;
+};
+
+class FileEngineHandler : public QAbstractFileEngineHandler
+{
+    public:
+        FileEngineHandler(char * argv0);
+        ~FileEngineHandler();
+
+        QAbstractFileEngine *create(const QString &filename) const;
+
+        static void mount(const QString & path);
+        static void mount(const QString & path, const QString & mountPoint);
+        static void setWriteDir(const QString & path);
+        static void mountPacks();
+
+//    private:
+        static const QString scheme;
+};
+
+class FileEngineIterator : public QAbstractFileEngineIterator
+{
+public:
+        FileEngineIterator(QDir::Filters filters, const QStringList & nameFilters, const QStringList & entries);
+
+        bool hasNext() const;
+        QString next();
+        QString currentFileName() const;
+private:
+        QStringList m_entries;
+        int m_index;
+};
+
+#endif
--- a/QTfrontend/util/namegen.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/QTfrontend/util/namegen.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -125,8 +125,7 @@
     QStringList list;
 
     // find .txt to load the names from
-    QFile * file = new QFile(DataManager::instance().findFileForRead(QString(
-                                 "Names/%1.txt").arg(filename)));
+    QFile * file = new QFile(QString("physfs://Names/%1.txt").arg(filename));
 
     if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
     {
@@ -154,8 +153,7 @@
     QStringList list;
 
     // find .cfg to load the dicts from
-    QFile * file = new QFile(DataManager::instance().findFileForRead(QString(
-                                 "Names/%1.cfg").arg(hatname)));
+    QFile * file = new QFile(QString("physfs://Names/%1.cfg").arg(hatname));
 
     if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
     {
@@ -183,8 +181,7 @@
     typesAvailable = false;
 
     // find .ini to load the names from
-    QFile * file = new QFile(
-        DataManager::instance().findFileForRead(QString("Names/types.ini")));
+    QFile * file = new QFile(QString("physfs://Names/types.ini"));
 
 
     if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
--- a/gameServer/Actions.hs	Sun Nov 18 23:09:29 2012 +0400
+++ b/gameServer/Actions.hs	Sun Nov 18 23:10:26 2012 +0400
@@ -255,7 +255,7 @@
     proto <- client's clientProto
     ri <- clientRoomA
     rnc <- gets roomsClients
-    newMasterId <- liftM (head . filter (/= ci)) . io $ roomClientsIndicesM rnc ri
+    newMasterId <- liftM (last . filter (/= ci)) . io $ roomClientsIndicesM rnc ri
     newMaster <- io $ client'sM rnc id newMasterId
     oldRoomName <- io $ room'sM rnc name ri
     oldMaster <- client's nick
@@ -276,7 +276,7 @@
 
     newRoom' <- io $ room'sM rnc id ri
     chans <- liftM (map sendChan) $! sameProtoClientsS proto
-    processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo newRoomName newRoom')
+    processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo (nick newMaster) newRoom')
 
 
 processAction (AddRoom roomName roomPassword) = do
@@ -299,7 +299,7 @@
     chans <- liftM (map sendChan) $! sameProtoClientsS proto
 
     mapM_ processAction [
-        AnswerClients chans ("ROOM" : "ADD" : roomInfo n rm)
+      AnswerClients chans ("ROOM" : "ADD" : roomInfo n rm{playersIn = 1})
         ]
 
 
@@ -326,8 +326,9 @@
     rnc <- gets roomsClients
     ri <- io $ clientRoomM rnc clId
     rm <- io $ room'sM rnc id ri
+    n <- io $ client'sM rnc nick (masterID rm)
     chans <- liftM (map sendChan) $! sameProtoClientsS proto
-    processAction $ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo (name rm) rm)
+    processAction $ AnswerClients chans ("ROOM" : "UPD" : name rm : roomInfo n rm)
 
 
 processAction UnreadyRoomClients = do
@@ -394,6 +395,7 @@
             teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r
             , gameInfo = liftM (\g -> g{leftTeams = teamName : leftTeams g}) $ gameInfo r
             })
+        : SendUpdateOnThisRoom
         : AnswerClients chans ["REMOVE_TEAM", teamName]
         : [SendTeamRemovalMessage teamName | inGame]
 
--- a/gameServer/CoreTypes.hs	Sun Nov 18 23:09:29 2012 +0400
+++ b/gameServer/CoreTypes.hs	Sun Nov 18 23:10:26 2012 +0400
@@ -100,7 +100,7 @@
         readyPlayers :: !Int,
         isRestrictedJoins :: Bool,
         isRestrictedTeams :: Bool,
-        roomBansList :: [B.ByteString],
+        roomBansList :: ![B.ByteString],
         mapParams :: Map.Map B.ByteString B.ByteString,
         params :: Map.Map B.ByteString [B.ByteString]
     }
--- a/gameServer/HWProtoInRoomState.hs	Sun Nov 18 23:09:29 2012 +0400
+++ b/gameServer/HWProtoInRoomState.hs	Sun Nov 18 23:10:26 2012 +0400
@@ -8,6 +8,7 @@
 import qualified Data.ByteString.Char8 as B
 import Control.Monad
 import Control.Monad.Reader
+import Control.DeepSeq
 --------------------------------------
 import CoreTypes
 import Actions
@@ -59,6 +60,7 @@
                 return color
                 else
                 liftM (head . (L.\\) (map B.singleton ['0'..]) . map teamcolor . teams) thisRoom
+        let newTeam = clNick `seq` TeamInfo ci clNick tName teamColor grave fort voicepack flag dif (newTeamHHNum rm) (hhsList hhsInfo)
         return $
             if not . null . drop (maxTeams rm - 1) $ teams rm then
                 [Warning "too many teams"]
@@ -71,17 +73,16 @@
             else if isRestrictedTeams rm then
                 [Warning "restricted"]
             else
-                [ModifyRoom (\r -> r{teams = teams r ++ [newTeam ci clNick r teamColor]}),
+                [ModifyRoom (\r -> r{teams = teams r ++ [newTeam]}),
                 SendUpdateOnThisRoom,
                 ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = Just teamColor}),
                 AnswerClients clChan ["TEAM_ACCEPTED", tName],
-                AnswerClients othChans $ teamToNet $ newTeam ci clNick rm teamColor,
+                AnswerClients othChans $ teamToNet $ newTeam,
                 AnswerClients roomChans ["TEAM_COLOR", tName, teamColor]
                 ]
         where
         canAddNumber r = 48 - (sum . map hhnum $ teams r)
         findTeam = find (\t -> tName == teamname t) . teams
-        newTeam ci clNick r tColor = TeamInfo ci clNick tName tColor grave fort voicepack flag dif (newTeamHHNum r) (hhsList hhsInfo)
         dif = readInt_ difStr
         hhsList [] = []
         hhsList [_] = error "Hedgehogs list with odd elements number"
@@ -107,7 +108,6 @@
                 [ProtocolError "Not team owner!"]
             else
                 [RemoveTeam tName,
-                SendUpdateOnThisRoom,
                 ModifyClient
                     (\c -> c{
                         teamsInGame = teamsInGame c - 1,
@@ -301,11 +301,18 @@
         engineMsg cl = toEngineMsg $ B.concat ["b", nick cl, "(team): ", msg, "\x20\x20"]
 
 handleCmd_inRoom ["BAN", banNick] = do
-    (_, rnc) <- ask
+    (thisClientId, rnc) <- ask
     maybeClientId <- clientByNick banNick
+    master <- liftM isMaster thisClient
     let banId = fromJust maybeClientId
-    master <- liftM isMaster thisClient
-    return [ModifyRoom (\r -> r{roomBansList = (host $ rnc `client` banId) : roomBansList r}) | master && isJust maybeClientId]
+    let sameRoom = clientRoom rnc thisClientId == clientRoom rnc banId
+    if master && isJust maybeClientId && (banId /= thisClientId) && sameRoom then
+        return [
+                ModifyRoom (\r -> r{roomBansList = let h = host $ rnc `client` banId in h `deepseq` h : roomBansList r})
+              , KickRoomClient banId
+            ]
+        else
+        return []
 
 
 handleCmd_inRoom ["LIST"] = return [] -- for old clients (<= 0.9.17)
--- a/hedgewars/CMakeLists.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/CMakeLists.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -54,6 +54,7 @@
     uLocale.pas
     uMisc.pas
     uMobile.pas
+    uPhysFSLayer.pas
     uRandom.pas
     uRender.pas
     uRenderUtils.pas
@@ -99,6 +100,9 @@
     endif (APPLE)
 endif(BUILD_ENGINE_LIBRARY)
 
+# doesn't work for some reason (doesn't find symbols)
+#set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a" ${pascal_flags})
+
 IF(FPC)
     set(fpc_executable ${FPC})
 ELSE()
@@ -269,6 +273,10 @@
     add_dependencies(${engine_output_name} lua)
 endif()
 
+# compile physfs before engine
+add_dependencies(${engine_output_name} physfs)
+add_dependencies(${engine_output_name} physfsrwops)
+
 #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})
--- a/hedgewars/GSHandlers.inc	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/GSHandlers.inc	Sun Nov 18 23:10:26 2012 +0400
@@ -722,7 +722,7 @@
         end;
     Gear^.Pos:= 0;
     Gear^.X:= int2hwFloat(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft);
-    Gear^.Y:= int2hwFloat(LongInt(LAND_HEIGHT + GetRandom(50)) - 1325);
+    Gear^.Y:= int2hwFloat(LAND_HEIGHT + LongInt(GetRandom(50)) - 1325);
     Gear^.State:= Gear^.State or gstInvisible;
     end
 end;
@@ -1691,7 +1691,7 @@
         end
     else
         begin 
-        if (Gear^.Pos <> posCaseHealth) and (GameTicks and $3FF = 0) then // stir it up every second or so
+        if (Gear^.Pos <> posCaseHealth) and (GameTicks and $1FFF = 0) then // stir 'em up periodically
             begin
             gi := GearsList;
             while gi <> nil do
@@ -3853,7 +3853,7 @@
             begin
             inc(iterator^.PortalCounter);
             iterator^.Active:= true;
-            iterator^.State:= iterator^.State and (not gstHHHJump)
+            iterator^.State:= iterator^.State and (not gstHHHJump) or gstMoving;
             end;
 
         // is it worth adding an arcsin table?  Just how often would we end up doing something like this?
@@ -4057,7 +4057,7 @@
                     or ((iterator^.Message and gmAllStoppable) = 0)) then
                             begin
                             iterator^.Active:= true;
-                            if iterator^.dY.QWordValue = _0.QWordValue then
+                            if iterator^.dY.QWordValue = 0 then
                                 iterator^.dY.isNegative:= false;
                             iterator^.State:= iterator^.State or gstMoving;
                             DeleteCI(iterator);
@@ -5149,6 +5149,7 @@
         begin
         with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac;
         AddRandomness(CheckSum);
+        if gi^.Kind = gtGenericFaller then gi^.State:= gi^.State and not gstTmpFlag;
         gi := gi^.NextGear
         end;
     AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y));
@@ -5166,8 +5167,17 @@
         DeleteGear(Gear);
         exit
         end;
-    
-doStepFallingGear(Gear);
+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
+        begin
+        Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
+        Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
+        Gear^.dX:= _90-(GetRandomf*_360);
+        Gear^.dY:= _90-(GetRandomf*_360)
+        end;
+    end
 end;
 
 procedure doStepCreeper(Gear: PGear);
--- a/hedgewars/SDLh.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/SDLh.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -1004,7 +1004,7 @@
 function  TTF_RenderUTF8_Blended(font: PTTF_Font; const text: PChar; fg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName;
 function  TTF_RenderUTF8_Shaded(font: PTTF_Font; const text: PChar; fg, bg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName;
 
-function  TTF_OpenFont(const filename: PChar; size: LongInt): PTTF_Font; cdecl; external SDL_TTFLibName;
+function  TTF_OpenFontRW(src: PSDL_RWops; freesrc: LongBool; size: LongInt): PTTF_Font; cdecl; external SDL_TTFLibName;
 procedure TTF_SetFontStyle(font: PTTF_Font; style: LongInt); cdecl; external SDL_TTFLibName;
 
 (*  SDL_mixer  *)
@@ -1024,7 +1024,7 @@
 procedure Mix_FreeMusic(music: PMixMusic); cdecl; external SDL_MixerLibName;
 
 function  Mix_LoadWAV_RW(src: PSDL_RWops; freesrc: LongInt): PMixChunk; cdecl; external SDL_MixerLibName;
-function  Mix_LoadMUS(const filename: PChar): PMixMusic; cdecl; external SDL_MixerLibName;
+function  Mix_LoadMUS_RW(src: PSDL_RWops): PMixMusic; cdecl; external SDL_MixerLibName;
 
 function  Mix_Playing(channel: LongInt): LongInt; cdecl; external SDL_MixerLibName;
 function  Mix_PlayingMusic: LongInt; cdecl; external SDL_MixerLibName;
@@ -1048,9 +1048,9 @@
 procedure IMG_Quit; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName;{$ENDIF}
 
 function  IMG_Load(const _file: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName;
-function  IMG_Load_RW(rwop: PSDL_RWops; freesrc: LongInt): PSDL_Surface; cdecl; external SDL_ImageLibName;
+function  IMG_Load_RW(rwop: PSDL_RWops; freesrc: LongBool): PSDL_Surface; cdecl; external SDL_ImageLibName;
 function  IMG_LoadPNG_RW(rwop: PSDL_RWops): PSDL_Surface; cdecl; external SDL_ImageLibName;
-function  IMG_LoadTyped_RW(rwop: PSDL_RWops; freesrc: LongInt; type_: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName;
+function  IMG_LoadTyped_RW(rwop: PSDL_RWops; freesrc: LongBool; type_: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName;
 
 (*  SDL_net  *)
 function  SDLNet_Init: LongInt; cdecl; external SDL_NetLibName;
--- a/hedgewars/hwLibrary.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/hwLibrary.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -99,14 +99,18 @@
     JNI_HW_versionInfoVersion := envderef^.NewStringUTF(env, PChar(cVersionString));
 end;
 
+procedure JNI_HW_GenLandPreview(env: PJNIEnv; c: JClass; port: JInt); cdecl;
+begin
+	GenLandPreview(port);
+end;
+
 exports
     JNI_HW_versionInfoNet name Java_Prefix+'HWversionInfoNetProto', 
     JNI_HW_versionInfoVersion name Java_Prefix+'HWversionInfoVersion', 
-    GenLandPreview name Java_Prefix + 'GenLandPreview',
+    JNI_HW_GenLandPreview name Java_Prefix + 'HWGenLandPreview',
     HW_getNumberOfweapons name Java_Prefix + 'HWgetNumberOfWeapons',
     HW_getMaxNumberOfHogs name Java_Prefix + 'HWgetMaxNumberOfHogs',
     HW_getMaxNumberOfTeams name Java_Prefix + 'HWgetMaxNumberOfTeams',
-    HW_terminate name Java_Prefix + 'HWterminate',
     Game;
 {$ELSE}
 exports
--- a/hedgewars/hwengine.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/hwengine.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -29,9 +29,10 @@
 program hwengine;
 {$ENDIF}
 
-uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler,
-     uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uAILandMarks, uLandTexture, uCollisions,
-     SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted
+uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler
+     , uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uAILandMarks, uLandTexture, uCollisions
+     , SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted
+     , uPhysFSLayer
      {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF}
      {$IFDEF USE_TOUCH_INTERFACE}, uTouch {$ENDIF}
      {$IFDEF ANDROID}, GLUnit{$ENDIF}
@@ -90,15 +91,15 @@
             end;
         gsConfirm, gsGame:
             begin
-            DrawWorld(Lag);
+            if not cOnlyStats then DrawWorld(Lag);
             DoGameTick(Lag);
-            ProcessVisualGears(Lag);
+            if not cOnlyStats then ProcessVisualGears(Lag);
             end;
         gsChat:
             begin
-            DrawWorld(Lag);
+            if not cOnlyStats then DrawWorld(Lag);
             DoGameTick(Lag);
-            ProcessVisualGears(Lag);
+            if not cOnlyStats then ProcessVisualGears(Lag);
             end;
         gsExit:
             begin
@@ -108,7 +109,7 @@
             exit(false);
             end;
 
-    SwapBuffers;
+    if not cOnlyStats then SwapBuffers;
 
 {$IFDEF USE_VIDEO_RECORDING}
     if flagPrerecording then
@@ -271,7 +272,7 @@
         CurrTime:= SDL_GetTicks();
         if PrevTime + longword(cTimerInterval) <= CurrTime then
         begin
-            isTerminated:= DoTimer(CurrTime - PrevTime);
+            isTerminated := isTerminated or DoTimer(CurrTime - PrevTime);
             PrevTime:= CurrTime
         end
         else SDL_Delay(1);
@@ -343,18 +344,8 @@
     for i:= 0 to ParamCount do
         AddFileLog(inttostr(i) + ': ' + ParamStr(i));
 
-    for p:= Succ(Low(TPathType)) to High(TPathType) do
-        if (p <> ptMapCurrent) and (p <> ptData) then
-            UserPathz[p]:= UserPathPrefix + '/Data/' + Pathz[p];
-
-    UserPathz[ptData]:= UserPathPrefix + '/Data';
-
-    for p:= Succ(Low(TPathType)) to High(TPathType) do
-        if p <> ptMapCurrent then
-            Pathz[p]:= PathPrefix + '/' + Pathz[p];
-
     WriteToConsole('Init SDL... ');
-    SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true);
+    if not cOnlyStats then SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true);
     WriteLnToConsole(msgOK);
 
     SDL_EnableUNICODE(1);
@@ -381,18 +372,15 @@
     InitKbdKeyTable();
     AddProgress();
 
-    LoadLocale(UserPathz[ptLocale] + '/en.txt');  // Do an initial load with english
-    LoadLocale(Pathz[ptLocale] + '/en.txt');  // Do an initial load with english
+    LoadLocale(cPathz[ptLocale] + '/en.txt');  // Do an initial load with english
     if cLocaleFName <> 'en.txt' then
         begin
         // Try two letter locale first before trying specific locale overrides
-        if (Length(cLocale) > 2) and (Copy(cLocale,1,2) <> 'en') then
+        if (Length(cLocale) > 3) and (Copy(cLocale, 1, 2) <> 'en') then
             begin
-            LoadLocale(UserPathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt');
-            LoadLocale(Pathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt')
+            LoadLocale(cPathz[ptLocale] + '/' + Copy(cLocale, 1, 2) + '.txt')
             end;
-        LoadLocale(UserPathz[ptLocale] + '/' + cLocaleFName);
-        LoadLocale(Pathz[ptLocale] + '/' + cLocaleFName)
+        LoadLocale(cPathz[ptLocale] + '/' + cLocaleFName)
         end
     else cLocale := 'en';
 
@@ -459,6 +447,7 @@
 
     if complete then
     begin
+        uPhysFSLayer.initModule;
 {$IFDEF ANDROID}GLUnit.initModule;{$ENDIF}
 {$IFDEF USE_TOUCH_INTERFACE}uTouch.initModule;{$ENDIF}
 {$IFDEF USE_VIDEO_RECORDING}uVideoRec.initModule;{$ENDIF}   //stub
@@ -510,6 +499,7 @@
 {$IFDEF USE_VIDEO_RECORDING}uVideoRec.freeModule;{$ENDIF}
 {$IFDEF USE_TOUCH_INTERFACE}uTouch.freeModule;{$ENDIF}  //stub
 {$IFDEF ANDROID}GLUnit.freeModule;{$ENDIF}
+        uPhysFSLayer.freeModule;
     end;
 
     uIO.freeModule;
--- a/hedgewars/uAI.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uAI.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -291,18 +291,13 @@
                     begin
                     with Stack.States[Pred(Stack.Count)] do
                         begin
-                        if Me^.dX.isNegative then
+                        if (Me^.Message and gmLeft) <> 0 then
                             AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0)
                         else
                             AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0);
                             
                         AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0);
                         AddAction(MadeActions, aia_HJump, 0, 350, 0, 0);
-                        
-                        if Me^.dX.isNegative then
-                            AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
-                        else
-                            AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
                         end;
                     // but first check walking forward
                     Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message)
@@ -317,7 +312,14 @@
                 // at final check where we go after jump walking backward
                 if Push(ticks, Actions, AltMe, Me^.Message xor 3) then
                     with Stack.States[Pred(Stack.Count)] do
+                        begin
+                        if (Me^.Message and gmLeft) <> 0 then
+                            AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0)
+                        else
+                            AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0);
+
                         AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0);
+                        end;
 
                 // push current position so we proceed from it after checking jump+forward walk opportunities
                 if CanGo then Push(ticks, Actions, Me^, Me^.Message);
@@ -353,6 +355,7 @@
                 addMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere);
 
                 TestAmmos(Actions, Me, ticks shr 12 = oldticks shr 12);
+                
                 end;
                 
             if GoInfo.FallPix >= FallPixForBranching then
@@ -429,7 +432,7 @@
             AddAction(BestActions, aia_Skip, 0, 250, 0, 0);
             end;
 
-        end else
+        end else SDL_Delay(100)
 else
     begin
     BackMe:= PGear(Me)^;
--- a/hedgewars/uAIAmmoTests.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uAIAmmoTests.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -40,6 +40,7 @@
 function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestWatermelon(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 function TestDesertEagle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
@@ -91,7 +92,7 @@
             (proc: @TestWatermelon;  flags: 0), // amWatermelon
             (proc: nil;              flags: 0), // amHellishBomb
             (proc: nil;              flags: 0), // amNapalm
-            (proc: nil;              flags: 0), // amDrill
+            (proc: @TestDrillRocket; flags: 0), // amDrill
             (proc: nil;              flags: 0), // amBallgun
             (proc: nil;              flags: 0), // amRCPlane
             (proc: nil;              flags: 0), // amLowGravity
@@ -121,8 +122,6 @@
             (proc: nil;              flags: 0)  // amKnife
             );
 
-const BadTurn = Low(LongInt) div 4;
-
 implementation
 uses uAIMisc, uVariables, uUtils, uGearsHandlers;
 
@@ -149,7 +148,7 @@
 repeat
     rTime:= rTime + 300 + Level * 50 + random(300);
     Vx:= - windSpeed * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
-    Vy:= cGravityf * rTime * 0.5 - (Targ.Y - mY) / rTime;
+    Vy:= cGravityf * rTime * 0.5 - (Targ.Y + 1 - mY) / rTime;
     r:= sqr(Vx) + sqr(Vy);
     if not (r > 1) then
         begin
@@ -173,7 +172,7 @@
             value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
         else value:= RateExplosion(Me, EX, EY, 101);
         if value = 0 then
-            value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+            value:= 1024 - Metric(Targ.X, Targ.Y, EX, EY) div 64;
         if valueResult <= value then
             begin
             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
@@ -189,6 +188,65 @@
 TestBazooka:= valueResult
 end;
 
+
+function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+var Vx, Vy, r, mX, mY: real;
+    rTime: LongInt;
+    EX, EY: LongInt;
+    valueResult: LongInt;
+    x, y, dX, dY: real;
+    t: LongInt;
+    value: LongInt;
+begin
+    mX:= hwFloat2Float(Me^.X);
+    mY:= hwFloat2Float(Me^.Y);
+    ap.Time:= 0;
+    rTime:= 350;
+    ap.ExplR:= 0;
+    valueResult:= BadTurn;
+    repeat
+        rTime:= rTime + 300 + Level * 50 + random(300);
+        Vx:= - windSpeed * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
+        Vy:= cGravityf * rTime * 0.5 - (Targ.Y - 35 - mY) / rTime;
+        r:= sqr(Vx) + sqr(Vy);
+        if not (r > 1) then
+            begin
+            x:= mX;
+            y:= mY;
+            dX:= Vx;
+            dY:= -Vy;
+            t:= rTime;
+            repeat
+                x:= x + dX;
+                y:= y + dY;
+                dX:= dX + windSpeed;
+                dY:= dY + cGravityf;
+                dec(t)
+            until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
+                   ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (y > cWaterLine);
+            
+            EX:= trunc(x);
+            EY:= trunc(y);
+            if Level = 1 then
+                value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
+            else value:= RateExplosion(Me, EX, EY, 101);
+            if value = 0 then
+                value:= 1024 - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+            if valueResult <= value then
+                begin
+                ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
+                ap.Power:= trunc(sqrt(r) * cMaxPower) - random((Level - 1) * 17 + 1);
+                ap.ExplR:= 100;
+                ap.ExplX:= EX;
+                ap.ExplY:= EY;
+                valueResult:= value
+                end;
+            end
+    until rTime > 4250;
+    TestDrillRocket:= valueResult
+end;
+
+
 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
 var Vx, Vy, r: real;
     rTime: LongInt;
@@ -229,8 +287,9 @@
         EY:= trunc(y);
 
         value:= RateShove(trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, afTrackFall);
-        if value = 0 then
-            value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+        // LOL copypasta: this is score for digging with... snowball
+        //if value = 0 then
+        //    value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
 
         if valueResult <= value then
             begin
@@ -337,7 +396,7 @@
     else 
         Score:= BadTurn;
 
-    if valueResult < Score then
+    if (valueResult < Score) and (Score > 0) then
         begin
         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
         ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
@@ -582,7 +641,7 @@
         valueResult:= RateShotgun(Me, vX, vY, rx, ry);
      
         if valueResult = 0 then 
-            valueResult:= - Metric(Targ.X, Targ.Y, rx, ry) div 64
+            valueResult:= 1024 - Metric(Targ.X, Targ.Y, rx, ry) div 64
         else 
             dec(valueResult, Level * 4000);
         // 27/20 is reuse bonus
--- a/hedgewars/uAIMisc.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uAIMisc.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -28,11 +28,12 @@
       afErasesLand = $00000002;
       afSetSkip    = $00000004;
 
+      BadTurn = Low(LongInt) div 4;
 
 type TTarget = record
     Point: TPoint;
     Score: LongInt;
-    skip: boolean;
+    skip, matters: boolean;
     end;
 TTargets = record
     Count: Longword;
@@ -110,13 +111,15 @@
             begin
             for i:= 0 to cMaxHHIndex do
                 if (Hedgehogs[i].Gear <> nil)
-                and (Hedgehogs[i].Gear <> ThinkingHH) 
+                and (Hedgehogs[i].Gear <> ThinkingHH)
                 and (Hedgehogs[i].Gear^.Health > Hedgehogs[i].Gear^.Damage) 
                     then
                     begin
                     with Targets.ar[Targets.Count], Hedgehogs[i] do
                         begin
                         skip:= false;
+                        matters:= (Hedgehogs[i].Gear^.AIHints and aihDoesntMatter) = 0;
+                        
                         Point.X:= hwRound(Gear^.X);
                         Point.Y:= hwRound(Gear^.Y);
                         if Clan <> CurrentTeam^.Clan then
@@ -407,6 +410,7 @@
 function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
 var i, fallDmg, dmg, dmgBase, rate, erasure: LongInt;
     dX, dY, dmgMod: real;
+    hadSkips: boolean;
 begin
 fallDmg:= 0;
 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
@@ -416,14 +420,22 @@
     begin
     Point.x:= hwRound(Me^.X);
     Point.y:= hwRound(Me^.Y);
+    skip:= false;
+    matters:= true;
     Score:= - ThinkingHH^.Health
     end;
 // rate explosion
 dmgBase:= r + cHHRadius div 2;
+
 if (Flags and afErasesLand <> 0) and (GameFlags and gfSolidLand = 0) then erasure:= r
 else erasure:= 0;
+
+hadSkips:= false;
+
 for i:= 0 to Targets.Count do
     with Targets.ar[i] do
+      if not matters then hadSkips:= true
+        else
         begin
         dmg:= 0;
         if abs(Point.x - x) + abs(Point.y - y) < dmgBase then
@@ -456,7 +468,11 @@
                 else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
             end;
         end;
-RateExplosion:= rate;
+
+if hadSkips and (rate = 0) then
+    RateExplosion:= BadTurn
+    else
+    RateExplosion:= rate;
 end;
 
 function RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
@@ -472,7 +488,7 @@
     with Targets.ar[i] do
       if skip then 
         if (Flags and afSetSkip = 0) then skip:= false else {still skip}
-      else  
+      else if matters then
         begin
         dmg:= 0;
         if abs(Point.x - x) + abs(Point.y - y) < r then
@@ -506,6 +522,7 @@
 function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
 var i, dmg, fallDmg, baseDmg, rate, erasure: LongInt;
     dX, dY, dmgMod: real;
+    hadSkips: boolean;
 begin
 dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
 rate:= 0;
@@ -516,14 +533,22 @@
     begin
     Point.x:= hwRound(Me^.X);
     Point.y:= hwRound(Me^.Y);
+    skip:= false;
+    matters:= true;
     Score:= - ThinkingHH^.Health
     end;
 // rate shot
 baseDmg:= cHHRadius + cShotgunRadius + 4;
+
 if GameFlags and gfSolidLand = 0 then erasure:= cShotgunRadius
 else erasure:= 0;
+
+hadSkips:= false;
+
 for i:= 0 to Targets.Count do
     with Targets.ar[i] do
+      if not matters then hadSkips:= true
+        else
         begin
         dmg:= 0;
         if abs(Point.x - x) + abs(Point.y - y) < baseDmg then
@@ -557,8 +582,12 @@
             else
                 dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
             end;
-        end;        
-RateShotgun:= rate * 1024;
+        end;
+
+if hadSkips and (rate = 0) then
+    RateShotgun:= BadTurn
+    else
+    RateShotgun:= rate * 1024;
 end;
 
 function RateHammer(Me: PGear): LongInt;
@@ -571,6 +600,7 @@
 
 for i:= 0 to Pred(Targets.Count) do
     with Targets.ar[i] do
+      if matters then
          // hammer hit radius is 8, shift is 10
         if abs(Point.x - x) + abs(Point.y - y) < 18 then
             begin
--- a/hedgewars/uCaptions.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uCaptions.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -44,6 +44,7 @@
 
 procedure AddCaption(s: shortstring; Color: Longword; Group: TCapGroup);
 begin
+    if cOnlyStats then exit;
     if Captions[Group].Text <> s then
         begin
         FreeTexture(Captions[Group].Tex);
--- a/hedgewars/uCommandHandlers.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uCommandHandlers.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -548,15 +548,9 @@
 if isDeveloperMode then
     begin
     if s = '' then
-        begin
-        UserPathz[ptMapCurrent]:= s;
-        Pathz[ptMapCurrent]:= s;
-        end
+        cPathz[ptMapCurrent]:= s
     else
-        begin
-        UserPathz[ptMapCurrent]:= UserPathz[ptMaps] + '/' + s;
-        Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s;
-        end;
+        cPathz[ptMapCurrent]:= cPathz[ptMaps] + '/' + s;
     InitStepsFlags:= InitStepsFlags or cifMap
     end;
 cMapName:= s;
@@ -567,8 +561,7 @@
 begin
 if isDeveloperMode then
     begin
-    UserPathz[ptCurrTheme]:= UserPathz[ptThemes] + '/' + s;
-    Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s;
+    cPathz[ptCurrTheme]:= cPathz[ptThemes] + '/' + s;
     Theme:= s;
     InitStepsFlags:= InitStepsFlags or cifTheme
     end
--- a/hedgewars/uConsts.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uConsts.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -161,21 +161,10 @@
     // do not change this value
     cDefaultZoomLevel = 2.0;
 
-{$IFDEF MOBILE}
-    cMaxZoomLevel = 0.5;
-    cMinZoomLevel = 3.5;
-    cZoomDelta = 0.20;
-{$ELSE}
-    cMaxZoomLevel = 1.0;
-    cMinZoomLevel = 3.0;
-    cZoomDelta = 0.25;
-{$ENDIF}
-
-    cMinMaxZoomLevelDelta = cMaxZoomLevel - cMinZoomLevel;
-
     cSendEmptyPacketTime = 1000;
     trigTurns = $80000001;
 
+    // game flags
     gfAny                = $FFFFFFFF;
     gfOneClanMode        = $00000001;           // used in trainings
     gfMultiWeapon        = $00000002;           // used in trainings
@@ -208,6 +197,7 @@
     // if a "game start notice" would be useful. If so,
     // add one in uWorld.pas - look for "AddGoal".
 
+    // gear states
     gstDrowning       = $00000001;
     gstHHDriven       = $00000002;
     gstMoving         = $00000004;
@@ -229,6 +219,7 @@
     gstHHGone         = $00100000;
     gstInvisible      = $00200000;
 
+    // gear messages
     gmLeft           = $00000001;
     gmRight          = $00000002;
     gmUp             = $00000004;
@@ -251,7 +242,12 @@
 
     cMaxSlotIndex       = 9;
     cMaxSlotAmmoIndex   = 5;
-
+    
+    // ai hints
+    aihUsualProcessing    = $00000000;
+    aihDoesntMatter       = $00000001;
+    
+    // ammo properties
     ammoprop_Timerable    = $00000001;
     ammoprop_Power        = $00000002;
     ammoprop_NeedTarget   = $00000004;
@@ -274,6 +270,7 @@
 
     AMMO_INFINITE = 100;
 
+    // explosion flags
     //EXPLAllDamageInRadius = $00000001;  Completely unused for ages
     EXPLAutoSound         = $00000002;
     EXPLNoDamage          = $00000004;
--- a/hedgewars/uGame.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uGame.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -50,17 +50,16 @@
 
     if (GameType = gmtDemo) then 
         if isSpeed then
-        begin
+            begin
             i:= RealTicks-SpeedStart;
             if i < 2000 then Lag:= Lag*5
             else if i < 4000 then Lag:= Lag*10
             else if i < 6000 then Lag:= Lag*20
             else if i < 8000 then Lag:= Lag*40
             else Lag:= Lag*80;
-        end
-        else
-            if cOnlyStats then
-                Lag:= High(LongInt);
+            end
+        else if cOnlyStats then
+            Lag:= High(LongInt)
     end;
 PlayNextVoice;
 i:= 1;
--- a/hedgewars/uGears.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uGears.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -472,6 +472,7 @@
 AddRandomness(CheckSum);
 ScriptCall('onGameTick');
 if GameTicks mod 20 = 0 then ScriptCall('onGameTick20');
+
 inc(GameTicks)
 end;
 
@@ -642,7 +643,7 @@
 
 if (GameFlags and gfArtillery) <> 0 then
     cArtillery:= true;
-for i:= GetRandom(10)+30 downto 0 do
+for i:= (LAND_WIDTH*LAND_HEIGHT) div 524288+2 downto 0 do
     begin
     rx:= GetRandom(rightX-leftX)+leftX;
     ry:= GetRandom(LAND_HEIGHT-topY)+topY;
@@ -656,7 +657,7 @@
 
 if (not hasBorder) and ((Theme = 'Snow') or (Theme = 'Christmas')) then
     for i:= vobCount * Longword(max(LAND_WIDTH,4096)) div 2048 downto 1 do
-        AddGear(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft, LongInt(LAND_HEIGHT + GetRandom(750)) - 1300, gtFlake, 0, _0, _0, 0);
+        AddGear(LongInt(GetRandom(snowRight - snowLeft)) + snowLeft, LAND_HEIGHT + LongInt(GetRandom(750)) - 1300, gtFlake, 0, _0, _0, 0);
 end;
 
 
--- a/hedgewars/uGearsHedgehog.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uGearsHedgehog.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -103,6 +103,13 @@
             LoadHedgehogHat(HHGear^.Hedgehog^, 'Reserved/chef')
         else if prevAmmo = amKnife then
             LoadHedgehogHat(HHGear^.Hedgehog^, Hat);
+        end;
+    // Try again in the next slot
+    if CurAmmoType = prevAmmo then 
+        begin
+        if slot >= cMaxSlotIndex then slot:= 0 else inc(slot);
+        HHGear^.MsgParam:= slot;
+        ChangeAmmo(HHGear)
         end
     end
 end;
@@ -641,9 +648,10 @@
                         gi := GearsList;
                         while gi <> nil do
                             begin
-                            if gi^.Kind = gtGenericFaller then
+                            if (gi^.Kind = gtGenericFaller) and (gi^.State and gstInvisible <> 0) then
                                 begin
                                 gi^.Active:= true;
+                                gi^.State:= gi^.State or gstTmpFlag;
                                 gi^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX);
                                 gi^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY);
                                 gi^.dX:= _90-(GetRandomf*_360);
@@ -971,7 +979,7 @@
 if (not isZero(Gear^.dY)) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then
     begin
     inc(Gear^.FlightTime);
-    if (Gear^.FlightTime > 1500) and ((hwRound(Gear^.X) < leftX-250) or (hwRound(Gear^.X) > rightX+250))  then
+    if (Gear^.FlightTime > 1500) and ((hwRound(Gear^.X) < LongInt(leftX)-250) or (hwRound(Gear^.X) > LongInt(rightX)+250))  then
         begin
         Gear^.FlightTime:= 0;
         AddCaption(GetEventString(eidHomerun), cWhiteColor, capgrpMessage);
@@ -1060,8 +1068,7 @@
             end;
 
 if (CurAmmoGear = nil)
-or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0) 
-or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) then
+or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)  then
     begin
     if ((HHGear^.Message and gmSlot) <> 0) then
         if ChangeAmmo(HHGear) then ApplyAmmoChanges(Hedgehog^);
--- a/hedgewars/uGearsRender.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uGearsRender.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -750,6 +750,7 @@
         begin
         if defaultPos then
             begin
+            if HH^.Team^.hasGone then Tint($FF, $FF, $FF, $80);
             DrawSpriteRotatedF(sprHHIdle,
                 sx,
                 sy,
@@ -791,7 +792,8 @@
                         32,
                         32);
                     Tint($FF, $FF, $FF, $FF)
-                    end
+                    end;
+                if HH^.Team^.hasGone then Tint($FF, $FF, $FF, $FF)
                 end
             else
                 begin
--- a/hedgewars/uGearsUtils.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uGearsUtils.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -286,7 +286,7 @@
 procedure CheckHHDamage(Gear: PGear);
 var 
     dmg: Longword;
-    i: LongInt;
+    i: LongWord;
     particle: PVisualGear;
 begin
     if _0_4 < Gear^.dY then
@@ -555,8 +555,8 @@
 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
 var x: LongInt;
     y, sy: LongInt;
-    ar: array[0..511] of TPoint;
-    ar2: array[0..1023] of TPoint;
+    ar: array[0..1023] of TPoint;
+    ar2: array[0..2047] of TPoint;
     cnt, cnt2: Longword;
     delta: LongInt;
     ignoreNearObjects, ignoreOverlap, tryAgain: boolean;
@@ -566,10 +566,10 @@
 tryAgain:= true;
 while tryAgain do
     begin
-    delta:= 250;
+    delta:= LAND_WIDTH div 16;
     cnt2:= 0;
     repeat
-        x:= Left + LongInt(GetRandom(Delta));
+        x:= Left + max(LAND_WIDTH div 2048, LongInt(GetRandom(Delta)));
         repeat
             inc(x, Delta);
             cnt:= 0;
--- a/hedgewars/uIO.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uIO.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -27,7 +27,7 @@
 
 procedure InitIPC;
 procedure SendIPC(s: shortstring);
-procedure SendIPCXY(cmd: char; X, Y: SmallInt);
+procedure SendIPCXY(cmd: char; X, Y: LongInt);
 procedure SendIPCRaw(p: pointer; len: Longword);
 procedure SendIPCAndWaitReply(s: shortstring);
 procedure SendKeepAliveMessage(Lag: Longword);
@@ -48,7 +48,7 @@
             case byte of
             1: (len: byte;
                 cmd: Char;
-                X, Y: SmallInt);
+                X, Y: LongInt);
             2: (str: shortstring);
             end;
 
@@ -234,13 +234,13 @@
     end
 end;
 
-procedure SendIPCXY(cmd: char; X, Y: SmallInt);
+procedure SendIPCXY(cmd: char; X, Y: LongInt);
 var s: shortstring;
 begin
-s[0]:= #5;
+s[0]:= #9;
 s[1]:= cmd;
-SDLNet_Write16(X, @s[2]);
-SDLNet_Write16(Y, @s[4]);
+SDLNet_Write32(X, @s[2]);
+SDLNet_Write32(Y, @s[6]);
 SendIPC(s)
 end;
 
@@ -270,7 +270,7 @@
 procedure NetGetNextCmd;
 var tmpflag: boolean;
     s: shortstring;
-    x16, y16: SmallInt;
+    x32, y32: LongInt;
 begin
 tmpflag:= true;
 
@@ -327,9 +327,9 @@
             AddFileLog('got cmd "N": time '+IntToStr(hiTicks shl 16 + headcmd^.loTime))
              end;
         'p': begin
-            x16:= SDLNet_Read16(@(headcmd^.X));
-            y16:= SDLNet_Read16(@(headcmd^.Y));
-            doPut(x16, y16, false)
+            x32:= SDLNet_Read32(@(headcmd^.X));
+            y32:= SDLNet_Read32(@(headcmd^.Y));
+            doPut(x32, y32, false)
              end;
         'P': begin
             // these are equations solved for CursorPoint
@@ -337,8 +337,8 @@
             // SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy;
             if not (CurrentTeam^.ExtDriven and bShowAmmoMenu) then
                begin
-               CursorPoint.X:= SmallInt(SDLNet_Read16(@(headcmd^.X))) + WorldDx;
-               CursorPoint.Y:= cScreenHeight - SmallInt(SDLNet_Read16(@(headcmd^.Y))) - WorldDy
+               CursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.X))) + WorldDx;
+               CursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.Y))) - WorldDy
                end
              end;
         'w': ParseCommand('setweap ' + headcmd^.str[2], true);
--- a/hedgewars/uInputHandler.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uInputHandler.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -280,8 +280,8 @@
 DefaultBinds[KeyNameToCode(_S'y')]:= 'confirm';
 
 DefaultBinds[KeyNameToCode('mousem')]:= 'zoomreset';
-DefaultBinds[KeyNameToCode('wheelup')]:= 'zoomin';
-DefaultBinds[KeyNameToCode('wheeldown')]:= 'zoomout';
+DefaultBinds[KeyNameToCode('wheelup')]:= 'zoomout';
+DefaultBinds[KeyNameToCode('wheeldown')]:= 'zoomin';
 
 DefaultBinds[KeyNameToCode('f12')]:= 'fullscr';
 
--- a/hedgewars/uLand.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uLand.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -31,12 +31,12 @@
 implementation
 uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, SysUtils,
      uVariables, uUtils, uCommands, adler32, uDebug, uLandPainted, uTextures,
-     uLandGenMaze, uLandOutline;
+     uLandGenMaze, uLandOutline, uPhysFSLayer;
 
 var digest: shortstring;
 
 procedure ResizeLand(width, height: LongWord);
-var potW, potH: LongWord;
+var potW, potH: LongInt;
 begin 
 potW:= toPowerOf2(width);
 potH:= toPowerOf2(height);
@@ -54,6 +54,9 @@
 
     SetLength(Land, LAND_HEIGHT, LAND_WIDTH);
     SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32));
+    // 0.5 is already approaching on unplayable
+    if (width div 4096 >= 2) or (height div 2048 >= 2) then cMaxZoomLevel:= 0.5;
+    cMinMaxZoomLevelDelta:= cMaxZoomLevel - cMinZoomLevel
     end;
 end;
 
@@ -124,7 +127,7 @@
     SDL_FreeSurface(tmpsurf);
 end;
 
-procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr);
+procedure SetPoints(var Template: TEdgeTemplate; var pa: TPixAr; fps: PPointArray);
 var i: LongInt;
 begin
 with Template do
@@ -145,7 +148,7 @@
                if pa.ar[i].x <> NTPX then
                    pa.ar[i].x:= LAND_WIDTH - 1 - pa.ar[i].x;
             for i:= 0 to pred(FillPointsCount) do
-                FillPoints^[i].x:= LAND_WIDTH - 1 - FillPoints^[i].x;
+                fps^[i].x:= LAND_WIDTH - 1 - fps^[i].x;
             end;
 
 (*  Experiment in making this option more useful
@@ -178,9 +181,9 @@
             end;
         for i:= 0 to pred(FillPointsCount) do
             begin
-            dec(FillPoints^[i].y, 100);
-            if FillPoints^[i].y < 0 then
-                FillPoints^[i].y:= 0;
+            dec(fps^[i].y, 100);
+            if fps^[i].y < 0 then
+                fps^[i].y:= 0;
             end;
         end;
 
@@ -189,7 +192,7 @@
         for i:= 0 to pred(BasePointsCount) do
             pa.ar[i].y:= LAND_HEIGHT - 1 - pa.ar[i].y;
         for i:= 0 to pred(FillPointsCount) do
-            FillPoints^[i].y:= LAND_HEIGHT - 1 - FillPoints^[i].y;
+            fps^[i].y:= LAND_HEIGHT - 1 - fps^[i].y;
         end;
     end
 end;
@@ -199,13 +202,15 @@
 var pa: TPixAr;
     i: Longword;
     y, x: Longword;
+    fps: TPointArray;
 begin
+    fps:=Template.FillPoints^;
     ResizeLand(Template.TemplateWidth, Template.TemplateHeight);
     for y:= 0 to LAND_HEIGHT - 1 do
         for x:= 0 to LAND_WIDTH - 1 do
             Land[y, x]:= lfBasic;
     {$HINTS OFF}
-    SetPoints(Template, pa);
+    SetPoints(Template, pa, @fps);
     {$HINTS ON}
     for i:= 1 to Template.BezierizeCount do
         begin
@@ -222,7 +227,7 @@
 
     with Template do
         for i:= 0 to pred(FillPointsCount) do
-            with FillPoints^[i] do
+            with fps[i] do
                 FillLand(x, y);
 
     DrawEdge(pa, lfBasic);
@@ -322,14 +327,6 @@
 var tmpsurf: PSDL_Surface;
     x,y: Longword;
 begin
-    WriteLnToConsole('Generating land...');
-    case cMapGen of
-        0: GenBlank(EdgeTemplates[SelectTemplate]);
-        1: begin ResizeLand(4096,2048); GenMaze; end;
-        2: GenDrawnMap;
-    else
-        OutError('Unknown mapgen', true);
-    end;
     AddProgress();
 
     tmpsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, LAND_WIDTH, LAND_HEIGHT, 32, RMask, GMask, BMask, 0);
@@ -425,22 +422,58 @@
 SDL_FreeSurface(tmpsurf);
 end;
 
+procedure LoadMapConfig;
+var f: PFSFile;
+    s: shortstring;
+begin
+s:= cPathz[ptMapCurrent] + '/map.cfg';
+
+WriteLnToConsole('Fetching map HH limit');
+
+f:= pfsOpenRead(s);
+if f <> nil then
+    begin
+    pfsReadLn(f, s);
+    if not pfsEof(f) then
+        begin
+        pfsReadLn(f, s);
+        val(s, MaxHedgehogs)
+        end;
+
+    pfsClose(f)
+    end;
+
+if (MaxHedgehogs = 0) then
+    MaxHedgehogs:= 18;
+end;
+
 // Loads Land[] from an image, allowing overriding standard collision
-procedure LoadMask(mapName: shortstring);
+procedure LoadMask;
 var tmpsurf: PSDL_Surface;
     p: PLongwordArray;
     x, y, cpX, cpY: Longword;
+    mapName: shortstring;
 begin
 tmpsurf:= LoadDataImage(ptMapCurrent, 'mask', ifAlpha or ifTransparent or ifIgnoreCaps);
 if tmpsurf = nil then
     begin
-    mapName:= ExtractFileName(Pathz[ptMapCurrent]);
+    mapName:= ExtractFileName(cPathz[ptMapCurrent]);
     tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps);
     end;
 
 
-if (tmpsurf <> nil) and (tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT) and (tmpsurf^.format^.BytesPerPixel = 4) then
+if (tmpsurf <> nil) and (tmpsurf^.format^.BytesPerPixel = 4) then
     begin
+    if LAND_WIDTH = 0 then
+        begin
+        LoadMapConfig;
+        ResizeLand(tmpsurf^.w, tmpsurf^.h);
+        playHeight:= tmpsurf^.h;
+        playWidth:= tmpsurf^.w;
+        leftX:= (LAND_WIDTH - playWidth) div 2;
+        rightX:= (playWidth + ((LAND_WIDTH - playWidth) div 2)) - 1;
+        topY:= LAND_HEIGHT - playHeight;
+        end;
     disableLandBack:= true;
 
     cpX:= (LAND_WIDTH - tmpsurf^.w) div 2;
@@ -491,7 +524,6 @@
 procedure LoadMap;
 var tmpsurf: PSDL_Surface;
     s: shortstring;
-    f: textfile;
     mapName: shortstring = '';
 begin
 WriteLnToConsole('Loading land from file...');
@@ -499,35 +531,14 @@
 tmpsurf:= LoadDataImage(ptMapCurrent, 'map', ifAlpha or ifTransparent or ifIgnoreCaps);
 if tmpsurf = nil then
     begin
-    mapName:= ExtractFileName(Pathz[ptMapCurrent]);
+    mapName:= ExtractFileName(cPathz[ptMapCurrent]);
     tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
     end;
 // (bare) Sanity check. Considering possible LongInt comparisons as well as just how much system memoery it would take
 TryDo((tmpsurf^.w < $40000000) and (tmpsurf^.h < $40000000) and (tmpsurf^.w * tmpsurf^.h < 6*1024*1024*1024), 'Map dimensions too big!', true);
 
 ResizeLand(tmpsurf^.w, tmpsurf^.h);
-
-// unC0Rr - should this be passed from the GUI? I am not sure which layer does what
-s:= UserPathz[ptMapCurrent] + '/map.cfg';
-if not FileExists(s) then
-    s:= Pathz[ptMapCurrent] + '/map.cfg';
-WriteLnToConsole('Fetching map HH limit');
-{$I-}
-Assign(f, s);
-filemode:= 0; // readonly
-Reset(f);
-if IOResult <> 0 then
-    begin
-    s:= Pathz[ptMissionMaps] + '/' + mapName + '/map.cfg';
-    Assign(f, s);
-    Reset(f);
-    end;
-Readln(f);
-if not eof(f) then
-    Readln(f, MaxHedgehogs);
-{$I+}
-if (MaxHedgehogs = 0) then
-    MaxHedgehogs:= 18;
+LoadMapConfig;
 
 playHeight:= tmpsurf^.h;
 playWidth:= tmpsurf^.w;
@@ -544,7 +555,7 @@
     tmpsurf);
 SDL_FreeSurface(tmpsurf);
 
-LoadMask(mapname);
+LoadMask;
 end;
 
 procedure DrawBottomBorder; // broken out from other borders for doing a floor-only map, or possibly updating bottom during SD
@@ -568,8 +579,11 @@
 
 procedure GenMap;
 var x, y, w, c: Longword;
+    map, mask: shortstring;
+    maskOnly: boolean;
 begin
     hasBorder:= false;
+    maskOnly:= false;
 
     LoadThemeConfig;
 
@@ -578,10 +592,30 @@
     //    FillChar(Land,SizeOf(TCollisionArray),0);*)
 
     if (GameFlags and gfForts) = 0 then
-        if Pathz[ptMapCurrent] <> '' then
-            LoadMap
+        if cPathz[ptMapCurrent] <> '' then
+            begin
+            map:= cPathz[ptMapCurrent] + '/map.png';
+            mask:= cPathz[ptMapCurrent] + '/mask.png';
+            if (not(FileExists(map)) and FileExists(mask)) then
+                begin
+                maskOnly:= true;
+                LoadMask;
+                GenLandSurface
+                end
+            else LoadMap;
+            end
         else
+            begin
+            WriteLnToConsole('Generating land...');
+            case cMapGen of
+                0: GenBlank(EdgeTemplates[SelectTemplate]);
+                1: begin ResizeLand(4096,2048); GenMaze; end;
+                2: GenDrawnMap;
+            else
+                OutError('Unknown mapgen', true);
+            end;
             GenLandSurface
+            end
     else
         MakeFortsMap;
 
@@ -657,7 +691,7 @@
 if (GameFlags and gfDisableGirders) <> 0 then
     hasGirders:= false;
 
-if ((GameFlags and gfForts) = 0) and (Pathz[ptMapCurrent] = '') then
+if (GameFlags and gfForts = 0) and (maskOnly or (cPathz[ptMapCurrent] = '')) then
     AddObjects
     
 else
--- a/hedgewars/uLandObjects.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uLandObjects.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -30,8 +30,9 @@
 procedure AddOnLandObjects(Surface: PSDL_Surface);
 
 implementation
-uses uStore, uConsts, uConsole, uRandom, uSound, GLunit,
-     uTypes, uVariables, uUtils, uDebug, SysUtils;
+uses uStore, uConsts, uConsole, uRandom, uSound, GLunit
+     , uTypes, uVariables, uUtils, uDebug, SysUtils
+     , uPhysFSLayer;
 
 const MaxRects = 512;
       MAXOBJECTRECTS = 16;
@@ -399,7 +400,7 @@
 
 procedure ReadThemeInfo(var ThemeObjects: TThemeObjects; var SprayObjects: TSprayObjects);
 var s, key: shortstring;
-    f: textfile;
+    f: PFSFile;
     i: LongInt;
     ii, t: Longword;
     c2: TSDL_Color;
@@ -429,21 +430,17 @@
         end
     end;
 
-s:= UserPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
-if not FileExists(s) then
-    s:= Pathz[ptCurrTheme] + '/' + cThemeCFGFilename;
+s:= cPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
 WriteLnToConsole('Reading objects info...');
-Assign(f, s);
-{$I-}
-filemode:= 0; // readonly
-Reset(f);
+f:= pfsOpenRead(s);
+TryDo(f <> nil, 'Bad data or cannot access file ' + cThemeCFGFilename, true);
 
 ThemeObjects.Count:= 0;
 SprayObjects.Count:= 0;
 
-while not eof(f) do
+while not pfsEOF(f) do
     begin
-    Readln(f, s);
+    pfsReadLn(f, s);
     if Length(s) = 0 then
         continue;
     if s[1] = ';' then
@@ -738,9 +735,7 @@
         end
     end;
 
-Close(f);
-{$I+}
-TryDo(IOResult = 0, 'Bad data or cannot access file ' + cThemeCFGFilename, true);
+pfsClose(f);
 AddProgress;
 end;
 
--- a/hedgewars/uLandTexture.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uLandTexture.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -66,6 +66,7 @@
 procedure UpdateLandTexture(X, Width, Y, Height: LongInt; landAdded: boolean);
 var tx, ty: Longword;
 begin
+    if cOnlyStats then exit;
     if (Width <= 0) or (Height <= 0) then
         exit;
     TryDo((X >= 0) and (X < LAND_WIDTH), 'UpdateLandTexture: wrong X parameter', true);
@@ -93,6 +94,7 @@
 var x, y, ty, tx, lx, ly : LongWord;
     isEmpty: boolean;
 begin
+    if cOnlyStats then exit;
 (*
 if LandTextures[0, 0].tex = nil then
     for x:= 0 to LANDTEXARW -1 do
--- a/hedgewars/uLocale.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uLocale.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -34,14 +34,14 @@
 {$ENDIF}
 
 implementation
-uses uRandom, uUtils, uVariables, uDebug;
+uses uRandom, uUtils, uVariables, uDebug, uPhysFSLayer;
 
 var trevt: array[TEventId] of array [0..Pred(MAX_EVENT_STRINGS)] of ansistring;
     trevt_n: array[TEventId] of integer;
 
 procedure LoadLocale(FileName: shortstring);
-var s: ansistring;
-    f: textfile;
+var s: shortstring;
+    f: pfsFile;
     a, b, c: LongInt;
     first: array[TEventId] of boolean;
     e: TEventId;
@@ -51,18 +51,14 @@
 for e:= Low(TEventId) to High(TEventId) do
     first[e]:= true;
 
-{$I-} // iochecks off
-Assign(f, FileName);
-filemode:= 0; // readonly
-Reset(f);
-if IOResult = 0 then
-    loaded:= true;
-TryDo(loaded, 'Cannot load locale "' + FileName + '"', false);
-if loaded then
+f:= pfsOpenRead(FileName);
+TryDo(f <> nil, 'Cannot load locale "' + FileName + '"', false);
+
+if f <> nil then
     begin
-    while not eof(f) do
+    while not pfsEof(f) do
         begin
-        readln(f, s);
+        pfsReadLn(f, s);
         if Length(s) = 0 then
             continue;
         if (s[1] < '0') or (s[1] > '9') then
@@ -99,9 +95,8 @@
                 trgoal[TGoalStrId(b)]:= s;
            end;
        end;
-   Close(f);
+   pfsClose(f);
    end;
-{$I+}
 end;
 
 function GetEventString(e: TEventId): ansistring;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uPhysFSLayer.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,117 @@
+unit uPhysFSLayer;
+
+{$LINKLIB ../bin/libphysfs.a}
+{$LINKLIB ../bin/libphysfsrwops.a}
+
+interface
+uses SDLh;
+
+procedure initModule;
+procedure freeModule;
+
+type PFSFile = pointer;
+
+function rwopsOpenRead(fname: shortstring): PSDL_RWops;
+function rwopsOpenWrite(fname: shortstring): PSDL_RWops;
+
+function pfsOpenRead(fname: shortstring): PFSFile;
+function pfsClose(f: PFSFile): boolean;
+
+procedure pfsReadLn(f: PFSFile; var s: shortstring);
+function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64;
+function pfsEOF(f: PFSFile): boolean;
+
+function pfsExists(fname: shortstring): boolean;
+
+implementation
+uses uUtils, uVariables;
+
+function PHYSFS_init(argv0: PChar) : LongInt; cdecl; external;
+function PHYSFS_deinit() : LongInt; cdecl; external;
+function PHYSFSRWOPS_openRead(fname: PChar): PSDL_RWops; cdecl; external;
+function PHYSFSRWOPS_openWrite(fname: PChar): PSDL_RWops; cdecl; external;
+
+function PHYSFS_mount(newDir, mountPoint: PChar; appendToPath: LongBool) : LongInt; cdecl; external;
+function PHYSFS_openRead(fname: PChar): PFSFile; cdecl; external;
+function PHYSFS_eof(f: PFSFile): LongBool; cdecl; external;
+function PHYSFS_readBytes(f: PFSFile; buffer: pointer; len: Int64): Int64; cdecl; external;
+function PHYSFS_close(f: PFSFile): LongBool; cdecl; external;
+function PHYSFS_exists(fname: PChar): LongBool; cdecl; external;
+
+procedure hedgewarsMountPackages(); cdecl; external;
+
+function rwopsOpenRead(fname: shortstring): PSDL_RWops;
+begin
+    exit(PHYSFSRWOPS_openRead(Str2PChar(fname)));
+end;
+
+function rwopsOpenWrite(fname: shortstring): PSDL_RWops;
+begin
+    exit(PHYSFSRWOPS_openWrite(Str2PChar(fname)));
+end;
+
+function pfsOpenRead(fname: shortstring): PFSFile;
+begin
+    exit(PHYSFS_openRead(Str2PChar(fname)));
+end;
+
+function pfsEOF(f: PFSFile): boolean;
+begin
+    exit(PHYSFS_eof(f))
+end;
+
+function pfsClose(f: PFSFile): boolean;
+begin
+    exit(PHYSFS_close(f))
+end;
+
+function pfsExists(fname: shortstring): boolean;
+begin
+    exit(PHYSFS_exists(Str2PChar(fname)))
+end;
+
+
+procedure pfsReadLn(f: PFSFile; var s: shortstring);
+var c: char;
+begin
+s[0]:= #0;
+
+while (PHYSFS_readBytes(f, @c, 1) = 1) and (c <> #10) do
+    if (c <> #13) and (s[0] < #255) then
+        begin
+        inc(s[0]);
+        s[byte(s[0])]:= c
+        end
+end;
+
+function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64;
+var r: Int64;
+begin
+    r:= PHYSFS_readBytes(f, buf, size);
+
+    if r <= 0 then
+        pfsBlockRead:= 0
+    else
+        pfsBlockRead:= r
+end;
+
+procedure initModule;
+var i: LongInt;
+begin
+    i:= PHYSFS_init(Str2PChar(ParamStr(0)));
+    AddFileLog('[PhysFS] init: ' + inttostr(i));
+
+    i:= PHYSFS_mount(Str2PChar(PathPrefix), nil, true);
+    AddFileLog('[PhysFS] mount ' + PathPrefix + ': ' + inttostr(i));
+    i:= PHYSFS_mount(Str2PChar(UserPathPrefix + '/Data'), nil, true);
+    AddFileLog('[PhysFS] mount ' + UserPathPrefix + '/Data: ' + inttostr(i));
+
+    hedgewarsMountPackages;
+end;
+
+procedure freeModule;
+begin
+    PHYSFS_deinit;
+end;
+
+end.
--- a/hedgewars/uScript.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uScript.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -81,7 +81,9 @@
     uLandGraphics,
     SDLh,
     SysUtils, 
-    uIO;
+    uIO,
+    uPhysFSLayer
+    ;
 
 var luaState : Plua_State;
     ScriptAmmoLoadout : shortstring;
@@ -1592,7 +1594,7 @@
         lua_pushnil(L);
         end
     else
-        lua_pushstring(L, str2pchar(Pathz[ptData]));
+        lua_pushstring(L, str2pchar(cPathz[ptData]));
     lc_getdatapath:= 1
 end;
 
@@ -1604,7 +1606,7 @@
         lua_pushnil(L);
         end
     else
-        lua_pushstring(L, str2pchar(UserPathz[ptData]));
+        lua_pushstring(L, str2pchar(cPathz[ptData]));
     lc_getuserdatapath:= 1
 end;
 
@@ -1727,36 +1729,29 @@
     else
         begin
         gear:= GearByUID(lua_tointeger(L, 1));
-        hiddenHedgehogs[hiddenHedgehogsNumber]:=gear^.hedgehog;
-        inc(hiddenHedgehogsNumber);
-        HideHog(gear^.hedgehog);
+        HideHog(gear^.hedgehog)
         end;
     lc_hidehog := 0;
 end;
 
 function lc_restorehog(L: Plua_State): LongInt; Cdecl;
 var hog: PHedgehog;
-    i, j: LongInt;
+    i, h: LongInt;
+    uid: LongWord;
 begin
     if lua_gettop(L) <> 1 then
         LuaError('Lua: Wrong number of parameters passed to RestoreHog!')
     else
         begin
-          i := 0;
-          while (i < hiddenHedgehogsNumber) do
-            begin
-            if hiddenHedgehogs[i]^.gearHidden^.uid = LongWord(lua_tointeger(L, 1)) then
-              begin
-                hog := hiddenHedgehogs[i];
-                RestoreHog(hog);
-                dec(hiddenHedgehogsNumber);
-                for j := i to hiddenHedgehogsNumber - 1 do
-                  hiddenHedgehogs[j] := hiddenHedgehogs[j + 1];
-                lc_restorehog := 0;
-                exit;
-              end;
-            inc(i);
-            end;
+        uid:= LongWord(lua_tointeger(L, 1));
+        if TeamsCount > 0 then
+            for i:= 0 to Pred(TeamsCount) do
+                for h:= 0 to cMaxHHIndex do
+                    if (TeamsArray[i]^.Hedgehogs[h].GearHidden <> nil) and (TeamsArray[i]^.Hedgehogs[h].GearHidden^.uid = uid) then
+                        begin
+                        RestoreHog(@TeamsArray[i]^.Hedgehogs[h]);
+                        exit(0)
+                        end
         end;
     lc_restorehog := 0;
 end;
@@ -1783,6 +1778,34 @@
         end;
     lc_testrectforobstacle:= 1
 end;
+
+
+function lc_setaihintsongear(L : Plua_State) : LongInt; Cdecl;
+var gear: PGear;
+begin
+    if lua_gettop(L) <> 2 then
+        LuaError('Lua: Wrong number of parameters passed to SetAIHintOnGear!')
+    else
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        if gear <> nil then
+            gear^.aihints:= lua_tointeger(L, 2);
+        end;
+    lc_setaihintsongear:= 0
+end;
+
+
+function lc_hedgewarsscriptload(L : Plua_State) : LongInt; Cdecl;
+begin
+    if lua_gettop(L) <> 1 then
+        begin
+        LuaError('Lua: Wrong number of parameters passed to HedgewarsScriptLoad!');
+        lua_pushnil(L)
+        end
+    else
+        ScriptLoad(lua_tostring(L, 1));
+    lc_hedgewarsscriptload:= 0;
+end;
 ///////////////////
 
 procedure ScriptPrintStack;
@@ -1955,18 +1978,30 @@
 ScriptCall('onScreenResize');
 end;
 
+// custom script loader via physfs, passed to lua_load
+const BUFSIZE = 1024;
+var physfsReaderBuffer: pointer; external;
+function physfsReader(L: Plua_State; f: PFSFile; sz: Psize_t) : PChar; cdecl; external;
+
 
 procedure ScriptLoad(name : shortstring);
 var ret : LongInt;
       s : shortstring;
+      f : PFSFile;
+    buf : array[0..Pred(BUFSIZE)] of byte;
 begin
-s:= UserPathz[ptData] + '/' + name;
-if not FileExists(s) then
-    s:= Pathz[ptData] + '/' + name;
-if not FileExists(s) then
+s:= cPathz[ptData] + name;
+if not pfsExists(s) then
     exit;
 
-ret:= luaL_loadfile(luaState, Str2PChar(s));
+f:= pfsOpenRead(s);
+if f = nil then 
+    exit;
+
+physfsReaderBuffer:= @buf;
+ret:= lua_load(luaState, @physfsReader, f, Str2PChar(s));
+pfsClose(f);
+
 if ret <> 0 then
     begin
     LuaError('Lua: Failed to load ' + name + '(error ' + IntToStr(ret) + ')');
@@ -2287,6 +2322,9 @@
 ScriptSetInteger('gstHHGone'         ,$00100000);
 ScriptSetInteger('gstInvisible'      ,$00200000);
 
+ScriptSetInteger('aihUsualProcessing' ,$00000000);
+ScriptSetInteger('aihDoesntMatter'    ,$00000001);
+
 // register functions
 lua_register(luaState, _P'HideHog', @lc_hidehog);
 lua_register(luaState, _P'RestoreHog', @lc_restorehog);
@@ -2380,6 +2418,9 @@
 lua_register(luaState, _P'GetCurAmmoType', @lc_getcurammotype);
 lua_register(luaState, _P'TestRectForObstacle', @lc_testrectforobstacle);
 
+lua_register(luaState, _P'SetGearAIHints', @lc_setaihintsongear);
+lua_register(luaState, _P'HedgewarsScriptLoad', @lc_hedgewarsscriptload);
+
 
 ScriptClearStack; // just to be sure stack is empty
 ScriptLoaded:= false;
--- a/hedgewars/uSound.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uSound.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -106,7 +106,7 @@
 
 
 implementation
-uses uVariables, uConsole, uUtils, uCommands, uDebug;
+uses uVariables, uConsole, uUtils, uCommands, uDebug, uPhysFSLayer;
 
 const chanTPU = 32;
 var Volume: LongInt;
@@ -131,29 +131,17 @@
     if cLocale <> 'en' then
         begin
         locName:= name+'_'+cLocale;
-        path:= UserPathz[ptVoices] + '/' + locName;
+        path:= cPathz[ptVoices] + '/' + locName;
         if DirectoryExists(path) then
             name:= locName
         else
-            begin
-            path:= Pathz[ptVoices] + '/' + locName;
-            if DirectoryExists(path) then
-                name:= locName
-            else if Length(cLocale) > 2
-                then
+            if Length(cLocale) > 3 then
                 begin
                 locName:= name+'_'+Copy(cLocale,1,2);
-                path:= UserPathz[ptVoices] + '/' + locName;
+                path:= cPathz[ptVoices] + '/' + locName;
                 if DirectoryExists(path) then
                     name:= locName
-                else
-                    begin
-                    path:= Pathz[ptVoices] + '/' + locName;
-                    if DirectoryExists(path) then
-                        name:= locName
-                    end
                 end
-            end
         end;
 
     // If that fails, use the unmodified one
@@ -267,11 +255,11 @@
         begin
         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
             begin
-            s:= UserPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
-            if not FileExists(s) then
-                s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
+            s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
+            if (not FileExists(s)) and (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then
+                s:= cPathz[Soundz[sndFirePunch1].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
-            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
+            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1);
             if voicepack^.chunks[snd] = nil then
                 WriteLnToConsole(msgFailed)
             else
@@ -283,11 +271,9 @@
         begin
         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
             begin
-            s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
-            if not FileExists(s) then
-                s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
+            s:= cPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
-            defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
+            defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1);
             SDLTry(defVoicepack^.chunks[snd] <> nil, true);
             WriteLnToConsole(msgOK);
             end;
@@ -367,11 +353,9 @@
         begin
         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
            begin
-            s:= UserPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
-            if not FileExists(s) then
-                s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
+            s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
-            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
+            voicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1);
             if voicepack^.chunks[snd] = nil then
                 WriteLnToConsole(msgFailed)
             else
@@ -383,11 +367,9 @@
         begin
         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
             begin
-            s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
-            if not FileExists(s) then
-                s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
+            s:= cPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
-            defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1);
+            defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1);
             SDLTry(defVoicepack^.chunks[snd] <> nil, true);
             WriteLnToConsole(msgOK);
             end;
@@ -434,12 +416,10 @@
     if (not isSoundEnabled) or (MusicFN = '') or (not isMusicEnabled) then
         exit;
 
-    s:= UserPathPrefix + '/Data/Music/' + MusicFN;
-    if not FileExists(s) then
-        s:= PathPrefix + '/Music/' + MusicFN;
+    s:= '/Music/' + MusicFN;
     WriteToConsole(msgLoading + s + ' ');
 
-    Mus:= Mix_LoadMUS(Str2PChar(s));
+    Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s));
     SDLTry(Mus <> nil, false);
     WriteLnToConsole(msgOK);
 
@@ -454,7 +434,7 @@
 function ChangeVolume(voldelta: LongInt): LongInt;
 begin
     ChangeVolume:= 0;
-    if (not isSoundEnabled) or ((voldelta = 0) and not (cInitVolume = 0)) then
+    if (not isSoundEnabled) or ((voldelta = 0) and (not (cInitVolume = 0))) then
         exit;
 
     inc(Volume, voldelta);
@@ -494,7 +474,7 @@
 
 procedure MuteAudio;
 begin
-    if (not isSoundEnabled) then
+    if not isSoundEnabled then
         exit;
 
     if (isAudioMuted) then
--- a/hedgewars/uStats.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uStats.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -36,7 +36,7 @@
 procedure hedgehogFlight(Gear: PGear; time: Longword);
 
 implementation
-uses uSound, uLocale, uVariables, uUtils, uIO, uCaptions, uDebug, uMisc;
+uses uSound, uLocale, uVariables, uUtils, uIO, uCaptions, uDebug, uMisc, uConsole;
 
 var DamageClan  : Longword = 0;
     DamageTotal : Longword = 0;
@@ -185,10 +185,10 @@
 begin
 if time > 4000 then
     begin
-    writeln(stdout, 'FLIGHT');
-    writeln(stdout, Gear^.Hedgehog^.Team^.TeamName);
-    writeln(stdout, inttostr(time));
-    writeln(stdout, '');
+    WriteLnToConsole('FLIGHT');
+    WriteLnToConsole(Gear^.Hedgehog^.Team^.TeamName);
+    WriteLnToConsole(inttostr(time));
+    WriteLnToConsole( '');
     end
 end;
 
@@ -293,14 +293,14 @@
 // now to console
 if winnersClan <> nil then 
     begin
-    writeln(stdout, 'WINNERS');
+    WriteLnToConsole('WINNERS');
     for t:= 0 to winnersClan^.TeamsNumber - 1 do
-        writeln(stdout, winnersClan^.Teams[t]^.TeamName);
+        WriteLnToConsole(winnersClan^.Teams[t]^.TeamName);
     end
 else
-    writeln(stdout, 'DRAW');
+    WriteLnToConsole('DRAW');
 
-writeln(stdout, '');
+WriteLnToConsole('');
 end;
 
 procedure initModule;
--- a/hedgewars/uStore.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uStore.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -56,9 +56,11 @@
 procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF};
 
 implementation
-uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands,
-     uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}
-     {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF};
+uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands
+    , uPhysFSLayer
+    , uDebug
+    {$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}
+    {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF};
 
 //type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple);
 
@@ -146,6 +148,7 @@
     texsurf, flagsurf, iconsurf: PSDL_Surface;
     foundBot: boolean;
 begin
+    if cOnlyStats then exit;
 r.x:= 0;
 r.y:= 0;
 drY:= - 4;
@@ -308,11 +311,9 @@
     for fi:= Low(THWFont) to High(THWFont) do
         with Fontz[fi] do
             begin
-            s:= UserPathz[ptFonts] + '/' + Name;
-            if not FileExists(s) then
-                s:= Pathz[ptFonts] + '/' + Name;
+            s:= cPathz[ptFonts] + '/' + Name;
             WriteToConsole(msgLoading + s + ' (' + inttostr(Height) + 'pt)... ');
-            Handle:= TTF_OpenFont(Str2PChar(s), Height);
+            Handle:= TTF_OpenFontRW(rwopsOpenRead(s), true, Height);
             SDLTry(Handle <> nil, true);
             TTF_SetFontStyle(Handle, style);
             WriteLnToConsole(msgOK)
@@ -564,7 +565,7 @@
     WriteToConsole(msgLoading + filename + '.png [flags: ' + inttostr(imageFlags) + '] ');
 
     s:= filename + '.png';
-    tmpsurf:= IMG_Load(Str2PChar(s));
+    tmpsurf:= IMG_Load_RW(rwopsOpenRead(s), true);
 
     if tmpsurf = nil then
     begin
@@ -575,7 +576,7 @@
     if ((imageFlags and ifIgnoreCaps) = 0) and ((tmpsurf^.w > MaxTextureSize) or (tmpsurf^.h > MaxTextureSize)) then
     begin
         SDL_FreeSurface(tmpsurf);
-        OutError(msgFailedSize, (imageFlags and ifCritical) <> 0);
+        OutError(msgFailedSize, ((not cOnlyStats) and ((imageFlags and ifCritical) <> 0)));
         // dummy surface to replace non-critical textures that failed to load due to their size
         LoadImage:= SDL_CreateRGBSurface(SDL_SWSURFACE, 2, 2, 32, RMask, GMask, BMask, AMask);
         exit;
@@ -596,13 +597,7 @@
 var tmpsurf: PSDL_Surface;
 begin
     // check for file in user dir (never critical)
-    tmpsurf:= LoadImage(UserPathz[path] + '/' + filename, imageFlags and (not ifCritical));
-
-    // if unsuccessful check data dir
-    if (tmpsurf = nil) then
-        tmpsurf:= LoadImage(Pathz[path] + '/' + filename, imageFlags);
-
-    LoadDataImage:= tmpsurf;
+    tmpsurf:= LoadImage(cPathz[path] + '/' + filename, imageFlags);
 end;
 
 
@@ -873,6 +868,7 @@
 var r: TSDL_Rect;
     texsurf: PSDL_Surface;
 begin
+    if cOnlyStats then exit;
     if Step = 0 then
     begin
         WriteToConsole(msgLoading + 'progress sprite: ');
@@ -1127,10 +1123,14 @@
     {$IFNDEF DARWIN}ico: PSDL_Surface;{$ENDIF}
     {$IFDEF SDL13}x, y: LongInt;{$ENDIF}
 begin
+    if cOnlyStats then
+        begin
+        MaxTextureSize:= 1024;
+        exit
+        end;
     if Length(s) = 0 then
-        cFullScreen:= (not cFullScreen)
-    else
-        cFullScreen:= s = '1';
+         cFullScreen:= (not cFullScreen)
+    else cFullScreen:= s = '1';
 
     AddFileLog('Preparing to change video parameters...');
 {$IFDEF SDL13}
--- a/hedgewars/uTeams.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uTeams.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -292,12 +292,20 @@
     TagTurnTimeLeft:= 0;
     NextClan:= false;
     end;
+
 if (TurnTimeLeft > 0) and (CurrentHedgehog^.BotLevel = 0) then
     begin
     if CurrentTeam^.ExtDriven then
-        AddVoice(sndIllGetYou, CurrentTeam^.voicepack)
+        begin
+        if GetRandom(2) = 0 then
+             AddVoice(sndIllGetYou, CurrentTeam^.voicepack)
+        else AddVoice(sndJustYouWait, CurrentTeam^.voicepack)
+        end
     else
+        begin
+        GetRandom(2); // needed to avoid extdriven desync
         AddVoice(sndYesSir, CurrentTeam^.voicepack);
+        end;
     if cHedgehogTurnTime < 1000000 then
         ReadyTimeLeft:= cReadyDelay;
     AddCaption(Format(shortstring(trmsg[sidReady]), CurrentTeam^.TeamName), cWhiteColor, capgrpGameState)
@@ -305,7 +313,11 @@
 else
     begin
     if TurnTimeLeft > 0 then
-        AddVoice(sndIllGetYou, CurrentTeam^.voicepack);
+        begin
+        if GetRandom(2) = 0 then
+             AddVoice(sndIllGetYou, CurrentTeam^.voicepack)
+        else AddVoice(sndJustYouWait, CurrentTeam^.voicepack)
+        end;
     ReadyTimeLeft:= 0
     end;
 
@@ -438,16 +450,18 @@
 begin
 with team^ do
     begin
-    NewTeamHealthBarWidth:= 0;
+    TeamHealth:= 0;
+    for i:= 0 to cMaxHHIndex do
+        if Hedgehogs[i].Gear <> nil then
+            inc(TeamHealth, Hedgehogs[i].Gear^.Health)
+        else if Hedgehogs[i].GearHidden <> nil then
+            inc(TeamHealth, Hedgehogs[i].GearHidden^.Health);
 
     if not hasGone then
-        for i:= 0 to cMaxHHIndex do
-            if Hedgehogs[i].Gear <> nil then
-                inc(NewTeamHealthBarWidth, Hedgehogs[i].Gear^.Health)
-            else if Hedgehogs[i].GearHidden <> nil then
-                inc(NewTeamHealthBarWidth, Hedgehogs[i].GearHidden^.Health);
+        NewTeamHealthBarWidth:= TeamHealth
+        else
+        NewTeamHealthBarWidth:= 0;
 
-    TeamHealth:= NewTeamHealthBarWidth;
     if NewTeamHealthBarWidth > MaxTeamHealth then
         begin
         MaxTeamHealth:= NewTeamHealthBarWidth;
--- a/hedgewars/uTextures.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uTextures.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -126,6 +126,7 @@
     tmpp: pointer;
     fromP4, toP4: PLongWordArray;
 begin
+if cOnlyStats then exit(nil);
 new(Surface2Tex);
 Surface2Tex^.PrevTexture:= nil;
 Surface2Tex^.NextTexture:= nil;
--- a/hedgewars/uTypes.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uTypes.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -123,7 +123,7 @@
             sndSplash, sndShotgunReload, sndShotgunFire, sndGraveImpact,
             sndMineImpact, sndMineTick, sndMudballImpact,
             sndPickhammer, sndGun, sndBee, sndJump1, sndJump2,
-            sndJump3, sndYesSir, sndLaugh, sndIllGetYou, sndIncoming,
+            sndJump3, sndYesSir, sndLaugh, sndIllGetYou, sndJustYouWait, sndIncoming,
             sndMissed, sndStupid, sndFirstBlood, sndBoring, sndByeBye,
             sndSameTeam, sndNutter, sndReinforce, sndTraitor, sndRegret,
             sndEnemyDown, sndCoward, sndHurry, sndWatchIt, sndKamikaze,
@@ -258,6 +258,7 @@
             nImpactSounds: Word; // count of ImpactSounds
             SoundChannel: LongInt;
             PortalCounter: LongWord;  // Hopefully temporary, but avoids infinite portal loops in a guaranteed fashion.
+            AIHints: LongWord; // hints for ai. haha ^^^^^^ temporary, sure
             LastDamage: PHedgehog;
             end;
     TPGearArray = array of PGear;
--- a/hedgewars/uVariables.pas	Sun Nov 18 23:09:29 2012 +0400
+++ b/hedgewars/uVariables.pas	Sun Nov 18 23:10:26 2012 +0400
@@ -21,7 +21,7 @@
 unit uVariables;
 interface
 
-uses SDLh, uTypes, uFloat, GLunit, uConsts, Math, uMobile;
+uses SDLh, uTypes, uFloat, GLunit, uConsts, Math, uMobile, uUtils;
 
 var
 /////// init flags ///////
@@ -108,7 +108,7 @@
     zoom             : GLfloat;
     ZoomValue        : GLfloat;
 
-    cWaterLine       : Word;
+    cWaterLine       : LongInt;
     cGearScrEdgesDist: LongInt;
     isAudioMuted     : boolean;
 
@@ -118,12 +118,9 @@
     SDWaterOpacity: byte;
     GrayScale: Boolean;
 
-    // originally from uConsts
-    Pathz: array[TPathType] of shortstring;
-    UserPathz: array[TPathType] of shortstring;
     CountTexz: array[0..Pred(AMMO_INFINITE)] of PTexture;
-    LAND_WIDTH       : Word;
-    LAND_HEIGHT      : Word;
+    LAND_WIDTH       : LongInt;
+    LAND_HEIGHT      : LongInt;
     LAND_WIDTH_MASK  : LongWord;
     LAND_HEIGHT_MASK : LongWord;
 
@@ -164,6 +161,10 @@
     AmmoMenuInvalidated: boolean;
     AmmoRect		: TSDL_Rect;
     HHTexture       : PTexture;
+    cMaxZoomLevel   : real;
+    cMinZoomLevel   : real;
+    cZoomDelta      : real;
+    cMinMaxZoomLevelDelta : real;
 
 
     flagMakeCapture : boolean;
@@ -192,8 +193,6 @@
     hiTicks: Word;
 
     LuaGoals        : shortstring;
-    hiddenHedgehogs : array [0..cMaxHHs] of PHedgehog;
-    hiddenHedgehogsNumber : longint;
 
     LuaTemplateNumber : LongWord;
 
@@ -223,27 +222,27 @@
     // these consts are here because they would cause circular dependencies in uConsts/uTypes
     cPathz: array[TPathType] of shortstring = (
         '',                              // ptNone
-        '',                              // ptData
-        'Graphics',                      // ptGraphics
-        'Themes',                        // ptThemes
-        'Themes/Bamboo',                 // ptCurrTheme
-        'Teams',                         // ptTeams
-        'Maps',                          // ptMaps
+        '/',                             // ptData
+        '/Graphics',                     // ptGraphics
+        '/Themes',                       // ptThemes
+        '/Themes/Bamboo',                // ptCurrTheme
+        '/Teams',                        // ptTeams
+        '/Maps',                         // ptMaps
         '',                              // ptMapCurrent
-        'Demos',                         // ptDemos
-        'Sounds',                        // ptSounds
-        'Graphics/Graves',               // ptGraves
-        'Fonts',                         // ptFonts
-        'Forts',                         // ptForts
-        'Locale',                        // ptLocale
-        'Graphics/AmmoMenu',             // ptAmmoMenu
-        'Graphics/Hedgehog',             // ptHedgehog
-        'Sounds/voices',                 // ptVoices
-        'Graphics/Hats',                 // ptHats
-        'Graphics/Flags',                // ptFlags
-        'Missions/Maps',                 // ptMissionMaps
-        'Graphics/SuddenDeath',           // ptSuddenDeath
-        'Graphics/Buttons'                // ptButton
+        '/Demos',                        // ptDemos
+        '/Sounds',                       // ptSounds
+        '/Graphics/Graves',              // ptGraves
+        '/Fonts',                        // ptFonts
+        '/Forts',                        // ptForts
+        '/Locale',                       // ptLocale
+        '/Graphics/AmmoMenu',            // ptAmmoMenu
+        '/Graphics/Hedgehog',            // ptHedgehog
+        '/Sounds/voices',                // ptVoices
+        '/Graphics/Hats',                // ptHats
+        '/Graphics/Flags',               // ptFlags
+        '/Missions/Maps',                // ptMissionMaps
+        '/Graphics/SuddenDeath',         // ptSuddenDeath
+        '/Graphics/Buttons'              // ptButton
     );
 
     Fontz: array[THWFont] of THHFont = (
@@ -716,6 +715,7 @@
             (FileName:               'Yessir.ogg'; Path: ptVoices),// sndYesSir
             (FileName:                'Laugh.ogg'; Path: ptVoices),// sndLaugh
             (FileName:            'Illgetyou.ogg'; Path: ptVoices),// sndIllGetYou
+            (FileName:          'JustYouWait.ogg'; Path: ptVoices),// sndJustYouWait
             (FileName:             'Incoming.ogg'; Path: ptVoices),// sndIncoming
             (FileName:               'Missed.ogg'; Path: ptVoices),// sndMissed
             (FileName:               'Stupid.ogg'; Path: ptVoices),// sndStupid
@@ -2553,11 +2553,13 @@
 
     UserPathPrefix  := '';
     ipcPort         := 0;
+    recordFileName  := '';
     UserNick        := '';
     cStereoMode     := smNone;
     GrayScale       := false;
     PathPrefix      := './';
     GameType        := gmtLocal;
+    cOnlyStats      := False;
 
 {$IFDEF USE_VIDEO_RECORDING}
     RecPrefix          := '';
@@ -2571,21 +2573,16 @@
 end;
 
 procedure initModule;
+var s: ShortString;
 begin
-
-    if (Length(cLocaleFName) > 6) then
-        cLocale := Copy(cLocaleFName,1,5)
-    else
-        cLocale := Copy(cLocaleFName,1,2);
+    cLocale:= cLocaleFName;
+    SplitByChar(cLocale, s, '.');
 
     cFlattenFlakes      := false;
     cFlattenClouds      := false;
-    cOnlyStats          := False;
     lastVisualGearByUID := nil;
     lastGearByUID       := nil;
-    recordFileName      := '';
     cReadyDelay         := 5000;
-    Pathz               := cPathz;
 
         {*  REFERENCE
       4096 -> $FFFFF000
@@ -2632,6 +2629,18 @@
     cDamageModifier         := _1;
     TargetPoint             := cTargetPointRef;
 
+{$IFDEF MOBILE}
+    cMaxZoomLevel:= 0.5;
+    cMinZoomLevel:= 3.5;
+    cZoomDelta:= 0.20;
+{$ELSE}
+    cMaxZoomLevel:= 1.0;
+    cMinZoomLevel:= 3.0;
+    cZoomDelta:= 0.25;
+{$ENDIF}
+
+    cMinMaxZoomLevelDelta:= cMaxZoomLevel - cMinZoomLevel;
+
     // int, longint longword and byte
     CursorMovementX     := 0;
     CursorMovementY     := 0;
@@ -2728,7 +2737,6 @@
     cMapName:= '';
 
     LuaTemplateNumber:= 0;
-    hiddenHedgehogsNumber:=0;
 end;
 
 procedure freeModule;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/Version_script.in	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,49 @@
+#
+# Export file for libvorbisidec
+#
+# Only the symbols listed in the global section will be callable from
+# applications linking to libvorbisidec.
+#
+
+@PACKAGE@.so.1
+{
+	global:
+		ov_clear;
+		ov_open;
+		ov_open_callbacks;
+		ov_test;
+		ov_test_callbacks;
+		ov_test_open;
+		ov_bitrate;
+		ov_bitrate_instant;
+		ov_streams;
+		ov_seekable;
+		ov_serialnumber;
+		ov_raw_total;
+		ov_pcm_total;
+		ov_time_total;
+		ov_raw_seek;
+		ov_pcm_seek;
+		ov_pcm_seek_page;
+		ov_time_seek;
+		ov_time_seek_page;
+		ov_raw_tell;
+		ov_pcm_tell;
+		ov_time_tell;
+		ov_info;
+		ov_comment;
+		ov_read;
+
+		vorbis_info_init;
+		vorbis_info_clear;
+		vorbis_info_blocksize;
+		vorbis_comment_init;
+		vorbis_comment_add;
+		vorbis_comment_add_tag;
+		vorbis_comment_query;
+		vorbis_comment_query_count;
+		vorbis_comment_clear;
+
+	local:
+		*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/backends.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,130 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: backend and mapping structures
+
+ ********************************************************************/
+
+/* this is exposed up here because we need it for static modes.
+   Lookups for each backend aren't exposed because there's no reason
+   to do so */
+
+#ifndef _vorbis_backend_h_
+#define _vorbis_backend_h_
+
+#include "codec_internal.h"
+
+/* this would all be simpler/shorter with templates, but.... */
+/* Transform backend generic *************************************/
+
+/* only mdct right now.  Flesh it out more if we ever transcend mdct
+   in the transform domain */
+
+/* Floor backend generic *****************************************/
+typedef struct{
+  vorbis_info_floor     *(*unpack)(vorbis_info *,oggpack_buffer *);
+  vorbis_look_floor     *(*look)  (vorbis_dsp_state *,vorbis_info_mode *,
+				   vorbis_info_floor *);
+  void (*free_info) (vorbis_info_floor *);
+  void (*free_look) (vorbis_look_floor *);
+  void *(*inverse1)  (struct vorbis_block *,vorbis_look_floor *);
+  int   (*inverse2)  (struct vorbis_block *,vorbis_look_floor *,
+		     void *buffer,ogg_int32_t *);
+} vorbis_func_floor;
+
+typedef struct{
+  int   order;
+  long  rate;
+  long  barkmap;
+
+  int   ampbits;
+  int   ampdB;
+
+  int   numbooks; /* <= 16 */
+  int   books[16];
+
+} vorbis_info_floor0;
+
+#define VIF_POSIT 63
+#define VIF_CLASS 16
+#define VIF_PARTS 31
+typedef struct{
+  int   partitions;                /* 0 to 31 */
+  int   partitionclass[VIF_PARTS]; /* 0 to 15 */
+
+  int   class_dim[VIF_CLASS];        /* 1 to 8 */
+  int   class_subs[VIF_CLASS];       /* 0,1,2,3 (bits: 1<<n poss) */
+  int   class_book[VIF_CLASS];       /* subs ^ dim entries */
+  int   class_subbook[VIF_CLASS][8]; /* [VIF_CLASS][subs] */
+
+
+  int   mult;                      /* 1 2 3 or 4 */
+  int   postlist[VIF_POSIT+2];    /* first two implicit */
+
+} vorbis_info_floor1;
+
+/* Residue backend generic *****************************************/
+typedef struct{
+  vorbis_info_residue *(*unpack)(vorbis_info *,oggpack_buffer *);
+  vorbis_look_residue *(*look)  (vorbis_dsp_state *,vorbis_info_mode *,
+				 vorbis_info_residue *);
+  void (*free_info)    (vorbis_info_residue *);
+  void (*free_look)    (vorbis_look_residue *);
+  int  (*inverse)      (struct vorbis_block *,vorbis_look_residue *,
+			ogg_int32_t **,int *,int);
+} vorbis_func_residue;
+
+typedef struct vorbis_info_residue0{
+/* block-partitioned VQ coded straight residue */
+  long  begin;
+  long  end;
+
+  /* first stage (lossless partitioning) */
+  int    grouping;         /* group n vectors per partition */
+  int    partitions;       /* possible codebooks for a partition */
+  int    groupbook;        /* huffbook for partitioning */
+  int    secondstages[64]; /* expanded out to pointers in lookup */
+  int    booklist[256];    /* list of second stage books */
+} vorbis_info_residue0;
+
+/* Mapping backend generic *****************************************/
+typedef struct{
+  vorbis_info_mapping *(*unpack)(vorbis_info *,oggpack_buffer *);
+  vorbis_look_mapping *(*look)  (vorbis_dsp_state *,vorbis_info_mode *,
+				 vorbis_info_mapping *);
+  void (*free_info)    (vorbis_info_mapping *);
+  void (*free_look)    (vorbis_look_mapping *);
+  int  (*inverse)      (struct vorbis_block *vb,vorbis_look_mapping *);
+} vorbis_func_mapping;
+
+typedef struct vorbis_info_mapping0{
+  int   submaps;  /* <= 16 */
+  int   chmuxlist[256];   /* up to 256 channels in a Vorbis stream */
+
+  int   floorsubmap[16];   /* [mux] submap to floors */
+  int   residuesubmap[16]; /* [mux] submap to residue */
+
+  int   psy[2]; /* by blocktype; impulse/padding for short,
+                   transition/normal for long */
+
+  int   coupling_steps;
+  int   coupling_mag[256];
+  int   coupling_ang[256];
+} vorbis_info_mapping0;
+
+#endif
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/block.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,453 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: PCM data vector blocking, windowing and dis/reassembly
+
+ ********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ogg.h"
+#include "ivorbiscodec.h"
+#include "codec_internal.h"
+
+#include "window.h"
+#include "registry.h"
+#include "misc.h"
+
+static int ilog(unsigned int v){
+  int ret=0;
+  if(v)--v;
+  while(v){
+    ret++;
+    v>>=1;
+  }
+  return(ret);
+}
+
+/* pcm accumulator examples (not exhaustive):
+
+ <-------------- lW ---------------->
+                   <--------------- W ---------------->
+:            .....|.....       _______________         |
+:        .'''     |     '''_---      |       |\        |
+:.....'''         |_____--- '''......|       | \_______|
+:.................|__________________|_______|__|______|
+                  |<------ Sl ------>|      > Sr <     |endW
+                  |beginSl           |endSl  |  |endSr
+                  |beginW            |endlW  |beginSr
+
+
+                      |< lW >|
+                   <--------------- W ---------------->
+                  |   |  ..  ______________            |
+                  |   | '  `/        |     ---_        |
+                  |___.'___/`.       |         ---_____|
+                  |_______|__|_______|_________________|
+                  |      >|Sl|<      |<------ Sr ----->|endW
+                  |       |  |endSl  |beginSr          |endSr
+                  |beginW |  |endlW
+                  mult[0] |beginSl                     mult[n]
+
+ <-------------- lW ----------------->
+                          |<--W-->|
+:            ..............  ___  |   |
+:        .'''             |`/   \ |   |
+:.....'''                 |/`....\|...|
+:.........................|___|___|___|
+                          |Sl |Sr |endW
+                          |   |   |endSr
+                          |   |beginSr
+                          |   |endSl
+			  |beginSl
+			  |beginW
+*/
+
+/* block abstraction setup *********************************************/
+
+#ifndef WORD_ALIGN
+#define WORD_ALIGN 8
+#endif
+
+int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
+  memset(vb,0,sizeof(*vb));
+  vb->vd=v;
+  vb->localalloc=0;
+  vb->localstore=NULL;
+
+  return(0);
+}
+
+void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
+  bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
+  if(bytes+vb->localtop>vb->localalloc){
+    /* can't just _ogg_realloc... there are outstanding pointers */
+    if(vb->localstore){
+      struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
+      vb->totaluse+=vb->localtop;
+      link->next=vb->reap;
+      link->ptr=vb->localstore;
+      vb->reap=link;
+    }
+    /* highly conservative */
+    vb->localalloc=bytes;
+    vb->localstore=_ogg_malloc(vb->localalloc);
+    vb->localtop=0;
+  }
+  {
+    void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
+    vb->localtop+=bytes;
+    return ret;
+  }
+}
+
+/* reap the chain, pull the ripcord */
+void _vorbis_block_ripcord(vorbis_block *vb){
+  /* reap the chain */
+  struct alloc_chain *reap=vb->reap;
+  while(reap){
+    struct alloc_chain *next=reap->next;
+    _ogg_free(reap->ptr);
+    memset(reap,0,sizeof(*reap));
+    _ogg_free(reap);
+    reap=next;
+  }
+  /* consolidate storage */
+  if(vb->totaluse){
+    vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
+    vb->localalloc+=vb->totaluse;
+    vb->totaluse=0;
+  }
+
+  /* pull the ripcord */
+  vb->localtop=0;
+  vb->reap=NULL;
+}
+
+int vorbis_block_clear(vorbis_block *vb){
+  _vorbis_block_ripcord(vb);
+  if(vb->localstore)_ogg_free(vb->localstore);
+
+  memset(vb,0,sizeof(*vb));
+  return(0);
+}
+
+static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
+  int i;
+  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
+  private_state *b=NULL;
+
+  memset(v,0,sizeof(*v));
+  b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
+
+  v->vi=vi;
+  b->modebits=ilog(ci->modes);
+
+  /* Vorbis I uses only window type 0 */
+  b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
+  b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
+
+  /* finish the codebooks */
+  if(!ci->fullbooks){
+    ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
+    for(i=0;i<ci->books;i++){
+      vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]);
+      /* decode codebooks are now standalone after init */
+      vorbis_staticbook_destroy(ci->book_param[i]);
+      ci->book_param[i]=NULL;
+    }
+  }
+
+  v->pcm_storage=ci->blocksizes[1];
+  v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
+  v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
+  for(i=0;i<vi->channels;i++)
+    v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
+
+  /* all 1 (large block) or 0 (small block) */
+  /* explicitly set for the sake of clarity */
+  v->lW=0; /* previous window size */
+  v->W=0;  /* current window size */
+
+  /* initialize all the mapping/backend lookups */
+  b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
+  for(i=0;i<ci->modes;i++){
+    int mapnum=ci->mode_param[i]->mapping;
+    int maptype=ci->map_type[mapnum];
+    b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
+					 ci->map_param[mapnum]);
+  }
+  return(0);
+}
+
+int vorbis_synthesis_restart(vorbis_dsp_state *v){
+  vorbis_info *vi=v->vi;
+  codec_setup_info *ci;
+
+  if(!v->backend_state)return -1;
+  if(!vi)return -1;
+  ci=vi->codec_setup;
+  if(!ci)return -1;
+
+  v->centerW=ci->blocksizes[1]/2;
+  v->pcm_current=v->centerW;
+
+  v->pcm_returned=-1;
+  v->granulepos=-1;
+  v->sequence=-1;
+  ((private_state *)(v->backend_state))->sample_count=-1;
+
+  return(0);
+}
+
+int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+  _vds_init(v,vi);
+  vorbis_synthesis_restart(v);
+
+  return(0);
+}
+
+void vorbis_dsp_clear(vorbis_dsp_state *v){
+  int i;
+  if(v){
+    vorbis_info *vi=v->vi;
+    codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
+    private_state *b=(private_state *)v->backend_state;
+
+    if(v->pcm){
+      for(i=0;i<vi->channels;i++)
+	if(v->pcm[i])_ogg_free(v->pcm[i]);
+      _ogg_free(v->pcm);
+      if(v->pcmret)_ogg_free(v->pcmret);
+    }
+
+    /* free mode lookups; these are actually vorbis_look_mapping structs */
+    if(ci){
+      for(i=0;i<ci->modes;i++){
+	int mapnum=ci->mode_param[i]->mapping;
+	int maptype=ci->map_type[mapnum];
+	if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
+      }
+    }
+
+    if(b){
+      if(b->mode)_ogg_free(b->mode);
+      _ogg_free(b);
+    }
+
+    memset(v,0,sizeof(*v));
+  }
+}
+
+/* Unlike in analysis, the window is only partially applied for each
+   block.  The time domain envelope is not yet handled at the point of
+   calling (as it relies on the previous block). */
+
+int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
+  vorbis_info *vi=v->vi;
+  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
+  private_state *b=v->backend_state;
+  int i,j;
+
+  if(v->pcm_current>v->pcm_returned  && v->pcm_returned!=-1)return(OV_EINVAL);
+
+  v->lW=v->W;
+  v->W=vb->W;
+  v->nW=-1;
+
+  if((v->sequence==-1)||
+     (v->sequence+1 != vb->sequence)){
+    v->granulepos=-1; /* out of sequence; lose count */
+    b->sample_count=-1;
+  }
+
+  v->sequence=vb->sequence;
+
+  if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly
+                   was called on block */
+    int n=ci->blocksizes[v->W]/2;
+    int n0=ci->blocksizes[0]/2;
+    int n1=ci->blocksizes[1]/2;
+
+    int thisCenter;
+    int prevCenter;
+
+    if(v->centerW){
+      thisCenter=n1;
+      prevCenter=0;
+    }else{
+      thisCenter=0;
+      prevCenter=n1;
+    }
+
+    /* v->pcm is now used like a two-stage double buffer.  We don't want
+       to have to constantly shift *or* adjust memory usage.  Don't
+       accept a new block until the old is shifted out */
+
+    /* overlap/add PCM */
+
+    for(j=0;j<vi->channels;j++){
+      /* the overlap/add section */
+      if(v->lW){
+	if(v->W){
+	  /* large/large */
+	  ogg_int32_t *pcm=v->pcm[j]+prevCenter;
+	  ogg_int32_t *p=vb->pcm[j];
+	  for(i=0;i<n1;i++)
+	    pcm[i]+=p[i];
+	}else{
+	  /* large/small */
+	  ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
+	  ogg_int32_t *p=vb->pcm[j];
+	  for(i=0;i<n0;i++)
+	    pcm[i]+=p[i];
+	}
+      }else{
+	if(v->W){
+	  /* small/large */
+	  ogg_int32_t *pcm=v->pcm[j]+prevCenter;
+	  ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
+	  for(i=0;i<n0;i++)
+	    pcm[i]+=p[i];
+	  for(;i<n1/2+n0/2;i++)
+	    pcm[i]=p[i];
+	}else{
+	  /* small/small */
+	  ogg_int32_t *pcm=v->pcm[j]+prevCenter;
+	  ogg_int32_t *p=vb->pcm[j];
+	  for(i=0;i<n0;i++)
+	    pcm[i]+=p[i];
+	}
+      }
+
+      /* the copy section */
+      {
+	ogg_int32_t *pcm=v->pcm[j]+thisCenter;
+	ogg_int32_t *p=vb->pcm[j]+n;
+	for(i=0;i<n;i++)
+	  pcm[i]=p[i];
+      }
+    }
+
+    if(v->centerW)
+      v->centerW=0;
+    else
+      v->centerW=n1;
+
+    /* deal with initial packet state; we do this using the explicit
+       pcm_returned==-1 flag otherwise we're sensitive to first block
+       being short or long */
+
+    if(v->pcm_returned==-1){
+      v->pcm_returned=thisCenter;
+      v->pcm_current=thisCenter;
+    }else{
+      v->pcm_returned=prevCenter;
+      v->pcm_current=prevCenter+
+	ci->blocksizes[v->lW]/4+
+	ci->blocksizes[v->W]/4;
+    }
+
+  }
+
+  /* track the frame number... This is for convenience, but also
+     making sure our last packet doesn't end with added padding.  If
+     the last packet is partial, the number of samples we'll have to
+     return will be past the vb->granulepos.
+     
+     This is not foolproof!  It will be confused if we begin
+     decoding at the last page after a seek or hole.  In that case,
+     we don't have a starting point to judge where the last frame
+     is.  For this reason, vorbisfile will always try to make sure
+     it reads the last two marked pages in proper sequence */
+
+  if(b->sample_count==-1){
+    b->sample_count=0;
+  }else{
+    b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+  }
+
+  if(v->granulepos==-1){
+    if(vb->granulepos!=-1){ /* only set if we have a position to set to */
+
+      v->granulepos=vb->granulepos;
+
+      /* is this a short page? */
+      if(b->sample_count>v->granulepos){
+	/* corner case; if this is both the first and last audio page,
+	   then spec says the end is cut, not beginning */
+	if(vb->eofflag){
+	  /* trim the end */
+	  /* no preceeding granulepos; assume we started at zero (we'd
+	     have to in a short single-page stream) */
+	  /* granulepos could be -1 due to a seek, but that would result
+	     in a long coun`t, not short count */
+
+	  v->pcm_current-=(b->sample_count-v->granulepos);
+	}else{
+	  /* trim the beginning */
+	  v->pcm_returned+=(b->sample_count-v->granulepos);
+	  if(v->pcm_returned>v->pcm_current)
+	    v->pcm_returned=v->pcm_current;
+	}
+
+      }
+
+    }
+  }else{
+    v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+    if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
+      
+      if(v->granulepos>vb->granulepos){
+	long extra=v->granulepos-vb->granulepos;
+	
+	if(extra)
+	  if(vb->eofflag){
+	    /* partial last frame.  Strip the extra samples off */
+	    v->pcm_current-=extra;
+	  } /* else {Shouldn't happen *unless* the bitstream is out of
+	       spec.  Either way, believe the bitstream } */
+      } /* else {Shouldn't happen *unless* the bitstream is out of
+	   spec.  Either way, believe the bitstream } */
+      v->granulepos=vb->granulepos;
+    }
+  }
+
+  /* Update, cleanup */
+
+  if(vb->eofflag)v->eofflag=1;
+  return(0);
+}
+
+/* pcm==NULL indicates we just want the pending samples, no more */
+int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
+  vorbis_info *vi=v->vi;
+  if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
+    if(pcm){
+      int i;
+      for(i=0;i<vi->channels;i++)
+	v->pcmret[i]=v->pcm[i]+v->pcm_returned;
+      *pcm=v->pcmret;
+    }
+    return(v->pcm_current-v->pcm_returned);
+  }
+  return(0);
+}
+
+int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
+  if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
+  v->pcm_returned+=bytes;
+  return(0);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/block.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,26 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2008    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: shared block functions
+
+ ********************************************************************/
+
+#ifndef _V_BLOCK_
+#define _V_BLOCK_
+
+#include "ivorbiscodec.h"
+
+extern void _vorbis_block_ripcord(vorbis_block *vb);
+extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/registry.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,50 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: registry for floor, res backends and channel mappings
+
+ ********************************************************************/
+
+#include "ivorbiscodec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "misc.h"
+
+
+/* seems like major overkill now; the backend numbers will grow into
+   the infrastructure soon enough */
+
+extern vorbis_func_floor     floor0_exportbundle;
+extern vorbis_func_floor     floor1_exportbundle;
+extern vorbis_func_residue   residue0_exportbundle;
+extern vorbis_func_residue   residue1_exportbundle;
+extern vorbis_func_residue   residue2_exportbundle;
+extern vorbis_func_mapping   mapping0_exportbundle;
+
+vorbis_func_floor     *_floor_P[]={
+  &floor0_exportbundle,
+  &floor1_exportbundle,
+};
+
+vorbis_func_residue   *_residue_P[]={
+  &residue0_exportbundle,
+  &residue1_exportbundle,
+  &residue2_exportbundle,
+};
+
+vorbis_func_mapping   *_mapping_P[]={
+  &mapping0_exportbundle,
+};
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/registry.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,40 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: registry for time, floor, res backends and channel mappings
+
+ ********************************************************************/
+
+#ifndef _V_REG_H_
+#define _V_REG_H_
+
+#define VI_TRANSFORMB 1
+#define VI_WINDOWB 1
+#define VI_TIMEB 1
+#define VI_FLOORB 2
+#define VI_RESB 3
+#define VI_MAPB 1
+
+#include "backends.h"
+
+#if defined(_WIN32) && defined(VORBISDLL_IMPORT)
+# define EXTERN __declspec(dllimport) extern
+#else
+# define EXTERN extern
+#endif
+
+EXTERN vorbis_func_floor     *_floor_P[];
+EXTERN vorbis_func_residue   *_residue_P[];
+EXTERN vorbis_func_mapping   *_mapping_P[];
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/sharedbook.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,439 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: basic shared codebook operations
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "ogg.h"
+#include "misc.h"
+#include "ivorbiscodec.h"
+#include "codebook.h"
+
+/**** pack/unpack helpers ******************************************/
+int _ilog(unsigned int v){
+  int ret=0;
+  while(v){
+    ret++;
+    v>>=1;
+  }
+  return(ret);
+}
+
+/* 32 bit float (not IEEE; nonnormalized mantissa +
+   biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm 
+   Why not IEEE?  It's just not that important here. */
+
+#define VQ_FEXP 10
+#define VQ_FMAN 21
+#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
+
+static ogg_int32_t _float32_unpack(long val,int *point){
+  long   mant=val&0x1fffff;
+  int    sign=val&0x80000000;
+  long   exp =(val&0x7fe00000L)>>VQ_FMAN;
+
+  exp-=(VQ_FMAN-1)+VQ_FEXP_BIAS;
+
+  if(mant){
+    while(!(mant&0x40000000)){
+      mant<<=1;
+      exp-=1;
+    }
+
+    if(sign)mant= -mant;
+  }else{
+    sign=0;
+    exp=-9999;
+  }
+
+  *point=exp;
+  return mant;
+}
+
+/* given a list of word lengths, generate a list of codewords.  Works
+   for length ordered or unordered, always assigns the lowest valued
+   codewords first.  Extended to handle unused entries (length 0) */
+ogg_uint32_t *_make_words(long *l,long n,long sparsecount){
+  long i,j,count=0;
+  ogg_uint32_t marker[33];
+  ogg_uint32_t *r=(ogg_uint32_t *)_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
+  memset(marker,0,sizeof(marker));
+
+  for(i=0;i<n;i++){
+    long length=l[i];
+    if(length>0){
+      ogg_uint32_t entry=marker[length];
+      
+      /* when we claim a node for an entry, we also claim the nodes
+	 below it (pruning off the imagined tree that may have dangled
+	 from it) as well as blocking the use of any nodes directly
+	 above for leaves */
+      
+      /* update ourself */
+      if(length<32 && (entry>>length)){
+	/* error condition; the lengths must specify an overpopulated tree */
+	_ogg_free(r);
+	return(NULL);
+      }
+      r[count++]=entry;
+    
+      /* Look to see if the next shorter marker points to the node
+	 above. if so, update it and repeat.  */
+      {
+	for(j=length;j>0;j--){
+	  
+	  if(marker[j]&1){
+	    /* have to jump branches */
+	    if(j==1)
+	      marker[1]++;
+	    else
+	      marker[j]=marker[j-1]<<1;
+	    break; /* invariant says next upper marker would already
+		      have been moved if it was on the same path */
+	  }
+	  marker[j]++;
+	}
+      }
+      
+      /* prune the tree; the implicit invariant says all the longer
+	 markers were dangling from our just-taken node.  Dangle them
+	 from our *new* node. */
+      for(j=length+1;j<33;j++)
+	if((marker[j]>>1) == entry){
+	  entry=marker[j];
+	  marker[j]=marker[j-1]<<1;
+	}else
+	  break;
+    }else
+      if(sparsecount==0)count++;
+  }
+    
+  /* bitreverse the words because our bitwise packer/unpacker is LSb
+     endian */
+  for(i=0,count=0;i<n;i++){
+    ogg_uint32_t temp=0;
+    for(j=0;j<l[i];j++){
+      temp<<=1;
+      temp|=(r[count]>>j)&1;
+    }
+
+    if(sparsecount){
+      if(l[i])
+	r[count++]=temp;
+    }else
+      r[count++]=temp;
+  }
+
+  return(r);
+}
+
+/* there might be a straightforward one-line way to do the below
+   that's portable and totally safe against roundoff, but I haven't
+   thought of it.  Therefore, we opt on the side of caution */
+long _book_maptype1_quantvals(const static_codebook *b){
+  /* get us a starting hint, we'll polish it below */
+  int bits=_ilog(b->entries);
+  int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim);
+
+  while(1){
+    long acc=1;
+    long acc1=1;
+    int i;
+    for(i=0;i<b->dim;i++){
+      acc*=vals;
+      acc1*=vals+1;
+    }
+    if(acc<=b->entries && acc1>b->entries){
+      return(vals);
+    }else{
+      if(acc>b->entries){
+	vals--;
+      }else{
+	vals++;
+      }
+    }
+  }
+}
+
+/* different than what _book_unquantize does for mainline:
+   we repack the book in a fixed point format that shares the same
+   binary point.  Upon first use, we can shift point if needed */
+
+/* we need to deal with two map types: in map type 1, the values are
+   generated algorithmically (each column of the vector counts through
+   the values in the quant vector). in map type 2, all the values came
+   in in an explicit list.  Both value lists must be unpacked */
+
+ogg_int32_t *_book_unquantize(const static_codebook *b,int n,int *sparsemap,
+			      int *maxpoint){
+  long j,k,count=0;
+  if(b->maptype==1 || b->maptype==2){
+    int quantvals;
+    int minpoint,delpoint;
+    ogg_int32_t mindel=_float32_unpack(b->q_min,&minpoint);
+    ogg_int32_t delta=_float32_unpack(b->q_delta,&delpoint);
+    ogg_int32_t *r=(ogg_int32_t *)_ogg_calloc(n*b->dim,sizeof(*r));
+    int *rp=(int *)_ogg_calloc(n*b->dim,sizeof(*rp));
+
+    *maxpoint=minpoint;
+
+    /* maptype 1 and 2 both use a quantized value vector, but
+       different sizes */
+    switch(b->maptype){
+    case 1:
+      /* most of the time, entries%dimensions == 0, but we need to be
+	 well defined.  We define that the possible vales at each
+	 scalar is values == entries/dim.  If entries%dim != 0, we'll
+	 have 'too few' values (values*dim<entries), which means that
+	 we'll have 'left over' entries; left over entries use zeroed
+	 values (and are wasted).  So don't generate codebooks like
+	 that */
+      quantvals=_book_maptype1_quantvals(b);
+      for(j=0;j<b->entries;j++){
+	if((sparsemap && b->lengthlist[j]) || !sparsemap){
+	  ogg_int32_t last=0;
+	  int lastpoint=0;
+	  int indexdiv=1;
+	  for(k=0;k<b->dim;k++){
+	    int index= (j/indexdiv)%quantvals;
+	    int point=0;
+	    int val=VFLOAT_MULTI(delta,delpoint,
+				 abs(b->quantlist[index]),&point);
+
+	    val=VFLOAT_ADD(mindel,minpoint,val,point,&point);
+	    val=VFLOAT_ADD(last,lastpoint,val,point,&point);
+	    
+	    if(b->q_sequencep){
+	      last=val;	  
+	      lastpoint=point;
+	    }
+	    
+	    if(sparsemap){
+	      r[sparsemap[count]*b->dim+k]=val;
+	      rp[sparsemap[count]*b->dim+k]=point;
+	    }else{
+	      r[count*b->dim+k]=val;
+	      rp[count*b->dim+k]=point;
+	    }
+	    if(*maxpoint<point)*maxpoint=point;
+	    indexdiv*=quantvals;
+	  }
+	  count++;
+	}
+
+      }
+      break;
+    case 2:
+      for(j=0;j<b->entries;j++){
+	if((sparsemap && b->lengthlist[j]) || !sparsemap){
+	  ogg_int32_t last=0;
+	  int         lastpoint=0;
+
+	  for(k=0;k<b->dim;k++){
+	    int point=0;
+	    int val=VFLOAT_MULTI(delta,delpoint,
+				 abs(b->quantlist[j*b->dim+k]),&point);
+
+	    val=VFLOAT_ADD(mindel,minpoint,val,point,&point);
+	    val=VFLOAT_ADD(last,lastpoint,val,point,&point);
+	    
+	    if(b->q_sequencep){
+	      last=val;	  
+	      lastpoint=point;
+	    }
+
+	    if(sparsemap){
+	      r[sparsemap[count]*b->dim+k]=val;
+	      rp[sparsemap[count]*b->dim+k]=point;
+	    }else{
+	      r[count*b->dim+k]=val;
+	      rp[count*b->dim+k]=point;
+	    }
+	    if(*maxpoint<point)*maxpoint=point;
+	  }
+	  count++;
+	}
+      }
+      break;
+    }
+
+    for(j=0;j<n*b->dim;j++)
+      if(rp[j]<*maxpoint)
+	r[j]>>=*maxpoint-rp[j];
+	    
+    _ogg_free(rp);
+    return(r);
+  }
+  return(NULL);
+}
+
+void vorbis_staticbook_clear(static_codebook *b){
+  if(b->quantlist)_ogg_free(b->quantlist);
+  if(b->lengthlist)_ogg_free(b->lengthlist);
+  memset(b,0,sizeof(*b));
+
+}
+
+void vorbis_staticbook_destroy(static_codebook *b){
+  vorbis_staticbook_clear(b);
+  _ogg_free(b);
+}
+
+void vorbis_book_clear(codebook *b){
+  /* static book is not cleared; we're likely called on the lookup and
+     the static codebook belongs to the info struct */
+  if(b->valuelist)_ogg_free(b->valuelist);
+  if(b->codelist)_ogg_free(b->codelist);
+
+  if(b->dec_index)_ogg_free(b->dec_index);
+  if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
+  if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
+
+  memset(b,0,sizeof(*b));
+}
+
+static ogg_uint32_t bitreverse(ogg_uint32_t x){
+  x=    ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
+  x=    ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
+  x=    ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
+  x=    ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
+  return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
+}
+
+static int sort32a(const void *a,const void *b){
+  return (**(ogg_uint32_t **)a>**(ogg_uint32_t **)b)-
+    (**(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
+}
+
+/* decode codebook arrangement is more heavily optimized than encode */
+int vorbis_book_init_decode(codebook *c,const static_codebook *s){
+  int i,j,n=0,tabn;
+  int *sortindex;
+  memset(c,0,sizeof(*c));
+  
+  /* count actually used entries */
+  for(i=0;i<s->entries;i++)
+    if(s->lengthlist[i]>0)
+      n++;
+
+  c->entries=s->entries;
+  c->used_entries=n;
+  c->dim=s->dim;
+
+  if(n>0){
+    /* two different remappings go on here.  
+       
+       First, we collapse the likely sparse codebook down only to
+       actually represented values/words.  This collapsing needs to be
+       indexed as map-valueless books are used to encode original entry
+       positions as integers.
+       
+       Second, we reorder all vectors, including the entry index above,
+       by sorted bitreversed codeword to allow treeless decode. */
+    
+    /* perform sort */
+    ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
+    ogg_uint32_t **codep=(ogg_uint32_t **)alloca(sizeof(*codep)*n);
+    
+    if(codes==NULL)goto err_out;
+
+    for(i=0;i<n;i++){
+      codes[i]=bitreverse(codes[i]);
+      codep[i]=codes+i;
+    }
+
+    qsort(codep,n,sizeof(*codep),sort32a);
+
+    sortindex=(int *)alloca(n*sizeof(*sortindex));
+    c->codelist=(ogg_uint32_t *)_ogg_malloc(n*sizeof(*c->codelist));
+    /* the index is a reverse index */
+    for(i=0;i<n;i++){
+      int position=codep[i]-codes;
+      sortindex[position]=i;
+    }
+
+    for(i=0;i<n;i++)
+      c->codelist[sortindex[i]]=codes[i];
+    _ogg_free(codes);
+    
+    
+    
+    c->valuelist=_book_unquantize(s,n,sortindex,&c->binarypoint);
+    c->dec_index=(int *)_ogg_malloc(n*sizeof(*c->dec_index));
+    
+    for(n=0,i=0;i<s->entries;i++)
+      if(s->lengthlist[i]>0)
+	c->dec_index[sortindex[n++]]=i;
+    
+    c->dec_codelengths=(char *)_ogg_malloc(n*sizeof(*c->dec_codelengths));
+    for(n=0,i=0;i<s->entries;i++)
+      if(s->lengthlist[i]>0)
+	c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
+    
+    c->dec_firsttablen=_ilog(c->used_entries)-4; /* this is magic */
+    if(c->dec_firsttablen<5)c->dec_firsttablen=5;
+    if(c->dec_firsttablen>8)c->dec_firsttablen=8;
+    
+    tabn=1<<c->dec_firsttablen;
+    c->dec_firsttable=(ogg_uint32_t *)_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
+    c->dec_maxlength=0;
+    
+    for(i=0;i<n;i++){
+      if(c->dec_maxlength<c->dec_codelengths[i])
+	c->dec_maxlength=c->dec_codelengths[i];
+      if(c->dec_codelengths[i]<=c->dec_firsttablen){
+	ogg_uint32_t orig=bitreverse(c->codelist[i]);
+	for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
+	  c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
+      }
+    }
+    
+    /* now fill in 'unused' entries in the firsttable with hi/lo search
+       hints for the non-direct-hits */
+    {
+      ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
+      long lo=0,hi=0;
+      
+      for(i=0;i<tabn;i++){
+	ogg_uint32_t word=i<<(32-c->dec_firsttablen);
+	if(c->dec_firsttable[bitreverse(word)]==0){
+	  while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
+	  while(    hi<n && word>=(c->codelist[hi]&mask))hi++;
+	  
+	  /* we only actually have 15 bits per hint to play with here.
+	     In order to overflow gracefully (nothing breaks, efficiency
+	     just drops), encode as the difference from the extremes. */
+	  {
+	    unsigned long loval=lo;
+	    unsigned long hival=n-hi;
+	    
+	    if(loval>0x7fff)loval=0x7fff;
+	    if(hival>0x7fff)hival=0x7fff;
+	    c->dec_firsttable[bitreverse(word)]=
+	      0x80000000UL | (loval<<15) | hival;
+	  }
+	}
+      }
+    }
+  }
+
+  return(0);
+ err_out:
+  vorbis_book_clear(c);
+  return(-1);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/synthesis.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,113 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: single-block PCM synthesis
+ last mod: $Id: synthesis.c,v 1.4 2003/03/29 03:07:21 xiphmont Exp $
+
+ ********************************************************************/
+
+#include <stdio.h>
+#include "ogg.h"
+#include "ivorbiscodec.h"
+#include "codec_internal.h"
+#include "registry.h"
+#include "misc.h"
+#include "block.h"
+
+int vorbis_synthesis(vorbis_block *vb,ogg_packet *op,int decodep){
+  vorbis_dsp_state     *vd=vb->vd;
+  private_state        *b=(private_state *)vd->backend_state;
+  vorbis_info          *vi=vd->vi;
+  codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
+  oggpack_buffer       *opb=&vb->opb;
+  int                   type,mode,i;
+ 
+  /* first things first.  Make sure decode is ready */
+  _vorbis_block_ripcord(vb);
+  oggpack_readinit(opb,op->packet);
+
+  /* Check the packet type */
+  if(oggpack_read(opb,1)!=0){
+    /* Oops.  This is not an audio data packet */
+    return(OV_ENOTAUDIO);
+  }
+
+  /* read our mode and pre/post windowsize */
+  mode=oggpack_read(opb,b->modebits);
+  if(mode==-1)return(OV_EBADPACKET);
+  
+  vb->mode=mode;
+  vb->W=ci->mode_param[mode]->blockflag;
+  if(vb->W){
+    vb->lW=oggpack_read(opb,1);
+    vb->nW=oggpack_read(opb,1);
+    if(vb->nW==-1)   return(OV_EBADPACKET);
+  }else{
+    vb->lW=0;
+    vb->nW=0;
+  }
+  
+  /* more setup */
+  vb->granulepos=op->granulepos;
+  vb->sequence=op->packetno-3; /* first block is third packet */
+  vb->eofflag=op->e_o_s;
+
+  if(decodep){
+    /* alloc pcm passback storage */
+    vb->pcmend=ci->blocksizes[vb->W];
+    vb->pcm=(ogg_int32_t **)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
+    for(i=0;i<vi->channels;i++)
+      vb->pcm[i]=(ogg_int32_t *)_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
+    
+    /* unpack_header enforces range checking */
+    type=ci->map_type[ci->mode_param[mode]->mapping];
+    
+    return(_mapping_P[type]->inverse(vb,b->mode[mode]));
+  }else{
+    /* no pcm */
+    vb->pcmend=0;
+    vb->pcm=NULL;
+    
+    return(0);
+  }
+}
+
+long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
+  codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
+  oggpack_buffer       opb;
+  int                  mode;
+ 
+  oggpack_readinit(&opb,op->packet);
+
+  /* Check the packet type */
+  if(oggpack_read(&opb,1)!=0){
+    /* Oops.  This is not an audio data packet */
+    return(OV_ENOTAUDIO);
+  }
+
+  {
+    int modebits=0;
+    int v=ci->modes;
+    while(v>1){
+      modebits++;
+      v>>=1;
+    }
+
+    /* read our mode and pre/post windowsize */
+    mode=oggpack_read(&opb,modebits);
+  }
+  if(mode==-1)return(OV_EBADPACKET);
+  return(ci->blocksizes[ci->mode_param[mode]->blockflag]);
+}
+
+
--- a/misc/libtremor/tremor/vorbisfile.c	Sun Nov 18 23:09:29 2012 +0400
+++ b/misc/libtremor/tremor/vorbisfile.c	Sun Nov 18 23:10:26 2012 +0400
@@ -740,7 +740,7 @@
     ogg_sync_destroy(vf->oy);
 
     if(vf->datasource && vf->callbacks.close_func)
-      (vf->callbacks.close_func)(vf->datasource);
+        (vf->callbacks.close_func)(vf->datasource);
     memset(vf,0,sizeof(*vf));
   }
 #ifdef DEBUG_LEAKS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/window.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,83 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: window functions
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <math.h>
+#include "misc.h"
+#include "window.h"
+#include "window_lookup.h"
+
+const void *_vorbis_window(int type, int left){
+
+  switch(type){
+  case 0:
+
+    switch(left){
+    case 32:
+      return vwin64;
+    case 64:
+      return vwin128;
+    case 128:
+      return vwin256;
+    case 256:
+      return vwin512;
+    case 512:
+      return vwin1024;
+    case 1024:
+      return vwin2048;
+    case 2048:
+      return vwin4096;
+    case 4096:
+      return vwin8192;
+    default:
+      return(0);
+    }
+    break;
+  default:
+    return(0);
+  }
+}
+
+void _vorbis_apply_window(ogg_int32_t *d,const void *window_p[2],
+			  long *blocksizes,
+			  int lW,int W,int nW){
+  
+  LOOKUP_T *window[2]={window_p[0],window_p[1]};
+  long n=blocksizes[W];
+  long ln=blocksizes[lW];
+  long rn=blocksizes[nW];
+
+  long leftbegin=n/4-ln/4;
+  long leftend=leftbegin+ln/2;
+
+  long rightbegin=n/2+n/4-rn/4;
+  long rightend=rightbegin+rn/2;
+  
+  int i,p;
+
+  for(i=0;i<leftbegin;i++)
+    d[i]=0;
+
+  for(p=0;i<leftend;i++,p++)
+    d[i]=MULT31(d[i],window[lW][p]);
+
+  for(i=rightbegin,p=rn/2-1;i<rightend;i++,p--)
+    d[i]=MULT31(d[i],window[nW][p]);
+
+  for(;i<n;i++)
+    d[i]=0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libtremor/tremor/window.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,27 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: window functions
+
+ ********************************************************************/
+
+#ifndef _V_WINDOW_
+#define _V_WINDOW_
+
+extern const void *_vorbis_window(int type,int left);
+extern void _vorbis_apply_window(ogg_int32_t *d,const void *window[2],
+				 long *blocksizes,
+				 int lW,int W,int nW);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/CMakeLists.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,546 @@
+# PhysicsFS; a portable, flexible file i/o abstraction.
+# Copyright (C) 2007  Ryan C. Gordon.
+#
+# Please see the file LICENSE.txt in the source's root directory.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+
+PROJECT(PhysicsFS)
+SET(PHYSFS_VERSION 2.1.0)
+
+# Increment this if/when we break backwards compatibility.
+SET(PHYSFS_SOVERSION 1)
+
+# I hate that they define "WIN32" ... we're about to move to Win64...I hope!
+IF(WIN32 AND NOT WINDOWS)
+    SET(WINDOWS TRUE)
+ENDIF(WIN32 AND NOT WINDOWS)
+
+# Bleh, let's do it for "APPLE" too.
+IF(APPLE AND NOT MACOSX)
+    SET(MACOSX TRUE)
+ENDIF(APPLE AND NOT MACOSX)
+
+# For now, Haiku and BeOS are the same, as far as the build system cares.
+IF(HAIKU AND NOT BEOS)
+    SET(BEOS TRUE)
+ENDIF(HAIKU AND NOT BEOS)
+
+IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+    SET(SOLARIS TRUE)
+ENDIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckCSourceCompiles)
+
+INCLUDE_DIRECTORIES(./src)
+
+IF(MACOSX)
+    # Fallback to older OS X on PowerPC to support wider range of systems...
+    IF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+        ADD_DEFINITIONS(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020)
+        SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2")
+    ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES ppc)
+
+    # Need these everywhere...
+    ADD_DEFINITIONS(-fno-common)
+    SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework Carbon -framework IOKit")
+ENDIF(MACOSX)
+
+# Add some gcc-specific command lines.
+IF(CMAKE_COMPILER_IS_GNUCC)
+    # Always build with debug symbols...you can strip it later.
+    ADD_DEFINITIONS(-g -pipe -Werror -fsigned-char)
+
+    # Stupid BeOS generates warnings in the system headers.
+    IF(NOT BEOS)
+        ADD_DEFINITIONS(-Wall)
+    ENDIF(NOT BEOS)
+
+    CHECK_C_SOURCE_COMPILES("
+        #if ((defined(__GNUC__)) && (__GNUC__ >= 4))
+        int main(int argc, char **argv) { int is_gcc4 = 1; return 0; }
+        #else
+        #error This is not gcc4.
+        #endif
+    " PHYSFS_IS_GCC4)
+
+    IF(PHYSFS_IS_GCC4)
+        # Not supported on several operating systems at this time.
+        IF(NOT SOLARIS AND NOT WINDOWS)
+            ADD_DEFINITIONS(-fvisibility=hidden)
+        ENDIF(NOT SOLARIS AND NOT WINDOWS)
+    ENDIF(PHYSFS_IS_GCC4)
+
+    # Don't use -rpath.
+    SET(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE)
+ENDIF(CMAKE_COMPILER_IS_GNUCC)
+
+IF(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+    ADD_DEFINITIONS(-erroff=E_EMPTY_TRANSLATION_UNIT)
+    ADD_DEFINITIONS(-xldscope=hidden)
+ENDIF(CMAKE_C_COMPILER_ID STREQUAL "SunPro")
+
+IF(MSVC)
+    # VS.NET 8.0 got really really anal about strcpy, etc, which even if we
+    #  cleaned up our code, zlib, etc still use...so disable the warning.
+    ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS=1)
+ENDIF(MSVC)
+
+# Basic chunks of source code ...
+
+SET(LZMA_SRCS
+    src/lzma/C/7zCrc.c
+    src/lzma/C/Archive/7z/7zBuffer.c
+    src/lzma/C/Archive/7z/7zDecode.c
+    src/lzma/C/Archive/7z/7zExtract.c
+    src/lzma/C/Archive/7z/7zHeader.c
+    src/lzma/C/Archive/7z/7zIn.c
+    src/lzma/C/Archive/7z/7zItem.c
+    src/lzma/C/Archive/7z/7zMethodID.c
+    src/lzma/C/Compress/Branch/BranchX86.c
+    src/lzma/C/Compress/Branch/BranchX86_2.c
+    src/lzma/C/Compress/Lzma/LzmaDecode.c
+)
+
+IF(BEOS)
+    # We add this explicitly, since we don't want CMake to think this
+    #  is a C++ project unless we're on BeOS.
+    SET(PHYSFS_BEOS_SRCS src/platform_beos.cpp)
+    FIND_LIBRARY(BE_LIBRARY be)
+    FIND_LIBRARY(ROOT_LIBRARY root)
+    SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY})
+ENDIF(BEOS)
+
+# Almost everything is "compiled" here, but things that don't apply to the
+#  build are #ifdef'd out. This is to make it easy to embed PhysicsFS into
+#  another project or bring up a new build system: just compile all the source
+#  code and #define the things you want.
+SET(PHYSFS_SRCS
+    src/physfs.c
+    src/physfs_byteorder.c
+    src/physfs_unicode.c
+    src/platform_posix.c
+    src/platform_unix.c
+    src/platform_macosx.c
+    src/platform_windows.c
+    src/archiver_dir.c
+    src/archiver_unpacked.c
+    src/archiver_grp.c
+    src/archiver_hog.c
+    src/archiver_lzma.c
+    src/archiver_mvl.c
+    src/archiver_qpak.c
+    src/archiver_wad.c
+    src/archiver_zip.c
+    src/archiver_iso9660.c
+    ${PHYSFS_BEOS_SRCS}
+)
+
+
+# platform layers ...
+
+IF(UNIX)
+    IF(BEOS)
+        SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+        SET(HAVE_PTHREAD_H TRUE)
+    ELSE(BEOS)
+        CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H)
+        IF(HAVE_UCRED_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_UCRED_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_UCRED_H)
+
+        CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H)
+        IF(HAVE_MNTENT_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_MNTENT_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_MNTENT_H)
+
+        # !!! FIXME: Solaris fails this, because mnttab.h implicitly
+        # !!! FIXME:  depends on other system headers.  :(
+        #CHECK_INCLUDE_FILE(sys/mnttab.h HAVE_SYS_MNTTAB_H)
+        CHECK_C_SOURCE_COMPILES("
+            #include <stdio.h>
+            #include <sys/mnttab.h>
+            int main(int argc, char **argv) { return 0; }
+        " HAVE_SYS_MNTTAB_H)
+
+        IF(HAVE_SYS_MNTTAB_H)
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_MNTTAB_H=1)
+            SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+        ENDIF(HAVE_SYS_MNTTAB_H)
+
+        CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
+        IF(HAVE_PTHREAD_H)
+            SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+        ENDIF(HAVE_PTHREAD_H)
+    ENDIF(BEOS)
+ENDIF(UNIX)
+
+IF(WINDOWS)
+    SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE)
+    SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE)
+ENDIF(WINDOWS)
+
+IF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+    ADD_DEFINITIONS(-DPHYSFS_NO_CDROM_SUPPORT=1)
+    MESSAGE(WARNING " ***")
+    MESSAGE(WARNING " *** There is no CD-ROM support in this build!")
+    MESSAGE(WARNING " *** PhysicsFS will just pretend there are no discs.")
+    MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+    MESSAGE(WARNING " ***   but is this what you REALLY wanted?")
+    MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+    MESSAGE(WARNING " ***")
+ENDIF(NOT PHYSFS_HAVE_CDROM_SUPPORT)
+
+IF(PHYSFS_HAVE_THREAD_SUPPORT)
+    ADD_DEFINITIONS(-D_REENTRANT -D_THREAD_SAFE)
+ELSE(PHYSFS_HAVE_THREAD_SUPPORT)
+    ADD_DEFINITIONS(-DPHYSFS_NO_THREAD_SUPPORT=1)
+    MESSAGE(WARNING " ***")
+    MESSAGE(WARNING " *** There is no thread support in this build!")
+    MESSAGE(WARNING " *** PhysicsFS will NOT be reentrant!")
+    MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,")
+    MESSAGE(WARNING " ***   but is this what you REALLY wanted?")
+    MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)")
+    MESSAGE(WARNING " ***")
+ENDIF(PHYSFS_HAVE_THREAD_SUPPORT)
+
+
+# Archivers ...
+
+OPTION(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE)
+IF(PHYSFS_ARCHIVE_ZIP)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ZIP=1)
+ENDIF(PHYSFS_ARCHIVE_ZIP)
+
+OPTION(PHYSFS_ARCHIVE_7Z "Enable 7zip support" FALSE)
+IF(PHYSFS_ARCHIVE_7Z)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_7Z=1)
+    # !!! FIXME: rename to 7z.c?
+    SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${LZMA_SRCS})
+ENDIF(PHYSFS_ARCHIVE_7Z)
+
+OPTION(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE)
+IF(PHYSFS_ARCHIVE_GRP)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_GRP=1)
+ENDIF(PHYSFS_ARCHIVE_GRP)
+
+OPTION(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE)
+IF(PHYSFS_ARCHIVE_WAD)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_WAD=1)
+ENDIF(PHYSFS_ARCHIVE_WAD)
+
+OPTION(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE)
+IF(PHYSFS_ARCHIVE_HOG)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_HOG=1)
+ENDIF(PHYSFS_ARCHIVE_HOG)
+
+OPTION(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE)
+IF(PHYSFS_ARCHIVE_MVL)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_MVL=1)
+ENDIF(PHYSFS_ARCHIVE_MVL)
+
+OPTION(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE)
+IF(PHYSFS_ARCHIVE_QPAK)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_QPAK=1)
+ENDIF(PHYSFS_ARCHIVE_QPAK)
+
+OPTION(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE)
+IF(PHYSFS_ARCHIVE_ISO9660)
+    ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ISO9660=1)
+ENDIF(PHYSFS_ARCHIVE_ISO9660)
+
+
+OPTION(PHYSFS_BUILD_STATIC "Build static library" TRUE)
+IF(PHYSFS_BUILD_STATIC)
+    ADD_LIBRARY(physfs STATIC ${PHYSFS_SRCS})
+    SET_TARGET_PROPERTIES(physfs PROPERTIES OUTPUT_NAME "physfs")
+    SET(PHYSFS_LIB_TARGET physfs)
+    SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
+ENDIF(PHYSFS_BUILD_STATIC)
+
+#OPTION(PHYSFS_BUILD_SHARED "Build shared library" FALSE)
+#IF(PHYSFS_BUILD_SHARED)
+#    ADD_LIBRARY(physfs SHARED ${PHYSFS_SRCS})
+#    SET_TARGET_PROPERTIES(physfs PROPERTIES VERSION ${PHYSFS_VERSION})
+#    SET_TARGET_PROPERTIES(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION})
+#    TARGET_LINK_LIBRARIES(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS})
+#    SET(PHYSFS_LIB_TARGET physfs)
+#    SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs")
+#ENDIF(PHYSFS_BUILD_SHARED)
+
+IF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+    MESSAGE(FATAL "Both shared and static libraries are disabled!")
+ENDIF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC)
+
+# CMake FAQ says I need this...
+IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+    SET_TARGET_PROPERTIES(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+    SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC)
+
+OPTION(PHYSFS_BUILD_TEST "Build stdio test program." FALSE)
+MARK_AS_ADVANCED(PHYSFS_BUILD_TEST)
+IF(PHYSFS_BUILD_TEST)
+    FIND_PATH(READLINE_H readline/readline.h)
+    FIND_PATH(HISTORY_H readline/history.h)
+    IF(READLINE_H AND HISTORY_H)
+        FIND_LIBRARY(CURSES_LIBRARY NAMES curses ncurses)
+        SET(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY})
+        FIND_LIBRARY(READLINE_LIBRARY readline)
+        IF(READLINE_LIBRARY)
+            SET(HAVE_SYSTEM_READLINE TRUE)
+            SET(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY})
+            INCLUDE_DIRECTORIES(${READLINE_H} ${HISTORY_H})
+            ADD_DEFINITIONS(-DPHYSFS_HAVE_READLINE=1)
+        ENDIF(READLINE_LIBRARY)
+    ENDIF(READLINE_H AND HISTORY_H)
+    ADD_EXECUTABLE(test_physfs test/test_physfs.c)
+    TARGET_LINK_LIBRARIES(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS})
+    SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs")
+ENDIF(PHYSFS_BUILD_TEST)
+
+
+# Scripting language bindings...
+
+#CMake's SWIG support is basically useless.
+#FIND_PACKAGE(SWIG)
+
+OPTION(PHYSFS_BUILD_SWIG "Build ${_LANG} bindings." FALSE)
+MARK_AS_ADVANCED(PHYSFS_BUILD_SWIG)
+
+FIND_PROGRAM(SWIG swig DOC "Path to swig command line app: http://swig.org/")
+IF(NOT SWIG)
+    MESSAGE(STATUS "SWIG not found. You won't be able to build scripting language bindings.")
+ELSE(NOT SWIG)
+    MARK_AS_ADVANCED(SWIG)
+    IF(DEFINED CMAKE_BUILD_TYPE)
+        IF((NOT CMAKE_BUILD_TYPE STREQUAL "") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
+            IF(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
+                SET(SWIG_OPT_CFLAGS "-small")
+            ELSE(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
+                SET(SWIG_OPT_CFLAGS "-O")
+            ENDIF(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
+        ENDIF((NOT CMAKE_BUILD_TYPE STREQUAL "") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Debug"))
+    ENDIF(DEFINED CMAKE_BUILD_TYPE)
+
+    SET(SWIG_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/physfs-swig-bindings")
+
+    MACRO(CONFIGURE_SWIG_BINDING _LANG _INSTALLPATH _EXTRAOUTPUTS _EXTRACFLAGS _EXTRALDFLAGS)
+        STRING(TOUPPER "${_LANG}" _UPPERLANG)
+        STRING(TOLOWER "${_LANG}" _LOWERLANG)
+        SET(_TARGET "physfs-${_LOWERLANG}")
+        SET(_TARGETDIR "${SWIG_OUTPUT_DIR}/${_LOWERLANG}")
+
+        IF(NOT EXISTS "${_TARGETDIR}")
+            FILE(MAKE_DIRECTORY "${_TARGETDIR}")
+        ENDIF(NOT EXISTS "${_TARGETDIR}")
+
+        IF(PHYSFS_BUILD_${_UPPERLANG})
+            ADD_CUSTOM_COMMAND(
+                OUTPUT "${_TARGETDIR}/${_TARGET}.c" ${_EXTRAOUTPUTS}
+                MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/extras/physfs-swig.i"
+                COMMAND "${SWIG}"
+                ARGS ${SWIG_OPT_CFLAGS} -${_LOWERLANG} -outdir "${_TARGETDIR}" -o "${_TARGETDIR}/${_TARGET}.c" "${CMAKE_CURRENT_SOURCE_DIR}/extras/physfs-swig.i"
+                COMMENT "Generating ${_LANG} bindings..."
+            )
+
+            ADD_LIBRARY(${_TARGET} SHARED "${_TARGETDIR}/${_TARGET}.c")
+            TARGET_LINK_LIBRARIES(${_TARGET} ${PHYSFS_LIB_TARGET})
+            SET_TARGET_PROPERTIES(${_TARGET} PROPERTIES
+                COMPILE_FLAGS "${_EXTRACFLAGS}"
+                LINK_FLAGS "${_EXTRALDFLAGS}"
+                LIBRARY_OUTPUT_NAME "physfs"
+                LIBRARY_OUTPUT_DIRECTORY "${_TARGETDIR}"
+                CLEAN_DIRECT_OUTPUT 1
+            )
+            INSTALL(TARGETS ${_TARGET} LIBRARY DESTINATION "${_INSTALLPATH}")
+            MESSAGE(STATUS "${_LANG} bindings configured!")
+        ELSE(PHYSFS_BUILD_${_UPPERLANG})
+            MESSAGE(STATUS "Couldn't figure out ${_LANG} configuration. Skipping ${_LANG} bindings.")
+        ENDIF(PHYSFS_BUILD_${_UPPERLANG})
+    ENDMACRO(CONFIGURE_SWIG_BINDING)
+
+    MACRO(ADD_SCRIPT_BINDING_OPTION _VAR _LANG _DEFVAL)
+        SET(BUILDSWIGVAL ${_DEFVAL})
+        IF(NOT PHYSFS_BUILD_SWIG)
+            SET(BUILDSWIGVAL FALSE)
+        ENDIF(NOT PHYSFS_BUILD_SWIG)
+        OPTION(${_VAR} "Build ${_LANG} bindings." ${BUILDSWIGVAL})
+        MARK_AS_ADVANCED(${_VAR})
+    ENDMACRO(ADD_SCRIPT_BINDING_OPTION)
+
+    ADD_SCRIPT_BINDING_OPTION(PHYSFS_BUILD_PERL "Perl" TRUE)
+    ADD_SCRIPT_BINDING_OPTION(PHYSFS_BUILD_RUBY "Ruby" TRUE)
+ENDIF(NOT SWIG)
+
+IF(PHYSFS_BUILD_PERL)
+    MESSAGE(STATUS "Configuring Perl bindings...")
+    FIND_PROGRAM(PERL perl DOC "Path to perl command line app: http://perl.org/")
+    IF(NOT PERL)
+        MESSAGE(STATUS "Perl not found. You won't be able to build perl bindings.")
+        SET(PHYSFS_BUILD_PERL FALSE)
+    ENDIF(NOT PERL)
+    MARK_AS_ADVANCED(PERL)
+
+    MACRO(GET_PERL_CONFIG _KEY _VALUE)
+        IF(PHYSFS_BUILD_PERL)
+            MESSAGE(STATUS "Figuring out perl config value '${_KEY}' ...")
+            EXECUTE_PROCESS(
+                COMMAND ${PERL} -w -e "use Config; print \$Config{${_KEY}};"
+                RESULT_VARIABLE GET_PERL_CONFIG_RC
+                OUTPUT_VARIABLE ${_VALUE}
+            )
+            IF(NOT GET_PERL_CONFIG_RC EQUAL 0)
+                MESSAGE(STATUS "Perl executable ('${PERL}') reported failure: ${GET_PERL_CONFIG_RC}")
+                SET(PHYSFS_BUILD_PERL FALSE)
+            ENDIF(NOT GET_PERL_CONFIG_RC EQUAL 0)
+            IF(NOT ${_VALUE})
+                MESSAGE(STATUS "Perl executable ('${PERL}') didn't have a value for '${_KEY}'")
+                SET(PHYSFS_BUILD_PERL FALSE)
+            ENDIF(NOT ${_VALUE})
+
+            IF(PHYSFS_BUILD_PERL)
+                MESSAGE(STATUS "Perl says: '${${_VALUE}}'.")
+            ENDIF(PHYSFS_BUILD_PERL)
+        ENDIF(PHYSFS_BUILD_PERL)
+    ENDMACRO(GET_PERL_CONFIG)
+
+    # !!! FIXME: installsitearch might be the wrong location.
+    GET_PERL_CONFIG("archlibexp" PERL_INCLUDE_PATH)
+    GET_PERL_CONFIG("ccflags" PERL_CCFLAGS)
+    GET_PERL_CONFIG("ldflags" PERL_LDFLAGS)
+    GET_PERL_CONFIG("installsitearch" PERL_INSTALL_PATH)
+
+    # !!! FIXME: this test for Mac OS X is wrong.
+    IF(MACOSX)
+        GET_PERL_CONFIG("libperl" PERL_LIBPERL)
+        SET(TMPLIBPERL "${PERL_LIBPERL}")
+        STRING(REGEX REPLACE "^lib" "" TMPLIBPERL "${TMPLIBPERL}")
+        STRING(REGEX REPLACE "\\.so$" "" TMPLIBPERL "${TMPLIBPERL}")
+        STRING(REGEX REPLACE "\\.dylib$" "" TMPLIBPERL "${TMPLIBPERL}")
+        STRING(REGEX REPLACE "\\.dll$" "" TMPLIBPERL "${TMPLIBPERL}")
+        IF(NOT "${TMPLIBPERL}" STREQUAL "${PERL_LIBPERL}")
+            MESSAGE(STATUS "Stripped '${PERL_LIBPERL}' down to '${TMPLIBPERL}'.")
+            SET(PERL_LIBPERL "${TMPLIBPERL}")
+        ENDIF(NOT "${TMPLIBPERL}" STREQUAL "${PERL_LIBPERL}")
+        SET(PERL_LIBPERL "-l${PERL_LIBPERL}")
+    ENDIF(MACOSX)
+
+    CONFIGURE_SWIG_BINDING(Perl "${PERL_INSTALL_PATH}" "${SWIG_OUTPUT_DIR}/perl/physfs.pm" "\"-I${PERL_INCLUDE_PATH}/CORE\" ${PERL_CCFLAGS} -w" "\"-L${PERL_INCLUDE_PATH}/CORE\" ${PERL_LIBPERL} ${PERL_LDFLAGS}")
+    INSTALL(FILES "${SWIG_OUTPUT_DIR}/perl/physfs.pm" DESTINATION "${PERL_INSTALL_PATH}")
+    INSTALL(
+        FILES test/test_physfs.pl
+        DESTINATION bin
+        PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
+                    GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+    )
+ENDIF(PHYSFS_BUILD_PERL)
+
+# !!! FIXME: lots of cut-and-paste from perl bindings.
+IF(PHYSFS_BUILD_RUBY)
+    MESSAGE(STATUS "Configuring Ruby bindings...")
+    FIND_PROGRAM(RUBY ruby DOC "Path to ruby command line app: http://ruby-lang.org/")
+    IF(NOT RUBY)
+        MESSAGE(STATUS "Ruby not found. You won't be able to build ruby bindings.")
+        SET(PHYSFS_BUILD_RUBY FALSE)
+    ENDIF(NOT RUBY)
+    MARK_AS_ADVANCED(RUBY)
+
+    MACRO(GET_RUBY_CONFIG _KEY _VALUE)
+        IF(PHYSFS_BUILD_RUBY)
+            MESSAGE(STATUS "Figuring out ruby config value '${_KEY}' ...")
+            EXECUTE_PROCESS(
+                COMMAND ${RUBY} -e "require 'rbconfig'; puts RbConfig::CONFIG['${_KEY}'];"
+                RESULT_VARIABLE GET_RUBY_CONFIG_RC
+                OUTPUT_VARIABLE ${_VALUE}
+                OUTPUT_STRIP_TRAILING_WHITESPACE
+            )
+            IF(NOT GET_RUBY_CONFIG_RC EQUAL 0)
+                MESSAGE(STATUS "Ruby executable ('${RUBY}') reported failure: ${GET_RUBY_CONFIG_RC}")
+                SET(PHYSFS_BUILD_RUBY FALSE)
+            ENDIF(NOT GET_RUBY_CONFIG_RC EQUAL 0)
+            IF(NOT ${_VALUE})
+                MESSAGE(STATUS "Ruby executable ('${RUBY}') didn't have a value for '${_KEY}'")
+                SET(PHYSFS_BUILD_RUBY FALSE)
+            ENDIF(NOT ${_VALUE})
+
+            IF(PHYSFS_BUILD_RUBY)
+                MESSAGE(STATUS "Ruby says: '${${_VALUE}}'.")
+            ENDIF(PHYSFS_BUILD_RUBY)
+        ENDIF(PHYSFS_BUILD_RUBY)
+    ENDMACRO(GET_RUBY_CONFIG)
+
+    GET_RUBY_CONFIG("archdir" RUBY_INCLUDE_PATH)
+    GET_RUBY_CONFIG("CFLAGS" RUBY_CCFLAGS)
+    GET_RUBY_CONFIG("LDFLAGS" RUBY_LDFLAGS)
+    GET_RUBY_CONFIG("sitearchdir" RUBY_INSTALL_PATH)
+    GET_RUBY_CONFIG("LIBRUBYARG_SHARED" RUBY_LIBRUBY)
+    GET_RUBY_CONFIG("libdir" RUBY_LIBDIR)
+
+    CONFIGURE_SWIG_BINDING(Ruby "${RUBY_INSTALL_PATH}" "" "\"-I${RUBY_INCLUDE_PATH}\" ${RUBY_CCFLAGS} -w" "\"-L${RUBY_LIBDIR}\" ${RUBY_LIBRUBY} ${RUBY_LDFLAGS}")
+    SET_TARGET_PROPERTIES(physfs-ruby PROPERTIES PREFIX "")
+    INSTALL(
+        FILES test/test_physfs.rb
+        DESTINATION bin
+        PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
+                    GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+    )
+ENDIF(PHYSFS_BUILD_RUBY)
+
+
+INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS}
+        RUNTIME DESTINATION bin
+        LIBRARY DESTINATION lib${LIB_SUFFIX}
+        ARCHIVE DESTINATION lib${LIB_SUFFIX})
+INSTALL(FILES src/physfs.h DESTINATION include)
+
+IF(UNIX)
+    SET(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz")
+    ADD_CUSTOM_TARGET(
+        dist
+        hg archive -t tgz "${PHYSFS_TARBALL}"
+        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+        COMMENT "Building source tarball '${PHYSFS_TARBALL}'..."
+    )
+#    ADD_CUSTOM_TARGET(
+#        uninstall
+#        "${CMAKE_CURRENT_SOURCE_DIR}/extras/uninstall.sh"
+#        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+#        COMMENT "Uninstall the project..."
+#    )
+ENDIF(UNIX)
+
+MACRO(MESSAGE_BOOL_OPTION _NAME _VALUE)
+    IF(${_VALUE})
+        MESSAGE(STATUS "  ${_NAME}: enabled")
+    ELSE(${_VALUE})
+        MESSAGE(STATUS "  ${_NAME}: disabled")
+    ENDIF(${_VALUE})
+ENDMACRO(MESSAGE_BOOL_OPTION)
+
+MESSAGE(STATUS "PhysicsFS will build with the following options:")
+MESSAGE_BOOL_OPTION("ZIP support" PHYSFS_ARCHIVE_ZIP)
+MESSAGE_BOOL_OPTION("7zip support" PHYSFS_ARCHIVE_7Z)
+MESSAGE_BOOL_OPTION("GRP support" PHYSFS_ARCHIVE_GRP)
+MESSAGE_BOOL_OPTION("WAD support" PHYSFS_ARCHIVE_WAD)
+MESSAGE_BOOL_OPTION("HOG support" PHYSFS_ARCHIVE_HOG)
+MESSAGE_BOOL_OPTION("MVL support" PHYSFS_ARCHIVE_MVL)
+MESSAGE_BOOL_OPTION("QPAK support" PHYSFS_ARCHIVE_QPAK)
+MESSAGE_BOOL_OPTION("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT)
+MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT)
+MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC)
+MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED)
+MESSAGE_BOOL_OPTION("Build Perl bindings" PHYSFS_BUILD_PERL)
+MESSAGE_BOOL_OPTION("Build Ruby bindings" PHYSFS_BUILD_RUBY)
+MESSAGE_BOOL_OPTION("Build stdio test program" PHYSFS_BUILD_TEST)
+IF(PHYSFS_BUILD_TEST)
+    MESSAGE_BOOL_OPTION("  Use readline in test program" HAVE_SYSTEM_READLINE)
+ENDIF(PHYSFS_BUILD_TEST)
+
+# end of CMakeLists.txt ...
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/extras/CMakeLists.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,9 @@
+find_package(SDL REQUIRED)
+
+include_directories(${SDL_INCLUDE_DIR})
+include_directories(${CMAKE_SOURCE_DIR}/misc/liblua)
+include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src)
+
+add_library(physfsrwops STATIC physfsrwops.c physfslualoader.c hwpacksmounter.c)
+
+add_dependencies(physfsrwops lua)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/extras/hwpacksmounter.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,36 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <physfs.h>
+
+#include "hwpacksmounter.h"
+
+void hedgewarsMountPackages()
+{
+    char ** filesList = PHYSFS_enumerateFiles("/");
+    char **i;
+
+    for (i = filesList; *i != NULL; i++)
+    {
+        char * fileName = *i;
+        int fileNameLength = strlen(fileName);
+        if (fileNameLength > 4)
+            if (strcmp(fileName + fileNameLength - 4, ".hwp") == 0)
+            {
+                const char * dir = PHYSFS_getRealDir(fileName);
+                if(dir)
+                {
+                    char * fullPath = (char *)malloc(strlen(dir) + fileNameLength + 2);
+                    strcpy(fullPath, dir);
+                    strcat(fullPath, "/");
+                    strcat(fullPath, fileName);
+
+                    PHYSFS_mount(fullPath, NULL, 1);
+
+                    free(fullPath);
+                }
+            }
+    }
+
+    PHYSFS_freeList(filesList);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/extras/hwpacksmounter.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,15 @@
+#ifndef HEDGEWARS_PACKAGES_MOUNTER_H
+#define HEDGEWARS_PACKAGES_MOUNTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void hedgewarsMountPackages();
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/extras/physfslualoader.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,24 @@
+#include <lua.h>
+#include <physfs.h>
+
+#define BUFSIZE 1024
+
+void * physfsReaderBuffer;
+
+const char * physfsReader(lua_State *L, PHYSFS_File *f, size_t *size)
+{
+
+    if(PHYSFS_eof(f))
+    {
+        return NULL;
+    }
+    else
+    {
+        *size = PHYSFS_readBytes(f, physfsReaderBuffer, BUFSIZE);
+
+        if(*size == 0)
+            return NULL;
+        else
+            return physfsReaderBuffer;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/extras/physfsrwops.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,219 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS.
+ *  You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+/* SDL's RWOPS interface changed a little in SDL 1.3... */
+#if defined(SDL_VERSION_ATLEAST)
+#if SDL_VERSION_ATLEAST(1, 3, 0)
+#define TARGET_SDL13 1
+#endif
+#endif
+
+#if TARGET_SDL13
+static long SDLCALL physfsrwops_seek(struct SDL_RWops *rw, long offset, int whence)
+#else
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+#endif
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    PHYSFS_sint64 pos = 0;
+
+    if (whence == SEEK_SET)
+        pos = (PHYSFS_sint64) offset;
+
+    else if (whence == SEEK_CUR)
+    {
+        const PHYSFS_sint64 current = PHYSFS_tell(handle);
+        if (current == -1)
+        {
+            SDL_SetError("Can't find position in file: %s",
+                          PHYSFS_getLastError());
+            return -1;
+        } /* if */
+
+        if (offset == 0)  /* this is a "tell" call. We're done. */
+        {
+            #if TARGET_SDL13
+            return (long) current;
+            #else
+            return (int) current;
+            #endif
+        } /* if */
+
+        pos = current + ((PHYSFS_sint64) offset);
+    } /* else if */
+
+    else if (whence == SEEK_END)
+    {
+        const PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+        if (len == -1)
+        {
+            SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+            return -1;
+        } /* if */
+
+        pos = len + ((PHYSFS_sint64) offset);
+    } /* else if */
+
+    else
+    {
+        SDL_SetError("Invalid 'whence' parameter.");
+        return -1;
+    } /* else */
+
+    if ( pos < 0 )
+    {
+        SDL_SetError("Attempt to seek past start of file.");
+        return -1;
+    } /* if */
+    
+    if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
+    {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+        return -1;
+    } /* if */
+
+    #if TARGET_SDL13
+    return (long) pos;
+    #else
+    return (int) pos;
+    #endif
+} /* physfsrwops_seek */
+
+
+#if TARGET_SDL13
+static size_t SDLCALL physfsrwops_read(struct SDL_RWops *rw, void *ptr,
+                                       size_t size, size_t maxnum)
+#else
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+#endif
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    const PHYSFS_uint64 readlen = (PHYSFS_uint64) (maxnum * size);
+    const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen);
+    if (rc != ((PHYSFS_sint64) readlen))
+    {
+        if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+            SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    } /* if */
+
+    #if TARGET_SDL13
+    return (size_t) rc;
+    #else
+    return (int) rc;
+    #endif
+} /* physfsrwops_read */
+
+
+#if TARGET_SDL13
+static size_t SDLCALL physfsrwops_write(struct SDL_RWops *rw, const void *ptr,
+                                        size_t size, size_t num)
+#else
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+#endif
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size);
+    const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen);
+    if (rc != ((PHYSFS_sint64) writelen))
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+    #if TARGET_SDL13
+    return (size_t) rc;
+    #else
+    return (int) rc;
+    #endif
+} /* physfsrwops_write */
+
+
+static int physfsrwops_close(SDL_RWops *rw)
+{
+    PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1;
+    if (!PHYSFS_close(handle))
+    {
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+        return -1;
+    } /* if */
+
+    SDL_FreeRW(rw);
+    return 0;
+} /* physfsrwops_close */
+
+
+static SDL_RWops *create_rwops(PHYSFS_File *handle)
+{
+    SDL_RWops *retval = NULL;
+
+    if (handle == NULL)
+        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+    else
+    {
+        retval = SDL_AllocRW();
+        if (retval != NULL)
+        {
+            retval->seek  = physfsrwops_seek;
+            retval->read  = physfsrwops_read;
+            retval->write = physfsrwops_write;
+            retval->close = physfsrwops_close;
+            retval->hidden.unknown.data1 = handle;
+        } /* if */
+    } /* else */
+
+    return retval;
+} /* create_rwops */
+
+
+SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle)
+{
+    SDL_RWops *retval = NULL;
+    if (handle == NULL)
+        SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
+    else
+        retval = create_rwops(handle);
+
+    return retval;
+} /* PHYSFSRWOPS_makeRWops */
+
+
+SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
+{
+    return create_rwops(PHYSFS_openRead(fname));
+} /* PHYSFSRWOPS_openRead */
+
+
+SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
+{
+    return create_rwops(PHYSFS_openWrite(fname));
+} /* PHYSFSRWOPS_openWrite */
+
+
+SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
+{
+    return create_rwops(PHYSFS_openAppend(fname));
+} /* PHYSFSRWOPS_openAppend */
+
+
+/* end of physfsrwops.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/extras/physfsrwops.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,88 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ *  Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ *  correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ *  verbatim into a closed-source project, exploiting it commercially, and
+ *  removing any trace of my name from the source (although I hope you won't
+ *  do that). I welcome enhancements and corrections to this file, but I do
+ *  not require you to send me patches if you make changes. This code has
+ *  NO WARRANTY.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
+ *  Please see LICENSE.txt in the root of the source tree.
+ *
+ * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
+ *
+ *  This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
+
+/**
+ * Open a platform-independent filename for writing, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
+
+/**
+ * Open a platform-independent filename for appending, and make it accessible
+ *  via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ *  RWops is closed. PhysicsFS should be configured to your liking before
+ *  opening files through this method.
+ *
+ *   @param filename File to open in platform-independent notation.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
+
+/**
+ * Make a SDL_RWops from an existing PhysicsFS file handle. You should
+ *  dispose of any references to the handle after successful creation of
+ *  the RWops. The actual PhysicsFS handle will be destroyed when the
+ *  RWops is closed.
+ *
+ *   @param handle a valid PhysicsFS file handle.
+ *  @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_dir.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,201 @@
+/*
+ * Standard directory I/O support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+/* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */
+
+
+
+static char *cvtToDependent(const char *prepend, const char *path, char *buf)
+{
+    BAIL_IF_MACRO(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    sprintf(buf, "%s%s", prepend ? prepend : "", path);
+
+    if (__PHYSFS_platformDirSeparator != '/')
+    {
+        char *p;
+        for (p = strchr(buf, '/'); p != NULL; p = strchr(p + 1, '/'))
+            *p = __PHYSFS_platformDirSeparator;
+    } /* if */
+
+    return buf;
+} /* cvtToDependent */
+
+
+#define CVT_TO_DEPENDENT(buf, pre, dir) { \
+    const size_t len = ((pre) ? strlen((char *) pre) : 0) + strlen(dir) + 1; \
+    buf = cvtToDependent((char*)pre,dir,(char*)__PHYSFS_smallAlloc(len)); \
+}
+
+
+
+static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    PHYSFS_Stat st;
+    const char dirsep = __PHYSFS_platformDirSeparator;
+    char *retval = NULL;
+    const size_t namelen = strlen(name);
+    const size_t seplen = 1;
+    int exists = 0;
+
+    assert(io == NULL);  /* shouldn't create an Io for these. */
+    BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &exists, &st), ERRPASS, NULL);
+    if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
+        BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+    retval = allocator.Malloc(namelen + seplen + 1);
+    BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    strcpy(retval, name);
+
+    /* make sure there's a dir separator at the end of the string */
+    if (retval[namelen - 1] != dirsep)
+    {
+        retval[namelen] = dirsep;
+        retval[namelen + 1] = '\0';
+    } /* if */
+
+    return retval;
+} /* DIR_openArchive */
+
+
+static void DIR_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    char *d;
+
+    CVT_TO_DEPENDENT(d, opaque, dname);
+    if (d != NULL)
+    {
+        __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb,
+                                        origdir, callbackdata);
+        __PHYSFS_smallFree(d);
+    } /* if */
+} /* DIR_enumerateFiles */
+
+
+static PHYSFS_Io *doOpen(PHYSFS_Dir *opaque, const char *name,
+                         const int mode, int *fileExists)
+{
+    char *f;
+    PHYSFS_Io *io = NULL;
+    int existtmp = 0;
+
+    CVT_TO_DEPENDENT(f, opaque, name);
+    BAIL_IF_MACRO(!f, ERRPASS, NULL);
+
+    if (fileExists == NULL)
+        fileExists = &existtmp;
+
+    io = __PHYSFS_createNativeIo(f, mode);
+    if (io == NULL)
+    {
+        const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
+        PHYSFS_Stat statbuf;
+        __PHYSFS_platformStat(f, fileExists, &statbuf);
+        __PHYSFS_setError(err);
+    } /* if */
+    else
+    {
+        *fileExists = 1;
+    } /* else */
+
+    __PHYSFS_smallFree(f);
+
+    return io;
+} /* doOpen */
+
+
+static PHYSFS_Io *DIR_openRead(PHYSFS_Dir *opaque, const char *fnm, int *exist)
+{
+    return doOpen(opaque, fnm, 'r', exist);
+} /* DIR_openRead */
+
+
+static PHYSFS_Io *DIR_openWrite(PHYSFS_Dir *opaque, const char *filename)
+{
+    return doOpen(opaque, filename, 'w', NULL);
+} /* DIR_openWrite */
+
+
+static PHYSFS_Io *DIR_openAppend(PHYSFS_Dir *opaque, const char *filename)
+{
+    return doOpen(opaque, filename, 'a', NULL);
+} /* DIR_openAppend */
+
+
+static int DIR_remove(PHYSFS_Dir *opaque, const char *name)
+{
+    int retval;
+    char *f;
+
+    CVT_TO_DEPENDENT(f, opaque, name);
+    BAIL_IF_MACRO(!f, ERRPASS, 0);
+    retval = __PHYSFS_platformDelete(f);
+    __PHYSFS_smallFree(f);
+    return retval;
+} /* DIR_remove */
+
+
+static int DIR_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+    int retval;
+    char *f;
+
+    CVT_TO_DEPENDENT(f, opaque, name);
+    BAIL_IF_MACRO(!f, ERRPASS, 0);
+    retval = __PHYSFS_platformMkDir(f);
+    __PHYSFS_smallFree(f);
+    return retval;
+} /* DIR_mkdir */
+
+
+static void DIR_closeArchive(PHYSFS_Dir *opaque)
+{
+    allocator.Free(opaque);
+} /* DIR_closeArchive */
+
+
+static int DIR_stat(PHYSFS_Dir *opaque, const char *name,
+                    int *exists, PHYSFS_Stat *stat)
+{
+    int retval = 0;
+    char *d;
+
+    CVT_TO_DEPENDENT(d, opaque, name);
+    BAIL_IF_MACRO(!d, ERRPASS, 0);
+    retval = __PHYSFS_platformStat(d, exists, stat);
+    __PHYSFS_smallFree(d);
+    return retval;
+} /* DIR_stat */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
+{
+    {
+        "",
+        "Non-archive, direct filesystem I/O",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://icculus.org/physfs/",
+    },
+    DIR_openArchive,        /* openArchive() method    */
+    DIR_enumerateFiles,     /* enumerateFiles() method */
+    DIR_openRead,           /* openRead() method       */
+    DIR_openWrite,          /* openWrite() method      */
+    DIR_openAppend,         /* openAppend() method     */
+    DIR_remove,             /* remove() method         */
+    DIR_mkdir,              /* mkdir() method          */
+    DIR_closeArchive,       /* closeArchive() method   */
+    DIR_stat                /* stat() method           */
+};
+
+/* end of dir.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_grp.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,110 @@
+/*
+ * GRP support routines for PhysicsFS.
+ *
+ * This driver handles BUILD engine archives ("groupfiles"). This format
+ *  (but not this driver) was put together by Ken Silverman.
+ *
+ * The format is simple enough. In Ken's words:
+ *
+ *    What's the .GRP file format?
+ *
+ *     The ".grp" file format is just a collection of a lot of files stored
+ *     into 1 big one. I tried to make the format as simple as possible: The
+ *     first 12 bytes contains my name, "KenSilverman". The next 4 bytes is
+ *     the number of files that were compacted into the group file. Then for
+ *     each file, there is a 16 byte structure, where the first 12 bytes are
+ *     the filename, and the last 4 bytes are the file's size. The rest of
+ *     the group file is just the raw data packed one after the other in the
+ *     same order as the list of files.
+ *
+ * (That info is from http://www.advsys.net/ken/build.htm ...)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_GRP
+
+static UNPKentry *grpLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+    PHYSFS_uint32 location = 16;  /* sizeof sig. */
+    UNPKentry *entries = NULL;
+    UNPKentry *entry = NULL;
+    char *ptr = NULL;
+
+    entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+    BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    location += (16 * fileCount);
+
+    for (entry = entries; fileCount > 0; fileCount--, entry++)
+    {
+        GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 12), ERRPASS, failed);
+        GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed);
+        entry->name[12] = '\0';  /* name isn't null-terminated in file. */
+        if ((ptr = strchr(entry->name, ' ')) != NULL)
+            *ptr = '\0';  /* trim extra spaces. */
+
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = location;
+        location += entry->size;
+    } /* for */
+
+    return entries;
+
+failed:
+    allocator.Free(entries);
+    return NULL;
+} /* grpLoadEntries */
+
+
+static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    PHYSFS_uint8 buf[12];
+    PHYSFS_uint32 count = 0;
+    UNPKentry *entries = NULL;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
+    if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
+        BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
+    count = PHYSFS_swapULE32(count);
+
+    entries = grpLoadEntries(io, count);
+    BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+    return UNPK_openArchive(io, entries, count);
+} /* GRP_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
+{
+    {
+        "GRP",
+        "Build engine Groupfile format",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://icculus.org/physfs/",
+    },
+    GRP_openArchive,        /* openArchive() method    */
+    UNPK_enumerateFiles,    /* enumerateFiles() method */
+    UNPK_openRead,          /* openRead() method       */
+    UNPK_openWrite,         /* openWrite() method      */
+    UNPK_openAppend,        /* openAppend() method     */
+    UNPK_remove,            /* remove() method         */
+    UNPK_mkdir,             /* mkdir() method          */
+    UNPK_closeArchive,      /* closeArchive() method   */
+    UNPK_stat               /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_GRP */
+
+/* end of grp.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_hog.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,116 @@
+/*
+ * HOG support routines for PhysicsFS.
+ *
+ * This driver handles Descent I/II HOG archives.
+ *
+ * The format is very simple:
+ *
+ *   The file always starts with the 3-byte signature "DHF" (Descent
+ *   HOG file). After that the files of a HOG are just attached after
+ *   another, divided by a 17 bytes header, which specifies the name
+ *   and length (in bytes) of the forthcoming file! So you just read
+ *   the header with its information of how big the following file is,
+ *   and then skip exact that number of bytes to get to the next file
+ *   in that HOG.
+ *
+ *    char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File
+ *
+ *    struct {
+ *     char file_name[13]; // Filename, padded to 13 bytes with 0s
+ *     int file_size; // filesize in bytes
+ *     char data[file_size]; // The file data
+ *    } FILE_STRUCT; // Repeated until the end of the file.
+ *
+ * (That info is from http://www.descent2.com/ddn/specs/hog/)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Bradley Bell.
+ *  Based on grp.c by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_HOG
+
+static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount)
+{
+    const PHYSFS_uint64 iolen = io->length(io);
+    PHYSFS_uint32 entCount = 0;
+    void *ptr = NULL;
+    UNPKentry *entries = NULL;
+    UNPKentry *entry = NULL;
+    PHYSFS_uint32 size = 0;
+    PHYSFS_uint32 pos = 3;
+
+    while (pos < iolen)
+    {
+        entCount++;
+        ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount);
+        GOTO_IF_MACRO(ptr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+        entries = (UNPKentry *) ptr;
+        entry = &entries[entCount-1];
+
+        GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 13), ERRPASS, failed);
+        pos += 13;
+        GOTO_IF_MACRO(!__PHYSFS_readAll(io, &size, 4), ERRPASS, failed);
+        pos += 4;
+
+        entry->size = PHYSFS_swapULE32(size);
+        entry->startPos = pos;
+        pos += size;
+
+        /* skip over entry */
+        GOTO_IF_MACRO(!io->seek(io, pos), ERRPASS, failed);
+    } /* while */
+
+    *_entCount = entCount;
+    return entries;
+
+failed:
+    allocator.Free(entries);
+    return NULL;
+} /* hogLoadEntries */
+
+
+static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    PHYSFS_uint8 buf[3];
+    PHYSFS_uint32 count = 0;
+    UNPKentry *entries = NULL;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 3), ERRPASS, NULL);
+    BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
+
+    entries = hogLoadEntries(io, &count);
+    BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+    return UNPK_openArchive(io, entries, count);
+} /* HOG_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
+{
+    {
+        "HOG",
+        "Descent I/II HOG file format",
+        "Bradley Bell <btb@icculus.org>",
+        "http://icculus.org/physfs/",
+    },
+    HOG_openArchive,         /* openArchive() method    */
+    UNPK_enumerateFiles,     /* enumerateFiles() method */
+    UNPK_openRead,           /* openRead() method       */
+    UNPK_openWrite,          /* openWrite() method      */
+    UNPK_openAppend,         /* openAppend() method     */
+    UNPK_remove,             /* remove() method         */
+    UNPK_mkdir,              /* mkdir() method          */
+    UNPK_closeArchive,       /* closeArchive() method   */
+    UNPK_stat                /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_HOG */
+
+/* end of hog.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_iso9660.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,969 @@
+/*
+ * ISO9660 support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Christoph Nelles.
+ */
+
+/* !!! FIXME: this file needs Ryanification. */
+
+/*
+ * Handles CD-ROM disk images (and raw CD-ROM devices).
+ *
+ * Not supported:
+ * - RockRidge
+ * - Non 2048 Sectors
+ * - UDF
+ *
+ * Deviations from the standard
+ * - Ignores mandatory sort order
+ * - Allows various invalid file names
+ *
+ * Problems
+ * - Ambiguities in the standard
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_ISO9660
+
+#include <time.h>
+
+/* cache files smaller than this completely in memory */
+#define ISO9660_FULLCACHEMAXSIZE 2048
+
+/* !!! FIXME: this is going to cause trouble. */
+#pragma pack(push)  /* push current alignment to stack */
+#pragma pack(1)     /* set alignment to 1 byte boundary */
+
+/* This is the format as defined by the standard
+typedef struct
+{
+    PHYSFS_uint32 lsb;
+    PHYSFS_uint32 msb;
+} ISOBB32bit; // 32byte Both Byte type, means the value first in LSB then in MSB
+
+typedef struct
+{
+    PHYSFS_uint16 lsb;
+    PHYSFS_uint16 msb;
+} ISOBB16bit; // 16byte Both Byte type, means the value first in LSB then in MSB
+*/
+
+/* define better ones to simplify coding (less if's) */
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+#define ISOBB32bit(name) PHYSFS_uint32 name; PHYSFS_uint32 __dummy_##name;
+#define ISOBB16bit(name) PHYSFS_uint16 name; PHYSFS_uint16 __dummy_##name;
+#else
+#define ISOBB32bit(name) PHYSFS_uint32 __dummy_##name; PHYSFS_uint32 name;
+#define ISOBB16bit(name) PHYSFS_uint16 __dummy_##name; PHYSFS_uint16 name;
+#endif
+
+typedef struct
+{
+    char year[4];
+    char month[2];
+    char day[2];
+    char hour[2];
+    char minute[2];
+    char second[2];
+    char centisec[2];
+    PHYSFS_sint8 offset; /* in 15min from GMT */
+} ISO9660VolumeTimestamp;
+
+typedef struct
+{
+    PHYSFS_uint8 year;
+    PHYSFS_uint8 month;
+    PHYSFS_uint8 day;
+    PHYSFS_uint8 hour;
+    PHYSFS_uint8 minute;
+    PHYSFS_uint8 second;
+    PHYSFS_sint8 offset;
+} ISO9660FileTimestamp;
+
+typedef struct
+{
+  unsigned existence:1;
+  unsigned directory:1;
+  unsigned associated_file:1;
+  unsigned record:1;
+  unsigned protection:1;
+  unsigned reserved:2;
+  unsigned multiextent:1;
+} ISO9660FileFlags;
+
+typedef struct
+{
+    PHYSFS_uint8 length;
+    PHYSFS_uint8 attribute_length;
+    ISOBB32bit(extent_location)
+    ISOBB32bit(data_length)
+    ISO9660FileTimestamp timestamp;
+    ISO9660FileFlags file_flags;
+    PHYSFS_uint8 file_unit_size;
+    PHYSFS_uint8 gap_size;
+    ISOBB16bit(vol_seq_no)
+    PHYSFS_uint8 len_fi;
+    char unused;
+} ISO9660RootDirectoryRecord;
+
+/* this structure is combined for all Volume descriptor types */
+typedef struct
+{
+    PHYSFS_uint8 type;
+    char identifier[5];
+    PHYSFS_uint8 version;
+    PHYSFS_uint8 flags;
+    char system_identifier[32];
+    char volume_identifier[32];
+    char unused2[8];
+    ISOBB32bit(space_size)
+    PHYSFS_uint8 escape_sequences[32];
+    ISOBB16bit(vol_set_size)
+    ISOBB16bit(vol_seq_no)
+    ISOBB16bit(block_size)
+    ISOBB32bit(path_table_size)
+/*    PHYSFS_uint32 path_table_start_lsb; // why didn't they use both byte type?
+    PHYSFS_uint32 opt_path_table_start_lsb;
+    PHYSFS_uint32 path_table_start_msb;
+    PHYSFS_uint32 opt_path_table_start_msb;*/
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+    PHYSFS_uint32 path_table_start;
+    PHYSFS_uint32 opt_path_table_start;
+    PHYSFS_uint32 unused6;
+    PHYSFS_uint32 unused7;
+#else
+    PHYSFS_uint32 unused6;
+    PHYSFS_uint32 unused7;
+    PHYSFS_uint32 path_table_start;
+    PHYSFS_uint32 opt_path_table_start;
+#endif
+    ISO9660RootDirectoryRecord rootdirectory;
+    char set_identifier[128];
+    char publisher_identifier[128];
+    char preparer_identifer[128];
+    char application_identifier[128];
+    char copyright_file_identifier[37];
+    char abstract_file_identifier[37];
+    char bibliographic_file_identifier[37];
+    ISO9660VolumeTimestamp creation_timestamp;
+    ISO9660VolumeTimestamp modification_timestamp;
+    ISO9660VolumeTimestamp expiration_timestamp;
+    ISO9660VolumeTimestamp effective_timestamp;
+    PHYSFS_uint8 file_structure_version;
+    char unused4;
+    char application_use[512];
+    char unused5[653];
+} ISO9660VolumeDescriptor;
+
+typedef struct
+{
+    PHYSFS_uint8 recordlen;
+    PHYSFS_uint8 extattributelen;
+    ISOBB32bit(extentpos)
+    ISOBB32bit(datalen)
+    ISO9660FileTimestamp recordtime;
+    ISO9660FileFlags flags;
+    PHYSFS_uint8 file_unit_size;
+    PHYSFS_uint8 interleave_gap;
+    ISOBB16bit(volseqno)
+    PHYSFS_uint8 filenamelen;
+    char filename[222]; /* This is not exact, but makes reading easier */
+} ISO9660FileDescriptor;
+
+typedef struct
+{
+    ISOBB16bit(owner)
+    ISOBB16bit(group)
+    PHYSFS_uint16 flags; /* not implemented*/
+    ISO9660VolumeTimestamp create_time; /* yes, not file timestamp */
+    ISO9660VolumeTimestamp mod_time;
+    ISO9660VolumeTimestamp expire_time;
+    ISO9660VolumeTimestamp effective_time;
+    PHYSFS_uint8 record_format;
+    PHYSFS_uint8 record_attributes;
+    ISOBB16bit(record_len)
+    char system_identifier[32];
+    char system_use[64];
+    PHYSFS_uint8 version;
+    ISOBB16bit(escape_len)
+    char reserved[64];
+    /** further fields not implemented */
+} ISO9660ExtAttributeRec;
+
+#pragma pack(pop)   /* restore original alignment from stack */
+
+typedef struct
+{
+    PHYSFS_Io *io;
+    PHYSFS_uint32 rootdirstart;
+    PHYSFS_uint32 rootdirsize;
+    PHYSFS_uint64 currpos;
+    int isjoliet;
+    char *path;
+    void *mutex;
+} ISO9660Handle;
+
+
+typedef struct __ISO9660FileHandle
+{
+    PHYSFS_sint64 filesize;
+    PHYSFS_uint64 currpos;
+    PHYSFS_uint64 startblock;
+    ISO9660Handle *isohandle;
+    PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer,
+            PHYSFS_uint64 len);
+    int (*seek)(struct __ISO9660FileHandle *filehandle,  PHYSFS_sint64 offset);
+    void (*close)(struct __ISO9660FileHandle *filehandle);
+    /* !!! FIXME: anonymouse union is going to cause problems. */
+    union
+    {
+        /* !!! FIXME: just use a memory PHYSFS_Io here, unify all this code. */
+        char *cacheddata; /* data of file when cached */
+        PHYSFS_Io *io; /* handle to separate opened file */
+    };
+} ISO9660FileHandle;
+
+/*******************************************************************************
+ * Time conversion functions
+ ******************************************************************************/
+
+static PHYSFS_sint64 iso_mktime(ISO9660FileTimestamp *timestamp)
+{
+    struct tm tm;
+    tm.tm_year = timestamp->year;
+    tm.tm_mon = timestamp->month - 1;
+    tm.tm_mday = timestamp->day;
+    tm.tm_hour = timestamp->hour;
+    tm.tm_min = timestamp->minute;
+    tm.tm_sec = timestamp->second;
+    /* Ignore GMT offset for now... */
+    return mktime(&tm);
+} /* iso_mktime */
+
+static int iso_atoi2(char *text)
+{
+    return ((text[0] - 40) * 10) + (text[1] - 40);
+} /* iso_atoi2 */
+
+static int iso_atoi4(char *text)
+{
+    return ((text[0] - 40) * 1000) + ((text[1] - 40) * 100) +
+           ((text[2] - 40) * 10) + (text[3] - 40);
+} /* iso_atoi4 */
+
+static PHYSFS_sint64 iso_volume_mktime(ISO9660VolumeTimestamp *timestamp)
+{
+    struct tm tm;
+    tm.tm_year = iso_atoi4(timestamp->year);
+    tm.tm_mon = iso_atoi2(timestamp->month) - 1;
+    tm.tm_mday = iso_atoi2(timestamp->day);
+    tm.tm_hour = iso_atoi2(timestamp->hour);
+    tm.tm_min = iso_atoi2(timestamp->minute);
+    tm.tm_sec = iso_atoi2(timestamp->second);
+    /* this allows values outside the range of a unix timestamp... sanitize them */
+    PHYSFS_sint64 value = mktime(&tm);
+    return value == -1 ? 0 : value;
+} /* iso_volume_mktime */
+
+/*******************************************************************************
+ * Filename extraction
+ ******************************************************************************/
+
+static int iso_extractfilenameISO(ISO9660FileDescriptor *descriptor,
+        char *filename, int *version)
+{
+    *filename = '\0';
+    if (descriptor->flags.directory)
+    {
+        strncpy(filename, descriptor->filename, descriptor->filenamelen);
+        filename[descriptor->filenamelen] = '\0';
+        *version = 0;
+    } /* if */
+    else
+    {
+        /* find last SEPARATOR2 */
+        int pos = 0;
+        int lastfound = -1;
+        for(;pos < descriptor->filenamelen; pos++)
+            if (descriptor->filename[pos] == ';')
+                lastfound = pos;
+        BAIL_IF_MACRO(lastfound < 1, PHYSFS_ERR_NO_SUCH_PATH /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1);
+        BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NO_SUCH_PATH /* !!! PHYSFS_ERR_BAD_FILENAME */, -1);
+        strncpy(filename, descriptor->filename, lastfound);
+        if (filename[lastfound - 1] == '.')
+            filename[lastfound - 1] = '\0'; /* consume trailing ., as done in all implementations */
+        else
+            filename[lastfound] = '\0';
+        *version = atoi(descriptor->filename + lastfound);
+    } /* else */
+
+    return 0;
+} /* iso_extractfilenameISO */
+
+
+static int iso_extractfilenameUCS2(ISO9660FileDescriptor *descriptor,
+        char *filename, int *version)
+{
+    PHYSFS_uint16 tmp[128];
+    PHYSFS_uint16 *src;
+    int len;
+
+    *filename = '\0';
+    *version = 1; /* Joliet does not have versions.. at least not on my images */
+
+    src = (PHYSFS_uint16*) descriptor->filename;
+    len = descriptor->filenamelen / 2;
+    tmp[len] = 0;
+
+    while(len--)
+        tmp[len] = PHYSFS_swapUBE16(src[len]);
+
+    PHYSFS_utf8FromUcs2(tmp, filename, 255);
+
+    return 0;
+} /* iso_extractfilenameUCS2 */
+
+
+static int iso_extractfilename(ISO9660Handle *handle,
+        ISO9660FileDescriptor *descriptor, char *filename,int *version)
+{
+    if (handle->isjoliet)
+        return iso_extractfilenameUCS2(descriptor, filename, version);
+    else
+        return iso_extractfilenameISO(descriptor, filename, version);
+} /* iso_extractfilename */
+
+/*******************************************************************************
+ * Basic image read functions
+ ******************************************************************************/
+
+static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where,
+                         void *buffer, PHYSFS_uint64 len)
+{
+    BAIL_IF_MACRO(!__PHYSFS_platformGrabMutex(handle->mutex), ERRPASS, -1);
+    int rc = -1;
+    if (where != handle->currpos)
+        GOTO_IF_MACRO(!handle->io->seek(handle->io,where), ERRPASS, unlockme);
+    rc = handle->io->read(handle->io, buffer, len);
+    if (rc == -1)
+    {
+        handle->currpos = (PHYSFS_uint64) -1;
+        goto unlockme;
+    } /* if */
+    handle->currpos += rc;
+
+    unlockme:
+    __PHYSFS_platformReleaseMutex(handle->mutex);
+    return rc;
+} /* iso_readimage */
+
+
+static PHYSFS_sint64 iso_readfiledescriptor(ISO9660Handle *handle,
+                                            PHYSFS_uint64 where,
+                                            ISO9660FileDescriptor *descriptor)
+{
+    PHYSFS_sint64 rc = iso_readimage(handle, where, descriptor,
+                                     sizeof (descriptor->recordlen));
+    BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
+    BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1);
+
+    if (descriptor->recordlen == 0)
+        return 0; /* fill bytes at the end of a sector */
+
+    rc = iso_readimage(handle, where + 1, &descriptor->extattributelen,
+            descriptor->recordlen - sizeof(descriptor->recordlen));
+    BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
+    BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1);
+
+    return 0;
+} /* iso_readfiledescriptor */
+
+static void iso_extractsubpath(char *path, char **subpath)
+{
+    *subpath = strchr(path,'/');
+    if (*subpath != 0)
+    {
+        **subpath = 0;
+        *subpath +=1;
+    } /* if */
+} /* iso_extractsubpath */
+
+/*
+ * Don't use path tables, they are not necessarily faster, but more complicated
+ * to implement as they store only directories and not files, so searching for
+ * a file needs to branch to the directory extent sooner or later.
+ */
+static int iso_find_dir_entry(ISO9660Handle *handle,const char *path,
+                              ISO9660FileDescriptor *descriptor, int *exists)
+{
+    char *subpath = 0;
+    PHYSFS_uint64 readpos, end_of_dir;
+    char filename[255];
+    char pathcopy[256];
+    char *mypath;
+    int version = 0;
+
+    strcpy(pathcopy, path);
+    mypath = pathcopy;
+    *exists = 0;
+
+    readpos = handle->rootdirstart;
+    end_of_dir = handle->rootdirstart + handle->rootdirsize;
+    iso_extractsubpath(mypath, &subpath);
+    while (1)
+    {
+        BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, descriptor), ERRPASS, -1);
+
+        /* recordlen = 0 -> no more entries or fill entry */
+        if (!descriptor->recordlen)
+        {
+            /* if we are in the last sector of the directory & it's 0 -> end */
+            if ((end_of_dir - 2048) <= (readpos -1))
+                break; /* finished */
+
+            /* else skip to the next sector & continue; */
+            readpos = (((readpos - 1) / 2048) + 1) * 2048;
+            continue;
+        } /* if */
+
+        readpos += descriptor->recordlen;
+        if (descriptor->filenamelen == 1 && (descriptor->filename[0] == 0
+                || descriptor->filename[0] == 1))
+            continue; /* special ones, ignore */
+
+        BAIL_IF_MACRO(
+            iso_extractfilename(handle, descriptor, filename, &version),
+            ERRPASS, -1);
+
+        if (strcmp(filename, mypath) == 0)
+        {
+            if ( (subpath == 0) || (subpath[0] == 0) )
+            {
+                *exists = 1;
+                return 0;  /* no subpaths left and we found the entry */
+            } /* if */
+
+            if (descriptor->flags.directory)
+            {
+                /* shorten the path to the subpath */
+                mypath = subpath;
+                iso_extractsubpath(mypath, &subpath);
+                /* gosub to the new directory extent */
+                readpos = descriptor->extentpos * 2048;
+                end_of_dir = readpos + descriptor->datalen;
+            } /* if */
+            else
+            {
+                /* we're at a file but have a remaining subpath -> no match */
+                return 0;
+            } /* else */
+        } /* if */
+    } /* while */
+
+    return 0;
+} /* iso_find_dir_entry */
+
+
+static int iso_read_ext_attributes(ISO9660Handle *handle, int block,
+                                   ISO9660ExtAttributeRec *attributes)
+{
+    return iso_readimage(handle, block * 2048, attributes,
+                         sizeof(ISO9660ExtAttributeRec));
+} /* iso_read_ext_attributes */
+
+
+static int ISO9660_flush(PHYSFS_Io *io) { return 1;  /* no write support. */ }
+
+static PHYSFS_Io *ISO9660_duplicate(PHYSFS_Io *_io)
+{
+    BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);  /* !!! FIXME: write me. */
+} /* ISO9660_duplicate */
+
+
+static void ISO9660_destroy(PHYSFS_Io *io)
+{
+    ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
+    fhandle->close(fhandle);
+    allocator.Free(io);
+} /* ISO9660_destroy */
+
+
+static PHYSFS_sint64 ISO9660_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+    ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
+    return fhandle->read(fhandle, buf, len);
+} /* ISO9660_read */
+
+
+static PHYSFS_sint64 ISO9660_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 l)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* ISO9660_write */
+
+
+static PHYSFS_sint64 ISO9660_tell(PHYSFS_Io *io)
+{
+    return ((ISO9660FileHandle*) io->opaque)->currpos;
+} /* ISO9660_tell */
+
+
+static int ISO9660_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+    ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque;
+    return fhandle->seek(fhandle, offset);
+} /* ISO9660_seek */
+
+
+static PHYSFS_sint64 ISO9660_length(PHYSFS_Io *io)
+{
+    return ((ISO9660FileHandle*) io->opaque)->filesize;
+} /* ISO9660_length */
+
+
+static const PHYSFS_Io ISO9660_Io =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    ISO9660_read,
+    ISO9660_write,
+    ISO9660_seek,
+    ISO9660_tell,
+    ISO9660_length,
+    ISO9660_duplicate,
+    ISO9660_flush,
+    ISO9660_destroy
+};
+
+
+/*******************************************************************************
+ * Archive management functions
+ ******************************************************************************/
+
+static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting)
+{
+    char magicnumber[6];
+    ISO9660Handle *handle;
+    int founddescriptor = 0;
+    int foundjoliet = 0;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+    /* Skip system area to magic number in Volume descriptor */
+    BAIL_IF_MACRO(!io->seek(io, 32769), ERRPASS, NULL);
+    BAIL_IF_MACRO(!io->read(io, magicnumber, 5) != 5, ERRPASS, NULL);
+    if (memcmp(magicnumber, "CD001", 6) != 0)
+        BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+    handle = allocator.Malloc(sizeof(ISO9660Handle));
+    GOTO_IF_MACRO(!handle, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup);
+    handle->path = 0;
+    handle->mutex= 0;
+    handle->io = NULL;
+
+    handle->path = allocator.Malloc(strlen(filename) + 1);
+    GOTO_IF_MACRO(!handle->path, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup);
+    strcpy(handle->path, filename);
+
+    handle->mutex = __PHYSFS_platformCreateMutex();
+    GOTO_IF_MACRO(!handle->mutex, ERRPASS, errorcleanup);
+
+    handle->io = io;
+
+    /* seek Primary Volume Descriptor */
+    GOTO_IF_MACRO(!io->seek(io, 32768), PHYSFS_ERR_IO, errorcleanup);
+
+    while (1)
+    {
+        ISO9660VolumeDescriptor descriptor;
+        GOTO_IF_MACRO(io->read(io, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), PHYSFS_ERR_IO, errorcleanup);
+        GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, PHYSFS_ERR_UNSUPPORTED, errorcleanup);
+
+        if (descriptor.type == 255)
+        {
+            /* type 255 terminates the volume descriptor list */
+            if (founddescriptor)
+                return handle; /* ok, we've found one volume descriptor */
+            else
+                GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup);
+        } /* if */
+        if (descriptor.type == 1 && !founddescriptor)
+        {
+            handle->currpos = io->tell(io);
+            handle->rootdirstart =
+                    descriptor.rootdirectory.extent_location * 2048;
+            handle->rootdirsize =
+                    descriptor.rootdirectory.data_length;
+            handle->isjoliet = 0;
+            founddescriptor = 1; /* continue search for joliet */
+        } /* if */
+        if (descriptor.type == 2 && !foundjoliet)
+        {
+            /* check if is joliet */
+            PHYSFS_uint8 *s = descriptor.escape_sequences;
+            int joliet = !(descriptor.flags & 1)
+                    && (s[0] == 0x25)
+                    && (s[1] == 0x2F)
+                    && ((s[2] == 0x40) || (s[2] == 0x43) || (s[2] == 0x45));
+            if (!joliet)
+                continue;
+
+            handle->currpos = io->tell(io);
+            handle->rootdirstart =
+                    descriptor.rootdirectory.extent_location * 2048;
+            handle->rootdirsize =
+                    descriptor.rootdirectory.data_length;
+            handle->isjoliet = 1;
+            founddescriptor = 1;
+            foundjoliet = 1;
+        } /* if */
+    } /* while */
+
+    GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup);  /* not found. */
+
+errorcleanup:
+    if (handle)
+    {
+        if (handle->path)
+            allocator.Free(handle->path);
+        if (handle->mutex)
+            __PHYSFS_platformDestroyMutex(handle->mutex);
+        allocator.Free(handle);
+    } /* if */
+    return NULL;
+} /* ISO9660_openArchive */
+
+
+static void ISO9660_closeArchive(PHYSFS_Dir *opaque)
+{
+    ISO9660Handle *handle = (ISO9660Handle*) opaque;
+    handle->io->destroy(handle->io);
+    __PHYSFS_platformDestroyMutex(handle->mutex);
+    allocator.Free(handle->path);
+    allocator.Free(handle);
+} /* ISO9660_closeArchive */
+
+
+/*******************************************************************************
+ * Read functions
+ ******************************************************************************/
+
+
+static PHYSFS_uint32 iso_file_read_mem(ISO9660FileHandle *filehandle,
+                                       void *buffer, PHYSFS_uint64 len)
+{
+    /* check remaining bytes & max obj which can be fetched */
+    const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
+    if (bytesleft < len)
+        len = bytesleft;
+
+    if (len == 0)
+        return 0;
+
+    memcpy(buffer, filehandle->cacheddata + filehandle->currpos, (size_t) len);
+
+    filehandle->currpos += len;
+    return (PHYSFS_uint32) len;
+} /* iso_file_read_mem */
+
+
+static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset)
+{
+    BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0);
+
+    fhandle->currpos = offset;
+    return 0;
+} /* iso_file_seek_mem */
+
+
+static void iso_file_close_mem(ISO9660FileHandle *fhandle)
+{
+    allocator.Free(fhandle->cacheddata);
+    allocator.Free(fhandle);
+} /* iso_file_close_mem */
+
+
+static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle,
+                                           void *buffer, PHYSFS_uint64 len)
+{
+    /* check remaining bytes & max obj which can be fetched */
+    const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos;
+    if (bytesleft < len)
+        len = bytesleft;
+
+    const PHYSFS_sint64 rc = filehandle->io->read(filehandle->io, buffer, len);
+    BAIL_IF_MACRO(rc == -1, ERRPASS, -1);
+
+    filehandle->currpos += rc; /* i trust my internal book keeping */
+    BAIL_IF_MACRO(rc < len, PHYSFS_ERR_CORRUPT, -1);
+    return rc;
+} /* iso_file_read_foreign */
+
+
+static int iso_file_seek_foreign(ISO9660FileHandle *fhandle,
+                                 PHYSFS_sint64 offset)
+{
+    BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0);
+
+    PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset;
+    BAIL_IF_MACRO(!fhandle->io->seek(fhandle->io, pos), ERRPASS, -1);
+
+    fhandle->currpos = offset;
+    return 0;
+} /* iso_file_seek_foreign */
+
+
+static void iso_file_close_foreign(ISO9660FileHandle *fhandle)
+{
+    fhandle->io->destroy(fhandle->io);
+    allocator.Free(fhandle);
+} /* iso_file_close_foreign */
+
+
+static int iso_file_open_mem(ISO9660Handle *handle, ISO9660FileHandle *fhandle)
+{
+    fhandle->cacheddata = allocator.Malloc(fhandle->filesize);
+    BAIL_IF_MACRO(!fhandle->cacheddata, PHYSFS_ERR_OUT_OF_MEMORY, -1);
+    int rc = iso_readimage(handle, fhandle->startblock * 2048,
+                           fhandle->cacheddata, fhandle->filesize);
+    GOTO_IF_MACRO(rc < 0, ERRPASS, freemem);
+    GOTO_IF_MACRO(rc == 0, PHYSFS_ERR_CORRUPT, freemem);
+
+    fhandle->read = iso_file_read_mem;
+    fhandle->seek = iso_file_seek_mem;
+    fhandle->close = iso_file_close_mem;
+    return 0;
+
+freemem:
+    allocator.Free(fhandle->cacheddata);
+    return -1;
+} /* iso_file_open_mem */
+
+
+static int iso_file_open_foreign(ISO9660Handle *handle,
+                                 ISO9660FileHandle *fhandle)
+{
+    int rc;
+    fhandle->io = __PHYSFS_createNativeIo(handle->path, 'r');
+    BAIL_IF_MACRO(!fhandle->io, ERRPASS, -1);
+    rc = fhandle->io->seek(fhandle->io, fhandle->startblock * 2048);
+    GOTO_IF_MACRO(!rc, ERRPASS, closefile);
+
+    fhandle->read = iso_file_read_foreign;
+    fhandle->seek = iso_file_seek_foreign;
+    fhandle->close = iso_file_close_foreign;
+    return 0;
+
+closefile:
+    fhandle->io->destroy(fhandle->io);
+    return -1;
+} /* iso_file_open_foreign */
+
+
+static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename,
+                                   int *exists)
+{
+    PHYSFS_Io *retval = NULL;
+    ISO9660Handle *handle = (ISO9660Handle*) opaque;
+    ISO9660FileHandle *fhandle;
+    ISO9660FileDescriptor descriptor;
+    int rc;
+
+    fhandle = allocator.Malloc(sizeof(ISO9660FileHandle));
+    BAIL_IF_MACRO(fhandle == 0, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    fhandle->cacheddata = 0;
+
+    retval = allocator.Malloc(sizeof(PHYSFS_Io));
+    GOTO_IF_MACRO(retval == 0, PHYSFS_ERR_OUT_OF_MEMORY, errorhandling);
+
+    /* find file descriptor */
+    rc = iso_find_dir_entry(handle, filename, &descriptor, exists);
+    GOTO_IF_MACRO(rc, ERRPASS, errorhandling);
+    GOTO_IF_MACRO(!*exists, PHYSFS_ERR_NO_SUCH_PATH, errorhandling);
+
+    fhandle->startblock = descriptor.extentpos + descriptor.extattributelen;
+    fhandle->filesize = descriptor.datalen;
+    fhandle->currpos = 0;
+    fhandle->isohandle = handle;
+    fhandle->cacheddata = NULL;
+    fhandle->io = NULL;
+
+    if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE)
+        rc = iso_file_open_mem(handle, fhandle);
+    else
+        rc = iso_file_open_foreign(handle, fhandle);
+    GOTO_IF_MACRO(rc, ERRPASS, errorhandling);
+
+    memcpy(retval, &ISO9660_Io, sizeof (PHYSFS_Io));
+    retval->opaque = fhandle;
+    return retval;
+
+errorhandling:
+    if (retval) allocator.Free(retval);
+    if (fhandle) allocator.Free(fhandle);
+    return NULL;
+} /* ISO9660_openRead */
+
+
+
+/*******************************************************************************
+ * Information gathering functions
+ ******************************************************************************/
+
+static void ISO9660_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+                                   int omitSymLinks,
+                                   PHYSFS_EnumFilesCallback cb,
+                                   const char *origdir, void *callbackdata)
+{
+    ISO9660Handle *handle = (ISO9660Handle*) opaque;
+    ISO9660FileDescriptor descriptor;
+    PHYSFS_uint64 readpos;
+    PHYSFS_uint64 end_of_dir;
+    char filename[130]; /* ISO allows 31, Joliet 128 -> 128 + 2 eol bytes */
+    int version = 0;
+
+    if (*dname == '\0')
+    {
+        readpos = handle->rootdirstart;
+        end_of_dir = readpos + handle->rootdirsize;
+    } /* if */
+    else
+    {
+        printf("pfad %s\n",dname);
+        int exists = 0;
+        BAIL_IF_MACRO(iso_find_dir_entry(handle,dname, &descriptor, &exists), ERRPASS,);
+        BAIL_IF_MACRO(!exists, ERRPASS, );
+        BAIL_IF_MACRO(!descriptor.flags.directory, ERRPASS,);
+
+        readpos = descriptor.extentpos * 2048;
+        end_of_dir = readpos + descriptor.datalen;
+    } /* else */
+
+    while (1)
+    {
+        BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, &descriptor), ERRPASS, );
+
+        /* recordlen = 0 -> no more entries or fill entry */
+        if (!descriptor.recordlen)
+        {
+            /* if we are in the last sector of the directory & it's 0 -> end */
+            if ((end_of_dir - 2048) <= (readpos -1))
+                break;  /* finished */
+
+            /* else skip to the next sector & continue; */
+            readpos = (((readpos - 1) / 2048) + 1) * 2048;
+            continue;
+        } /* if */
+
+        readpos +=  descriptor.recordlen;
+        if (descriptor.filenamelen == 1 && (descriptor.filename[0] == 0
+                || descriptor.filename[0] == 1))
+            continue; /* special ones, ignore */
+
+        strncpy(filename,descriptor.filename,descriptor.filenamelen);
+        iso_extractfilename(handle, &descriptor, filename, &version);
+        cb(callbackdata, origdir,filename);
+    } /* while */
+} /* ISO9660_enumerateFiles */
+
+
+static int ISO9660_stat(PHYSFS_Dir *opaque, const char *name, int *exists,
+                        PHYSFS_Stat *stat)
+{
+    ISO9660Handle *handle = (ISO9660Handle*) opaque;
+    ISO9660FileDescriptor descriptor;
+    ISO9660ExtAttributeRec extattr;
+    BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, exists), ERRPASS, -1);
+    if (!*exists)
+        return 0;
+
+    stat->readonly = 1;
+
+    /* try to get extended info */
+    if (descriptor.extattributelen)
+    {
+        BAIL_IF_MACRO(iso_read_ext_attributes(handle,
+                descriptor.extentpos, &extattr), ERRPASS, -1);
+        stat->createtime = iso_volume_mktime(&extattr.create_time);
+        stat->modtime = iso_volume_mktime(&extattr.mod_time);
+        stat->accesstime = iso_volume_mktime(&extattr.mod_time);
+    } /* if */
+    else
+    {
+        stat->createtime = iso_mktime(&descriptor.recordtime);
+        stat->modtime = iso_mktime(&descriptor.recordtime);
+        stat->accesstime = iso_mktime(&descriptor.recordtime);
+    } /* else */
+
+    if (descriptor.flags.directory)
+    {
+        stat->filesize = 0;
+        stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+    } /* if */
+    else
+    {
+        stat->filesize = descriptor.datalen;
+        stat->filetype = PHYSFS_FILETYPE_REGULAR;
+    } /* else */
+
+    return 1;
+} /* ISO9660_stat */
+
+
+/*******************************************************************************
+ * Not supported functions
+ ******************************************************************************/
+
+static PHYSFS_Io *ISO9660_openWrite(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ISO9660_openWrite */
+
+
+static PHYSFS_Io *ISO9660_openAppend(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ISO9660_openAppend */
+
+
+static int ISO9660_remove(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ISO9660_remove */
+
+
+static int ISO9660_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ISO9660_mkdir */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 =
+{
+    {
+        "ISO",
+        "ISO9660 image file",
+        "Christoph Nelles <evilazrael@evilazrael.de>",
+        "http://www.evilazrael.de/",
+    },
+    ISO9660_openArchive,        /* openArchive() method    */
+    ISO9660_enumerateFiles,     /* enumerateFiles() method */
+    ISO9660_openRead,           /* openRead() method       */
+    ISO9660_openWrite,          /* openWrite() method      */
+    ISO9660_openAppend,         /* openAppend() method     */
+    ISO9660_remove,             /* remove() method         */
+    ISO9660_mkdir,              /* mkdir() method          */
+    ISO9660_closeArchive,       /* closeArchive() method   */
+    ISO9660_stat                /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_ISO9660 */
+
+/* end of archiver_iso9660.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_lzma.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,701 @@
+/*
+ * LZMA support routines for PhysicsFS.
+ *
+ * Please see the file lzma.txt in the lzma/ directory.
+ *
+ *  This file was written by Dennis Schridde, with some peeking at "7zMain.c"
+ *   by Igor Pavlov.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_7Z
+
+#include "lzma/C/7zCrc.h"
+#include "lzma/C/Archive/7z/7zIn.h"
+#include "lzma/C/Archive/7z/7zExtract.h"
+
+
+/* 7z internal from 7zIn.c */
+extern int TestSignatureCandidate(Byte *testBytes);
+
+
+#ifdef _LZMA_IN_CB
+# define BUFFER_SIZE (1 << 12)
+#endif /* _LZMA_IN_CB */
+
+
+/*
+ * Carries filestream metadata through 7z
+ */
+typedef struct _FileInputStream
+{
+    ISzAlloc allocImp; /* Allocation implementation, used by 7z */
+    ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */
+    ISzInStream inStream; /* Input stream with read callbacks, used by 7z */
+    PHYSFS_Io *io;  /* Filehandle, used by read implementation */
+#ifdef _LZMA_IN_CB
+    Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */
+#endif /* _LZMA_IN_CB */
+} FileInputStream;
+
+/*
+ * In the 7z format archives are splited into blocks, those are called folders
+ * Set by LZMA_read()
+*/
+typedef struct _LZMAfolder
+{
+    PHYSFS_uint32 index; /* Index of folder in archive */
+    PHYSFS_uint32 references; /* Number of files using this block */
+    PHYSFS_uint8 *cache; /* Cached folder */
+    size_t size; /* Size of folder */
+} LZMAfolder;
+
+/*
+ * Set by LZMA_openArchive(), except folder which gets it's values
+ *  in LZMA_read()
+ */
+typedef struct _LZMAarchive
+{
+    struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */
+    LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */
+    CArchiveDatabaseEx db; /* For 7z: Database */
+    FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */
+} LZMAarchive;
+
+/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */
+typedef struct _LZMAfile
+{
+    PHYSFS_uint32 index; /* Index of file in archive */
+    LZMAarchive *archive; /* Link to corresponding archive */
+    LZMAfolder *folder; /* Link to corresponding folder */
+    CFileItem *item; /* For 7z: File info, eg. name, size */
+    size_t offset; /* Offset in folder */
+    size_t position; /* Current "virtual" position in file */
+} LZMAfile;
+
+
+/* Memory management implementations to be passed to 7z */
+
+static void *SzAllocPhysicsFS(size_t size)
+{
+    return ((size == 0) ? NULL : allocator.Malloc(size));
+} /* SzAllocPhysicsFS */
+
+
+static void SzFreePhysicsFS(void *address)
+{
+    if (address != NULL)
+        allocator.Free(address);
+} /* SzFreePhysicsFS */
+
+
+/* Filesystem implementations to be passed to 7z */
+
+#ifdef _LZMA_IN_CB
+
+/*
+ * Read implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize,
+                        size_t *processedSize)
+{
+    FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */
+    PHYSFS_sint64 processedSizeLoc = 0;
+
+    if (maxReqSize > BUFFER_SIZE)
+        maxReqSize = BUFFER_SIZE;
+    processedSizeLoc = s->io->read(s->io, s->buffer, maxReqSize);
+    *buffer = s->buffer;
+    if (processedSize != NULL)
+        *processedSize = (size_t) processedSizeLoc;
+
+    return SZ_OK;
+} /* SzFileReadImp */
+
+#else
+
+/*
+ * Read implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size,
+                        size_t *processedSize)
+{
+    FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
+    const size_t processedSizeLoc = s->io->read(s->io, buffer, size);
+    if (processedSize != NULL)
+        *processedSize = processedSizeLoc;
+    return SZ_OK;
+} /* SzFileReadImp */
+
+#endif
+
+/*
+ * Seek implementation, to be passed to 7z
+ * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly!
+ */
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+    FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */
+    if (s->io->seek(s->io, (PHYSFS_uint64) pos))
+        return SZ_OK;
+    return SZE_FAIL;
+} /* SzFileSeekImp */
+
+
+/*
+ * Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp
+ */
+static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft)
+{
+    /* MS counts in nanoseconds ... */
+    const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000);
+    /* MS likes to count seconds since 01.01.1601 ... */
+    const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600);
+
+    PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32);
+    return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF;
+} /* lzma_filetime_to_unix_timestamp */
+
+
+/*
+ * Compare a file with a given name, C89 stdlib variant
+ * Used for sorting
+ */
+static int lzma_file_cmp_stdlib(const void *key, const void *object)
+{
+    const char *name = (const char *) key;
+    LZMAfile *file = (LZMAfile *) object;
+    return strcmp(name, file->item->Name);
+} /* lzma_file_cmp_posix */
+
+
+/*
+ * Compare two files with each other based on the name
+ * Used for sorting
+ */
+static int lzma_file_cmp(void *_a, size_t one, size_t two)
+{
+    LZMAfile *files = (LZMAfile *) _a;
+    return strcmp(files[one].item->Name, files[two].item->Name);
+} /* lzma_file_cmp */
+
+
+/*
+ * Swap two entries in the file array
+ */
+static void lzma_file_swap(void *_a, size_t one, size_t two)
+{
+    LZMAfile tmp;
+    LZMAfile *first = &(((LZMAfile *) _a)[one]);
+    LZMAfile *second = &(((LZMAfile *) _a)[two]);
+    memcpy(&tmp, first, sizeof (LZMAfile));
+    memcpy(first, second, sizeof (LZMAfile));
+    memcpy(second, &tmp, sizeof (LZMAfile));
+} /* lzma_file_swap */
+
+
+/*
+ * Find entry 'name' in 'archive'
+ */
+static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name)
+{
+    LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */
+
+    BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL);
+
+    return file;
+} /* lzma_find_file */
+
+
+/*
+ * Load metadata for the file at given index
+ */
+static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex)
+{
+    LZMAfile *file = &archive->files[fileIndex];
+    PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex];
+
+    file->index = fileIndex; /* Store index into 7z array, since we sort our own. */
+    file->archive = archive;
+    file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */
+    file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */
+    file->position = 0;
+    file->offset = 0; /* Offset will be set by LZMA_read() */
+
+    return 1;
+} /* lzma_load_file */
+
+
+/*
+ * Load metadata for all files
+ */
+static int lzma_files_init(LZMAarchive *archive)
+{
+    PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+
+    for (fileIndex = 0; fileIndex < numFiles; fileIndex++ )
+    {
+        if (!lzma_file_init(archive, fileIndex))
+        {
+            return 0; /* FALSE on failure */
+        }
+    } /* for */
+
+   __PHYSFS_sort(archive->files, (size_t) numFiles, lzma_file_cmp, lzma_file_swap);
+
+    return 1;
+} /* lzma_load_files */
+
+
+/*
+ * Initialise specified archive
+ */
+static void lzma_archive_init(LZMAarchive *archive)
+{
+    memset(archive, 0, sizeof(*archive));
+
+    /* Prepare callbacks for 7z */
+    archive->stream.inStream.Read = SzFileReadImp;
+    archive->stream.inStream.Seek = SzFileSeekImp;
+
+    archive->stream.allocImp.Alloc = SzAllocPhysicsFS;
+    archive->stream.allocImp.Free = SzFreePhysicsFS;
+
+    archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS;
+    archive->stream.allocTempImp.Free = SzFreePhysicsFS;
+}
+
+
+/*
+ * Deinitialise archive
+ */
+static void lzma_archive_exit(LZMAarchive *archive)
+{
+    /* Free arrays */
+    allocator.Free(archive->folders);
+    allocator.Free(archive->files);
+    allocator.Free(archive);
+}
+
+/*
+ * Wrap all 7z calls in this, so the physfs error state is set appropriately.
+ */
+static int lzma_err(SZ_RESULT rc)
+{
+    switch (rc)
+    {
+        case SZ_OK: /* Same as LZMA_RESULT_OK */
+            break;
+        case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */
+            __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */
+            break;
+        case SZE_OUTOFMEMORY:
+            __PHYSFS_setError(PHYSFS_ERR_OUT_OF_MEMORY);
+            break;
+        case SZE_CRC_ERROR:
+            __PHYSFS_setError(PHYSFS_ERR_CORRUPT);
+            break;
+        case SZE_NOTIMPL:
+            __PHYSFS_setError(PHYSFS_ERR_UNSUPPORTED);
+            break;
+        case SZE_FAIL:
+            __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR);  /* !!! FIXME: right? */
+            break;
+        case SZE_ARCHIVE_ERROR:
+            __PHYSFS_setError(PHYSFS_ERR_CORRUPT);  /* !!! FIXME: right? */
+            break;
+        default:
+            __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR);
+    } /* switch */
+
+    return rc;
+} /* lzma_err */
+
+
+static PHYSFS_sint64 LZMA_read(PHYSFS_Io *io, void *outBuf, PHYSFS_uint64 len)
+{
+    LZMAfile *file = (LZMAfile *) io->opaque;
+
+    size_t wantedSize = (size_t) len;
+    const size_t remainingSize = file->item->Size - file->position;
+    size_t fileSize = 0;
+
+    BAIL_IF_MACRO(wantedSize == 0, ERRPASS, 0); /* quick rejection. */
+    BAIL_IF_MACRO(remainingSize == 0, PHYSFS_ERR_PAST_EOF, 0);
+
+    if (wantedSize > remainingSize)
+        wantedSize = remainingSize;
+
+    /* Only decompress the folder if it is not already cached */
+    if (file->folder->cache == NULL)
+    {
+        const int rc = lzma_err(SzExtract(
+            &file->archive->stream.inStream, /* compressed data */
+            &file->archive->db, /* 7z's database, containing everything */
+            file->index, /* Index into database arrays */
+            /* Index of cached folder, will be changed by SzExtract */
+            &file->folder->index,
+            /* Cache for decompressed folder, allocated/freed by SzExtract */
+            &file->folder->cache,
+            /* Size of cache, will be changed by SzExtract */
+            &file->folder->size,
+            /* Offset of this file inside the cache, set by SzExtract */
+            &file->offset,
+            &fileSize, /* Size of this file */
+            &file->archive->stream.allocImp,
+            &file->archive->stream.allocTempImp));
+
+        if (rc != SZ_OK)
+            return -1;
+    } /* if */
+
+    /* Copy wanted bytes over from cache to outBuf */
+    memcpy(outBuf, (file->folder->cache + file->offset + file->position),
+            wantedSize);
+    file->position += wantedSize; /* Increase virtual position */
+
+    return wantedSize;
+} /* LZMA_read */
+
+
+static PHYSFS_sint64 LZMA_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* LZMA_write */
+
+
+static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io)
+{
+    LZMAfile *file = (LZMAfile *) io->opaque;
+    return file->position;
+} /* LZMA_tell */
+
+
+static int LZMA_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+    LZMAfile *file = (LZMAfile *) io->opaque;
+
+    BAIL_IF_MACRO(offset > file->item->Size, PHYSFS_ERR_PAST_EOF, 0);
+
+    file->position = offset; /* We only use a virtual position... */
+
+    return 1;
+} /* LZMA_seek */
+
+
+static PHYSFS_sint64 LZMA_length(PHYSFS_Io *io)
+{
+    const LZMAfile *file = (LZMAfile *) io->opaque;
+    return (file->item->Size);
+} /* LZMA_length */
+
+
+static PHYSFS_Io *LZMA_duplicate(PHYSFS_Io *_io)
+{
+    /* !!! FIXME: this archiver needs to be reworked to allow multiple
+     * !!! FIXME:  opens before we worry about duplication. */
+    BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+} /* LZMA_duplicate */
+
+
+static int LZMA_flush(PHYSFS_Io *io) { return 1;  /* no write support. */ }
+
+
+static void LZMA_destroy(PHYSFS_Io *io)
+{
+    LZMAfile *file = (LZMAfile *) io->opaque;
+
+    if (file->folder != NULL)
+    {
+        /* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */
+        if (file->folder->references > 0)
+            file->folder->references--;
+        if (file->folder->references == 0)
+        {
+            /* Free the cache which might have been allocated by LZMA_read() */
+            allocator.Free(file->folder->cache);
+            file->folder->cache = NULL;
+        }
+        /* !!! FIXME: we don't free (file) or (file->folder)?! */
+    } /* if */
+} /* LZMA_destroy */
+
+
+static const PHYSFS_Io LZMA_Io =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    LZMA_read,
+    LZMA_write,
+    LZMA_seek,
+    LZMA_tell,
+    LZMA_length,
+    LZMA_duplicate,
+    LZMA_flush,
+    LZMA_destroy
+};
+
+
+static void *LZMA_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    PHYSFS_uint8 sig[k7zSignatureSize];
+    size_t len = 0;
+    LZMAarchive *archive = NULL;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+    if (io->read(io, sig, k7zSignatureSize) != k7zSignatureSize)
+        return 0;
+    BAIL_IF_MACRO(!TestSignatureCandidate(sig), PHYSFS_ERR_UNSUPPORTED, NULL);
+    BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
+
+    archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive));
+    BAIL_IF_MACRO(archive == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    lzma_archive_init(archive);
+    archive->stream.io = io;
+
+    CrcGenerateTable();
+    SzArDbExInit(&archive->db);
+    if (lzma_err(SzArchiveOpen(&archive->stream.inStream,
+                               &archive->db,
+                               &archive->stream.allocImp,
+                               &archive->stream.allocTempImp)) != SZ_OK)
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        lzma_archive_exit(archive);
+        return NULL; /* Error is set by lzma_err! */
+    } /* if */
+
+    len = archive->db.Database.NumFiles * sizeof (LZMAfile);
+    archive->files = (LZMAfile *) allocator.Malloc(len);
+    if (archive->files == NULL)
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    }
+
+    /*
+     * Init with 0 so we know when a folder is already cached
+     * Values will be set by LZMA_openRead()
+     */
+    memset(archive->files, 0, len);
+
+    len = archive->db.Database.NumFolders * sizeof (LZMAfolder);
+    archive->folders = (LZMAfolder *) allocator.Malloc(len);
+    if (archive->folders == NULL)
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    }
+
+    /*
+     * Init with 0 so we know when a folder is already cached
+     * Values will be set by LZMA_read()
+     */
+    memset(archive->folders, 0, len);
+
+    if(!lzma_files_init(archive))
+    {
+        SzArDbExFree(&archive->db, SzFreePhysicsFS);
+        lzma_archive_exit(archive);
+        BAIL_MACRO(PHYSFS_ERR_OTHER_ERROR, NULL);
+    }
+
+    return archive;
+} /* LZMA_openArchive */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, size_t flen)
+{
+    char *newstr = __PHYSFS_smallAlloc(flen + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, flen);
+    newstr[flen] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                                const char *origdir, void *callbackdata)
+{
+    size_t dlen = strlen(dname),
+           dlen_inc = dlen + ((dlen > 0) ? 1 : 0);
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = NULL,
+            *lastFile = &archive->files[archive->db.Database.NumFiles];
+        if (dlen)
+        {
+            file = lzma_find_file(archive, dname);
+            if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */
+                file += 1;
+        }
+        else
+        {
+            file = archive->files;
+        }
+
+    BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, );
+
+    while (file < lastFile)
+    {
+        const char * fname = file->item->Name;
+        const char * dirNameEnd = fname + dlen_inc;
+
+        if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */
+            break;
+
+        if (strchr(dirNameEnd, '/')) /* Skip subdirs */
+        {
+            file++;
+            continue;
+        }
+
+        /* Do the actual callback... */
+        doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd));
+
+        file++;
+    }
+} /* LZMA_enumerateFiles */
+
+
+static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name,
+                                int *fileExists)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+    LZMAfile *file = lzma_find_file(archive, name);
+    PHYSFS_Io *io = NULL;
+
+    *fileExists = (file != NULL);
+    BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL);
+    BAIL_IF_MACRO(file->folder == NULL, PHYSFS_ERR_NOT_A_FILE, NULL);
+
+    file->position = 0;
+    file->folder->references++; /* Increase refcount for automatic cleanup... */
+
+    io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    BAIL_IF_MACRO(io == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    memcpy(io, &LZMA_Io, sizeof (*io));
+    io->opaque = file;
+
+    return io;
+} /* LZMA_openRead */
+
+
+static PHYSFS_Io *LZMA_openWrite(PHYSFS_Dir *opaque, const char *filename)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* LZMA_openWrite */
+
+
+static PHYSFS_Io *LZMA_openAppend(PHYSFS_Dir *opaque, const char *filename)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* LZMA_openAppend */
+
+
+static void LZMA_closeArchive(PHYSFS_Dir *opaque)
+{
+    LZMAarchive *archive = (LZMAarchive *) opaque;
+
+#if 0  /* !!! FIXME: you shouldn't have to do this. */
+    PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles;
+    for (fileIndex = 0; fileIndex < numFiles; fileIndex++)
+    {
+        LZMA_fileClose(&archive->files[fileIndex]);
+    } /* for */
+#endif
+
+    SzArDbExFree(&archive->db, SzFreePhysicsFS);
+    archive->stream.io->destroy(archive->stream.io);
+    lzma_archive_exit(archive);
+} /* LZMA_closeArchive */
+
+
+static int LZMA_remove(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* LZMA_remove */
+
+
+static int LZMA_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* LZMA_mkdir */
+
+static int LZMA_stat(PHYSFS_Dir *opaque, const char *filename,
+                     int *exists, PHYSFS_Stat *stat)
+{
+    const LZMAarchive *archive = (const LZMAarchive *) opaque;
+    const LZMAfile *file = lzma_find_file(archive, filename);
+
+    *exists = (file != 0);
+    if (!file)
+        return 0;
+
+    if(file->item->IsDirectory)
+    {
+        stat->filesize = 0;
+        stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+    } /* if */
+    else
+    {
+        stat->filesize = (PHYSFS_sint64) file->item->Size;
+        stat->filetype = PHYSFS_FILETYPE_REGULAR;
+    } /* else */
+
+    /* !!! FIXME: the 0's should be -1's? */
+    if (file->item->IsLastWriteTimeDefined)
+        stat->modtime = lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime);
+    else
+        stat->modtime = 0;
+
+    /* real create and accesstype are currently not in the lzma SDK */
+    stat->createtime = stat->modtime;
+    stat->accesstime = 0;
+
+    stat->readonly = 1;  /* 7zips are always read only */
+
+    return 1;
+} /* LZMA_stat */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
+{
+    {
+        "7Z",
+        "LZMA (7zip) format",
+        "Dennis Schridde <devurandom@gmx.net>",
+        "http://icculus.org/physfs/",
+    },
+    LZMA_openArchive,        /* openArchive() method    */
+    LZMA_enumerateFiles,     /* enumerateFiles() method */
+    LZMA_openRead,           /* openRead() method       */
+    LZMA_openWrite,          /* openWrite() method      */
+    LZMA_openAppend,         /* openAppend() method     */
+    LZMA_remove,             /* remove() method         */
+    LZMA_mkdir,              /* mkdir() method          */
+    LZMA_closeArchive,       /* closeArchive() method   */
+    LZMA_stat                /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_7Z */
+
+/* end of lzma.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_mvl.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,103 @@
+/*
+ * MVL support routines for PhysicsFS.
+ *
+ * This driver handles Descent II Movielib archives.
+ *
+ * The file format of MVL is quite easy...
+ *
+ *   //MVL File format - Written by Heiko Herrmann
+ *   char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library
+ *
+ *   int num_files; // the number of files in this MVL
+ *
+ *   struct {
+ *    char file_name[13]; // Filename, padded to 13 bytes with 0s
+ *    int file_size; // filesize in bytes
+ *   }DIR_STRUCT[num_files];
+ *
+ *   struct {
+ *    char data[file_size]; // The file data
+ *   }FILE_STRUCT[num_files];
+ *
+ * (That info is from http://www.descent2.com/ddn/specs/mvl/)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Bradley Bell.
+ *  Based on grp.c by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_MVL
+
+static UNPKentry *mvlLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+    PHYSFS_uint32 location = 8;  /* sizeof sig. */
+    UNPKentry *entries = NULL;
+    UNPKentry *entry = NULL;
+
+    entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+    BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    location += (17 * fileCount);
+
+    for (entry = entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (!__PHYSFS_readAll(io, &entry->name, 13)) goto failed;
+        if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = location;
+        location += entry->size;
+    } /* for */
+
+    return entries;
+
+failed:
+    allocator.Free(entries);
+    return NULL;
+} /* mvlLoadEntries */
+
+
+static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    PHYSFS_uint8 buf[4];
+    PHYSFS_uint32 count = 0;
+    UNPKentry *entries = NULL;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 4), ERRPASS, NULL);
+    BAIL_IF_MACRO(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL);
+
+    count = PHYSFS_swapULE32(count);
+    entries = mvlLoadEntries(io, count);
+    return (!entries) ? NULL : UNPK_openArchive(io, entries, count);
+} /* MVL_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
+{
+    {
+        "MVL",
+        "Descent II Movielib format",
+        "Bradley Bell <btb@icculus.org>",
+        "http://icculus.org/physfs/",
+    },
+    MVL_openArchive,        /* openArchive() method    */
+    UNPK_enumerateFiles,     /* enumerateFiles() method */
+    UNPK_openRead,           /* openRead() method       */
+    UNPK_openWrite,          /* openWrite() method      */
+    UNPK_openAppend,         /* openAppend() method     */
+    UNPK_remove,             /* remove() method         */
+    UNPK_mkdir,              /* mkdir() method          */
+    UNPK_closeArchive,       /* closeArchive() method   */
+    UNPK_stat                /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_MVL */
+
+/* end of mvl.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_qpak.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,119 @@
+/*
+ * QPAK support routines for PhysicsFS.
+ *
+ *  This archiver handles the archive format utilized by Quake 1 and 2.
+ *  Quake3-based games use the PkZip/Info-Zip format (which our zip.c
+ *  archiver handles).
+ *
+ *  ========================================================================
+ *
+ *  This format info (in more detail) comes from:
+ *     http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt
+ *
+ *  Quake PAK Format
+ *
+ *  Header
+ *   (4 bytes)  signature = 'PACK'
+ *   (4 bytes)  directory offset
+ *   (4 bytes)  directory length
+ *
+ *  Directory
+ *   (56 bytes) file name
+ *   (4 bytes)  file position
+ *   (4 bytes)  file length
+ *
+ *  ========================================================================
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_QPAK
+
+#define QPAK_SIG 0x4B434150   /* "PACK" in ASCII. */
+
+static UNPKentry *qpakLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+    UNPKentry *entries = NULL;
+    UNPKentry *entry = NULL;
+
+    entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+    BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    for (entry = entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (!__PHYSFS_readAll(io, &entry->name, 56)) goto failed;
+        if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
+        if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = PHYSFS_swapULE32(entry->startPos);
+    } /* for */
+
+    return entries;
+
+failed:
+    allocator.Free(entries);
+    return NULL;
+} /* qpakLoadEntries */
+
+
+static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    UNPKentry *entries = NULL;
+    PHYSFS_uint32 val = 0;
+    PHYSFS_uint32 pos = 0;
+    PHYSFS_uint32 count = 0;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
+    if (PHYSFS_swapULE32(val) != QPAK_SIG)
+        BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
+    pos = PHYSFS_swapULE32(val);  /* directory table offset. */
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL);
+    count = PHYSFS_swapULE32(val);
+
+    /* corrupted archive? */
+    BAIL_IF_MACRO((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL);
+    count /= 64;
+
+    BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, NULL);
+
+    entries = qpakLoadEntries(io, count);
+    BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+    return UNPK_openArchive(io, entries, count);
+} /* QPAK_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
+{
+    {
+        "PAK",
+        "Quake I/II format",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://icculus.org/physfs/",
+    },
+    QPAK_openArchive,       /* openArchive() method    */
+    UNPK_enumerateFiles,    /* enumerateFiles() method */
+    UNPK_openRead,          /* openRead() method       */
+    UNPK_openWrite,         /* openWrite() method      */
+    UNPK_openAppend,        /* openAppend() method     */
+    UNPK_remove,            /* remove() method         */
+    UNPK_mkdir,             /* mkdir() method          */
+    UNPK_closeArchive,       /* closeArchive() method   */
+    UNPK_stat               /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_QPAK */
+
+/* end of qpak.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_unpacked.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,470 @@
+/*
+ * High-level PhysicsFS archiver for simple unpacked file formats.
+ *
+ * This is a framework that basic archivers build on top of. It's for simple
+ *  formats that can just hand back a list of files and the offsets of their
+ *  uncompressed data. There are an alarming number of formats like this.
+ *
+ * RULES: Archive entries must be uncompressed, must not have separate subdir
+ *  entries (but can have subdirs), must be case insensitive LOW ASCII
+ *  filenames <= 56 bytes. No symlinks, etc. We can relax some of these rules
+ *  as necessary.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+typedef struct
+{
+    PHYSFS_Io *io;
+    PHYSFS_uint32 entryCount;
+    UNPKentry *entries;
+} UNPKinfo;
+
+
+typedef struct
+{
+    PHYSFS_Io *io;
+    UNPKentry *entry;
+    PHYSFS_uint32 curPos;
+} UNPKfileinfo;
+
+
+void UNPK_closeArchive(PHYSFS_Dir *opaque)
+{
+    UNPKinfo *info = ((UNPKinfo *) opaque);
+    info->io->destroy(info->io);
+    allocator.Free(info->entries);
+    allocator.Free(info);
+} /* UNPK_closeArchive */
+
+
+static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len)
+{
+    UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+    const UNPKentry *entry = finfo->entry;
+    const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos);
+    PHYSFS_sint64 rc;
+
+    if (bytesLeft < len)
+        len = bytesLeft;
+
+    rc = finfo->io->read(finfo->io, buffer, len);
+    if (rc > 0)
+        finfo->curPos += (PHYSFS_uint32) rc;
+
+    return rc;
+} /* UNPK_read */
+
+
+static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* UNPK_write */
+
+
+static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io)
+{
+    return ((UNPKfileinfo *) io->opaque)->curPos;
+} /* UNPK_tell */
+
+
+static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+    UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+    const UNPKentry *entry = finfo->entry;
+    int rc;
+
+    BAIL_IF_MACRO(offset >= entry->size, PHYSFS_ERR_PAST_EOF, 0);
+    rc = finfo->io->seek(finfo->io, entry->startPos + offset);
+    if (rc)
+        finfo->curPos = (PHYSFS_uint32) offset;
+
+    return rc;
+} /* UNPK_seek */
+
+
+static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io)
+{
+    const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+    return ((PHYSFS_sint64) finfo->entry->size);
+} /* UNPK_length */
+
+
+static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io)
+{
+    UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque;
+    PHYSFS_Io *io = NULL;
+    PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
+    GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
+    GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed);
+
+    io = origfinfo->io->duplicate(origfinfo->io);
+    if (!io) goto UNPK_duplicate_failed;
+    finfo->io = io;
+    finfo->entry = origfinfo->entry;
+    finfo->curPos = 0;
+    memcpy(retval, _io, sizeof (PHYSFS_Io));
+    retval->opaque = finfo;
+    return retval;
+
+UNPK_duplicate_failed:
+    if (finfo != NULL) allocator.Free(finfo);
+    if (retval != NULL) allocator.Free(retval);
+    if (io != NULL) io->destroy(io);
+    return NULL;
+} /* UNPK_duplicate */
+
+static int UNPK_flush(PHYSFS_Io *io) { return 1;  /* no write support. */ }
+
+static void UNPK_destroy(PHYSFS_Io *io)
+{
+    UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque;
+    finfo->io->destroy(finfo->io);
+    allocator.Free(finfo);
+    allocator.Free(io);
+} /* UNPK_destroy */
+
+
+static const PHYSFS_Io UNPK_Io =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    UNPK_read,
+    UNPK_write,
+    UNPK_seek,
+    UNPK_tell,
+    UNPK_length,
+    UNPK_duplicate,
+    UNPK_flush,
+    UNPK_destroy
+};
+
+
+static int entryCmp(void *_a, size_t one, size_t two)
+{
+    if (one != two)
+    {
+        const UNPKentry *a = (const UNPKentry *) _a;
+        return __PHYSFS_stricmpASCII(a[one].name, a[two].name);
+    } /* if */
+
+    return 0;
+} /* entryCmp */
+
+
+static void entrySwap(void *_a, size_t one, size_t two)
+{
+    if (one != two)
+    {
+        UNPKentry tmp;
+        UNPKentry *first = &(((UNPKentry *) _a)[one]);
+        UNPKentry *second = &(((UNPKentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (UNPKentry));
+        memcpy(first, second, sizeof (UNPKentry));
+        memcpy(second, &tmp, sizeof (UNPKentry));
+    } /* if */
+} /* entrySwap */
+
+
+static PHYSFS_sint32 findStartOfDir(UNPKinfo *info, const char *path,
+                                    int stop_on_first_find)
+{
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
+    PHYSFS_sint32 retval = -1;
+    const char *name;
+    int rc;
+
+    if (*path == '\0')  /* root dir? */
+        return 0;
+
+    if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        name = info->entries[middle].name;
+        rc = __PHYSFS_strnicmpASCII(path, name, dlen);
+        if (rc == 0)
+        {
+            char ch = name[dlen];
+            if (ch < '/') /* make sure this isn't just a substr match. */
+                rc = -1;
+            else if (ch > '/')
+                rc = 1;
+            else 
+            {
+                if (stop_on_first_find) /* Just checking dir's existance? */
+                    return middle;
+
+                if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+                    return (middle + 1);
+
+                /* there might be more entries earlier in the list. */
+                retval = middle;
+                hi = middle - 1;
+            } /* else */
+        } /* if */
+
+        if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    return retval;
+} /* findStartOfDir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+                         int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                         const char *origdir, void *callbackdata)
+{
+    UNPKinfo *info = ((UNPKinfo *) opaque);
+    PHYSFS_sint32 dlen, dlen_inc, max, i;
+
+    i = findStartOfDir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
+
+    dlen = (PHYSFS_sint32) strlen(dname);
+    if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
+    max = (PHYSFS_sint32) info->entryCount;
+    while (i < max)
+    {
+        char *add;
+        char *ptr;
+        PHYSFS_sint32 ln;
+        char *e = info->entries[i].name;
+        if ((dlen) &&
+            ((__PHYSFS_strnicmpASCII(e, dname, dlen)) || (e[dlen] != '/')))
+        {
+            break;  /* past end of this dir; we're done. */
+        } /* if */
+
+        add = e + dlen_inc;
+        ptr = strchr(add, '/');
+        ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+        doEnumCallback(cb, callbackdata, origdir, add, ln);
+        ln += dlen_inc;  /* point past entry to children... */
+
+        /* increment counter and skip children of subdirs... */
+        while ((++i < max) && (ptr != NULL))
+        {
+            char *e_new = info->entries[i].name;
+            if ((__PHYSFS_strnicmpASCII(e, e_new, ln) != 0) ||
+                (e_new[ln] != '/'))
+            {
+                break;
+            } /* if */
+        } /* while */
+    } /* while */
+} /* UNPK_enumerateFiles */
+
+
+/*
+ * This will find the UNPKentry associated with a path in platform-independent
+ *  notation. Directories don't have UNPKentries associated with them, but 
+ *  (*isDir) will be set to non-zero if a dir was hit.
+ */
+static UNPKentry *findEntry(const UNPKinfo *info, const char *path, int *isDir)
+{
+    UNPKentry *a = info->entries;
+    PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
+    PHYSFS_sint32 lo = 0;
+    PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1);
+    PHYSFS_sint32 middle;
+    const char *thispath = NULL;
+    int rc;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        thispath = a[middle].name;
+        rc = __PHYSFS_strnicmpASCII(path, thispath, pathlen);
+
+        if (rc > 0)
+            lo = middle + 1;
+
+        else if (rc < 0)
+            hi = middle - 1;
+
+        else /* substring match...might be dir or entry or nothing. */
+        {
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return NULL;
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return &a[middle];
+            /* adjust search params, try again. */
+            else if (thispath[pathlen] > '/')
+                hi = middle - 1;
+            else
+                lo = middle + 1;
+        } /* if */
+    } /* while */
+
+    if (isDir != NULL)
+        *isDir = 0;
+
+    BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
+} /* findEntry */
+
+
+PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists)
+{
+    PHYSFS_Io *retval = NULL;
+    UNPKinfo *info = (UNPKinfo *) opaque;
+    UNPKfileinfo *finfo = NULL;
+    int isdir = 0;
+    UNPKentry *entry = findEntry(info, fnm, &isdir);
+
+    *fileExists = (entry != NULL);
+    GOTO_IF_MACRO(isdir, PHYSFS_ERR_NOT_A_FILE, UNPK_openRead_failed);
+    GOTO_IF_MACRO(!entry, ERRPASS, UNPK_openRead_failed);
+
+    retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
+
+    finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo));
+    GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed);
+
+    finfo->io = info->io->duplicate(info->io);
+    GOTO_IF_MACRO(!finfo->io, ERRPASS, UNPK_openRead_failed);
+
+    if (!finfo->io->seek(finfo->io, entry->startPos))
+        goto UNPK_openRead_failed;
+
+    finfo->curPos = 0;
+    finfo->entry = entry;
+
+    memcpy(retval, &UNPK_Io, sizeof (*retval));
+    retval->opaque = finfo;
+    return retval;
+
+UNPK_openRead_failed:
+    if (finfo != NULL)
+    {
+        if (finfo->io != NULL)
+            finfo->io->destroy(finfo->io);
+        allocator.Free(finfo);
+    } /* if */
+
+    if (retval != NULL)
+        allocator.Free(retval);
+
+    return NULL;
+} /* UNPK_openRead */
+
+
+PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* UNPK_openWrite */
+
+
+PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* UNPK_openAppend */
+
+
+int UNPK_remove(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* UNPK_remove */
+
+
+int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* UNPK_mkdir */
+
+
+int UNPK_stat(PHYSFS_Dir *opaque, const char *filename,
+              int *exists, PHYSFS_Stat *stat)
+{
+    int isDir = 0;
+    const UNPKinfo *info = (const UNPKinfo *) opaque;
+    const UNPKentry *entry = findEntry(info, filename, &isDir);
+
+    if (isDir)
+    {
+        *exists = 1;
+        stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+        stat->filesize = 0;
+    } /* if */
+    else if (entry != NULL)
+    {
+        *exists = 1;
+        stat->filetype = PHYSFS_FILETYPE_REGULAR;
+        stat->filesize = entry->size;
+    } /* else if */
+    else
+    {
+        *exists = 0;
+        return 0;
+    } /* else */
+
+    stat->modtime = -1;
+    stat->createtime = -1;
+    stat->accesstime = -1;
+    stat->readonly = 1;
+
+    return 1;
+} /* UNPK_stat */
+
+
+PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e,
+                             const PHYSFS_uint32 num)
+{
+    UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo));
+    if (info == NULL)
+    {
+        allocator.Free(e);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    __PHYSFS_sort(e, (size_t) num, entryCmp, entrySwap);
+    info->io = io;
+    info->entryCount = num;
+    info->entries = e;
+
+    return info;
+} /* UNPK_openArchive */
+
+/* end of archiver_unpacked.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_wad.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,127 @@
+/*
+ * WAD support routines for PhysicsFS.
+ *
+ * This driver handles DOOM engine archives ("wads"). 
+ * This format (but not this driver) was designed by id Software for use
+ *  with the DOOM engine.
+ * The specs of the format are from the unofficial doom specs v1.666
+ * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html
+ * The format of the archive: (from the specs)
+ *
+ *  A WAD file has three parts:
+ *  (1) a twelve-byte header
+ *  (2) one or more "lumps"
+ *  (3) a directory or "info table" that contains the names, offsets, and
+ *      sizes of all the lumps in the WAD
+ *
+ *  The header consists of three four-byte parts:
+ *    (a) an ASCII string which must be either "IWAD" or "PWAD"
+ *    (b) a 4-byte (long) integer which is the number of lumps in the wad
+ *    (c) a long integer which is the file offset to the start of
+ *    the directory
+ *
+ *  The directory has one 16-byte entry for every lump. Each entry consists
+ *  of three parts:
+ *
+ *    (a) a long integer, the file offset to the start of the lump
+ *    (b) a long integer, the size of the lump in bytes
+ *    (c) an 8-byte ASCII string, the name of the lump, padded with zeros.
+ *        For example, the "DEMO1" entry in hexadecimal would be
+ *        (44 45 4D 4F 31 00 00 00)
+ * 
+ * Note that there is no way to tell if an opened WAD archive is a
+ *  IWAD or PWAD with this archiver.
+ * I couldn't think of a way to provide that information, without being too
+ *  hacky.
+ * I don't think it's really that important though.
+ *
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ * This file written by Travis Wells, based on the GRP archiver by
+ *  Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_WAD
+
+static UNPKentry *wadLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount)
+{
+    PHYSFS_uint32 directoryOffset;
+    UNPKentry *entries = NULL;
+    UNPKentry *entry = NULL;
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &directoryOffset, 4), ERRPASS, 0);
+    directoryOffset = PHYSFS_swapULE32(directoryOffset);
+
+    BAIL_IF_MACRO(!io->seek(io, directoryOffset), ERRPASS, 0);
+
+    entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount);
+    BAIL_IF_MACRO(!entries, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    for (entry = entries; fileCount > 0; fileCount--, entry++)
+    {
+        if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed;
+        if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed;
+        if (!__PHYSFS_readAll(io, &entry->name, 8)) goto failed;
+
+        entry->name[8] = '\0'; /* name might not be null-terminated in file. */
+        entry->size = PHYSFS_swapULE32(entry->size);
+        entry->startPos = PHYSFS_swapULE32(entry->startPos);
+    } /* for */
+
+    return entries;
+
+failed:
+    allocator.Free(entries);
+    return NULL;
+} /* wadLoadEntries */
+
+
+static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    PHYSFS_uint8 buf[4];
+    UNPKentry *entries = NULL;
+    PHYSFS_uint32 count = 0;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL);
+    if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
+        BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL);
+
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof (count)), ERRPASS, NULL);
+    count = PHYSFS_swapULE32(count);
+
+    entries = wadLoadEntries(io, count);
+    BAIL_IF_MACRO(!entries, ERRPASS, NULL);
+    return UNPK_openArchive(io, entries, count);
+} /* WAD_openArchive */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
+{
+    {
+        "WAD",
+        "DOOM engine format",
+        "Travis Wells <traviswells@mchsi.com>",
+        "http://www.3dmm2.com/doom/",
+    },
+    WAD_openArchive,        /* openArchive() method    */
+    UNPK_enumerateFiles,     /* enumerateFiles() method */
+    UNPK_openRead,           /* openRead() method       */
+    UNPK_openWrite,          /* openWrite() method      */
+    UNPK_openAppend,         /* openAppend() method     */
+    UNPK_remove,             /* remove() method         */
+    UNPK_mkdir,              /* mkdir() method          */
+    UNPK_closeArchive,       /* closeArchive() method   */
+    UNPK_stat                /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_WAD */
+
+/* end of wad.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/archiver_zip.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,1717 @@
+/*
+ * ZIP support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon, with some peeking at "unzip.c"
+ *   by Gilles Vollant.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#if PHYSFS_SUPPORTS_ZIP
+
+#include <errno.h>
+#include <time.h>
+
+#define USE_MINIZ 1
+#if USE_MINIZ
+#include "physfs_miniz.h"
+#else
+#include <zlib.h>
+#endif
+
+/*
+ * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened,
+ *  and is freed when you close the file; compressed data is read into
+ *  this buffer, and then is decompressed into the buffer passed to
+ *  PHYSFS_read().
+ *
+ * Uncompressed entries in a zipfile do not allocate this buffer; they just
+ *  read data directly into the buffer passed to PHYSFS_read().
+ *
+ * Depending on your speed and memory requirements, you should tweak this
+ *  value.
+ */
+#define ZIP_READBUFSIZE   (16 * 1024)
+
+
+/*
+ * Entries are "unresolved" until they are first opened. At that time,
+ *  local file headers parsed/validated, data offsets will be updated to look
+ *  at the actual file data instead of the header, and symlinks will be
+ *  followed and optimized. This means that we don't seek and read around the
+ *  archive until forced to do so, and after the first time, we had to do
+ *  less reading and parsing, which is very CD-ROM friendly.
+ */
+typedef enum
+{
+    ZIP_UNRESOLVED_FILE,
+    ZIP_UNRESOLVED_SYMLINK,
+    ZIP_RESOLVING,
+    ZIP_RESOLVED,
+    ZIP_BROKEN_FILE,
+    ZIP_BROKEN_SYMLINK
+} ZipResolveType;
+
+
+/*
+ * One ZIPentry is kept for each file in an open ZIP archive.
+ */
+typedef struct _ZIPentry
+{
+    char *name;                         /* Name of file in archive        */
+    struct _ZIPentry *symlink;          /* NULL or file we symlink to     */
+    ZipResolveType resolved;            /* Have we resolved file/symlink? */
+    PHYSFS_uint64 offset;               /* offset of data in archive      */
+    PHYSFS_uint16 version;              /* version made by                */
+    PHYSFS_uint16 version_needed;       /* version needed to extract      */
+    PHYSFS_uint16 compression_method;   /* compression method             */
+    PHYSFS_uint32 crc;                  /* crc-32                         */
+    PHYSFS_uint64 compressed_size;      /* compressed size                */
+    PHYSFS_uint64 uncompressed_size;    /* uncompressed size              */
+    PHYSFS_sint64 last_mod_time;        /* last file mod time             */
+} ZIPentry;
+
+/*
+ * One ZIPinfo is kept for each open ZIP archive.
+ */
+typedef struct
+{
+    PHYSFS_Io *io;
+    int zip64;                /* non-zero if this is a Zip64 archive. */
+    PHYSFS_uint64 entryCount; /* Number of files in ZIP.              */
+    ZIPentry *entries;        /* info on all files in ZIP.            */
+} ZIPinfo;
+
+/*
+ * One ZIPfileinfo is kept for each open file in a ZIP archive.
+ */
+typedef struct
+{
+    ZIPentry *entry;                      /* Info on file.              */
+    PHYSFS_Io *io;                        /* physical file handle.      */
+    PHYSFS_uint32 compressed_position;    /* offset in compressed data. */
+    PHYSFS_uint32 uncompressed_position;  /* tell() position.           */
+    PHYSFS_uint8 *buffer;                 /* decompression buffer.      */
+    z_stream stream;                      /* zlib stream state.         */
+} ZIPfileinfo;
+
+
+/* Magic numbers... */
+#define ZIP_LOCAL_FILE_SIG                          0x04034b50
+#define ZIP_CENTRAL_DIR_SIG                         0x02014b50
+#define ZIP_END_OF_CENTRAL_DIR_SIG                  0x06054b50
+#define ZIP64_END_OF_CENTRAL_DIR_SIG                0x06064b50
+#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG  0x07064b50
+#define ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG         0x0001
+
+/* compression methods... */
+#define COMPMETH_NONE 0
+/* ...and others... */
+
+
+#define UNIX_FILETYPE_MASK    0170000
+#define UNIX_FILETYPE_SYMLINK 0120000
+
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size)
+{
+    return ((PHYSFS_Allocator *) opaque)->Malloc(items * size);
+} /* zlibPhysfsAlloc */
+
+/*
+ * Bridge physfs allocation functions to zlib's format...
+ */
+static void zlibPhysfsFree(voidpf opaque, voidpf address)
+{
+    ((PHYSFS_Allocator *) opaque)->Free(address);
+} /* zlibPhysfsFree */
+
+
+/*
+ * Construct a new z_stream to a sane state.
+ */
+static void initializeZStream(z_stream *pstr)
+{
+    memset(pstr, '\0', sizeof (z_stream));
+    pstr->zalloc = zlibPhysfsAlloc;
+    pstr->zfree = zlibPhysfsFree;
+    pstr->opaque = &allocator;
+} /* initializeZStream */
+
+
+static PHYSFS_ErrorCode zlib_error_code(int rc)
+{
+    switch (rc)
+    {
+        case Z_OK: return PHYSFS_ERR_OK;  /* not an error. */
+        case Z_STREAM_END: return PHYSFS_ERR_OK; /* not an error. */
+        case Z_ERRNO: return PHYSFS_ERR_IO;
+        case Z_MEM_ERROR: return PHYSFS_ERR_OUT_OF_MEMORY;
+        default: return PHYSFS_ERR_CORRUPT;
+    } /* switch */
+} /* zlib_error_string */
+
+
+/*
+ * Wrap all zlib calls in this, so the physfs error state is set appropriately.
+ */
+static int zlib_err(const int rc)
+{
+    __PHYSFS_setError(zlib_error_code(rc));
+    return rc;
+} /* zlib_err */
+
+
+/*
+ * Read an unsigned 64-bit int and swap to native byte order.
+ */
+static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val)
+{
+    PHYSFS_uint64 v;
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+    *val = PHYSFS_swapULE64(v);
+    return 1;
+} /* readui64 */
+
+/*
+ * Read an unsigned 32-bit int and swap to native byte order.
+ */
+static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
+{
+    PHYSFS_uint32 v;
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+    *val = PHYSFS_swapULE32(v);
+    return 1;
+} /* readui32 */
+
+
+/*
+ * Read an unsigned 16-bit int and swap to native byte order.
+ */
+static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val)
+{
+    PHYSFS_uint16 v;
+    BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0);
+    *val = PHYSFS_swapULE16(v);
+    return 1;
+} /* readui16 */
+
+
+static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
+    PHYSFS_Io *io = finfo->io;
+    ZIPentry *entry = finfo->entry;
+    PHYSFS_sint64 retval = 0;
+    PHYSFS_sint64 maxread = (PHYSFS_sint64) len;
+    PHYSFS_sint64 avail = entry->uncompressed_size -
+                          finfo->uncompressed_position;
+
+    if (avail < maxread)
+        maxread = avail;
+
+    BAIL_IF_MACRO(maxread == 0, ERRPASS, 0);    /* quick rejection. */
+
+    if (entry->compression_method == COMPMETH_NONE)
+        retval = io->read(io, buf, maxread);
+    else
+    {
+        finfo->stream.next_out = buf;
+        finfo->stream.avail_out = (uInt) maxread;
+
+        while (retval < maxread)
+        {
+            PHYSFS_uint32 before = finfo->stream.total_out;
+            int rc;
+
+            if (finfo->stream.avail_in == 0)
+            {
+                PHYSFS_sint64 br;
+
+                br = entry->compressed_size - finfo->compressed_position;
+                if (br > 0)
+                {
+                    if (br > ZIP_READBUFSIZE)
+                        br = ZIP_READBUFSIZE;
+
+                    br = io->read(io, finfo->buffer, (PHYSFS_uint64) br);
+                    if (br <= 0)
+                        break;
+
+                    finfo->compressed_position += (PHYSFS_uint32) br;
+                    finfo->stream.next_in = finfo->buffer;
+                    finfo->stream.avail_in = (PHYSFS_uint32) br;
+                } /* if */
+            } /* if */
+
+            rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH));
+            retval += (finfo->stream.total_out - before);
+
+            if (rc != Z_OK)
+                break;
+        } /* while */
+    } /* else */
+
+    if (retval > 0)
+        finfo->uncompressed_position += (PHYSFS_uint32) retval;
+
+    return retval;
+} /* ZIP_read */
+
+
+static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1);
+} /* ZIP_write */
+
+
+static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io)
+{
+    return ((ZIPfileinfo *) io->opaque)->uncompressed_position;
+} /* ZIP_tell */
+
+
+static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque;
+    ZIPentry *entry = finfo->entry;
+    PHYSFS_Io *io = finfo->io;
+
+    BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0);
+
+    if (entry->compression_method == COMPMETH_NONE)
+    {
+        const PHYSFS_sint64 newpos = offset + entry->offset;
+        BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0);
+        finfo->uncompressed_position = (PHYSFS_uint32) offset;
+    } /* if */
+
+    else
+    {
+        /*
+         * If seeking backwards, we need to redecode the file
+         *  from the start and throw away the compressed bits until we hit
+         *  the offset we need. If seeking forward, we still need to
+         *  decode, but we don't rewind first.
+         */
+        if (offset < finfo->uncompressed_position)
+        {
+            /* we do a copy so state is sane if inflateInit2() fails. */
+            z_stream str;
+            initializeZStream(&str);
+            if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK)
+                return 0;
+
+            if (!io->seek(io, entry->offset))
+                return 0;
+
+            inflateEnd(&finfo->stream);
+            memcpy(&finfo->stream, &str, sizeof (z_stream));
+            finfo->uncompressed_position = finfo->compressed_position = 0;
+        } /* if */
+
+        while (finfo->uncompressed_position != offset)
+        {
+            PHYSFS_uint8 buf[512];
+            PHYSFS_uint32 maxread;
+
+            maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position);
+            if (maxread > sizeof (buf))
+                maxread = sizeof (buf);
+
+            if (ZIP_read(_io, buf, maxread) != maxread)
+                return 0;
+        } /* while */
+    } /* else */
+
+    return 1;
+} /* ZIP_seek */
+
+
+static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io)
+{
+    const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
+    return (PHYSFS_sint64) finfo->entry->uncompressed_size;
+} /* ZIP_length */
+
+
+static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry);
+
+static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
+{
+    ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque;
+    PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
+    GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+    GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+    memset(finfo, '\0', sizeof (*finfo));
+
+    finfo->entry = origfinfo->entry;
+    finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
+    GOTO_IF_MACRO(!finfo->io, ERRPASS, failed);
+
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+    {
+        finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
+        GOTO_IF_MACRO(!finfo->buffer, PHYSFS_ERR_OUT_OF_MEMORY, failed);
+        if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
+            goto failed;
+    } /* if */
+
+    memcpy(retval, io, sizeof (PHYSFS_Io));
+    retval->opaque = finfo;
+    return retval;
+
+failed:
+    if (finfo != NULL)
+    {
+        if (finfo->io != NULL)
+            finfo->io->destroy(finfo->io);
+
+        if (finfo->buffer != NULL)
+        {
+            allocator.Free(finfo->buffer);
+            inflateEnd(&finfo->stream);
+        } /* if */
+
+        allocator.Free(finfo);
+    } /* if */
+
+    if (retval != NULL)
+        allocator.Free(retval);
+
+    return NULL;
+} /* ZIP_duplicate */
+
+static int ZIP_flush(PHYSFS_Io *io) { return 1;  /* no write support. */ }
+
+static void ZIP_destroy(PHYSFS_Io *io)
+{
+    ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque;
+    finfo->io->destroy(finfo->io);
+
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+        inflateEnd(&finfo->stream);
+
+    if (finfo->buffer != NULL)
+        allocator.Free(finfo->buffer);
+
+    allocator.Free(finfo);
+    allocator.Free(io);
+} /* ZIP_destroy */
+
+
+static const PHYSFS_Io ZIP_Io =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    ZIP_read,
+    ZIP_write,
+    ZIP_seek,
+    ZIP_tell,
+    ZIP_length,
+    ZIP_duplicate,
+    ZIP_flush,
+    ZIP_destroy
+};
+
+
+
+static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len)
+{
+    PHYSFS_uint8 buf[256];
+    PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 };
+    PHYSFS_sint32 i = 0;
+    PHYSFS_sint64 filelen;
+    PHYSFS_sint64 filepos;
+    PHYSFS_sint32 maxread;
+    PHYSFS_sint32 totalread = 0;
+    int found = 0;
+
+    filelen = io->length(io);
+    BAIL_IF_MACRO(filelen == -1, ERRPASS, 0);
+
+    /*
+     * Jump to the end of the file and start reading backwards.
+     *  The last thing in the file is the zipfile comment, which is variable
+     *  length, and the field that specifies its size is before it in the
+     *  file (argh!)...this means that we need to scan backwards until we
+     *  hit the end-of-central-dir signature. We can then sanity check that
+     *  the comment was as big as it should be to make sure we're in the
+     *  right place. The comment length field is 16 bits, so we can stop
+     *  searching for that signature after a little more than 64k at most,
+     *  and call it a corrupted zipfile.
+     */
+
+    if (sizeof (buf) < filelen)
+    {
+        filepos = filelen - sizeof (buf);
+        maxread = sizeof (buf);
+    } /* if */
+    else
+    {
+        filepos = 0;
+        maxread = (PHYSFS_uint32) filelen;
+    } /* else */
+
+    while ((totalread < filelen) && (totalread < 65557))
+    {
+        BAIL_IF_MACRO(!io->seek(io, filepos), ERRPASS, -1);
+
+        /* make sure we catch a signature between buffers. */
+        if (totalread != 0)
+        {
+            if (!__PHYSFS_readAll(io, buf, maxread - 4))
+                return -1;
+            memcpy(&buf[maxread - 4], &extra, sizeof (extra));
+            totalread += maxread - 4;
+        } /* if */
+        else
+        {
+            if (!__PHYSFS_readAll(io, buf, maxread))
+                return -1;
+            totalread += maxread;
+        } /* else */
+
+        memcpy(&extra, buf, sizeof (extra));
+
+        for (i = maxread - 4; i > 0; i--)
+        {
+            if ((buf[i + 0] == 0x50) &&
+                (buf[i + 1] == 0x4B) &&
+                (buf[i + 2] == 0x05) &&
+                (buf[i + 3] == 0x06) )
+            {
+                found = 1;  /* that's the signature! */
+                break;  
+            } /* if */
+        } /* for */
+
+        if (found)
+            break;
+
+        filepos -= (maxread - 4);
+        if (filepos < 0)
+            filepos = 0;
+    } /* while */
+
+    BAIL_IF_MACRO(!found, PHYSFS_ERR_UNSUPPORTED, -1);
+
+    if (len != NULL)
+        *len = filelen;
+
+    return (filepos + i);
+} /* zip_find_end_of_central_dir */
+
+
+static int isZip(PHYSFS_Io *io)
+{
+    PHYSFS_uint32 sig = 0;
+    int retval = 0;
+
+    /*
+     * The first thing in a zip file might be the signature of the
+     *  first local file record, so it makes for a quick determination.
+     */
+    if (readui32(io, &sig))
+    {
+        retval = (sig == ZIP_LOCAL_FILE_SIG);
+        if (!retval)
+        {
+            /*
+             * No sig...might be a ZIP with data at the start
+             *  (a self-extracting executable, etc), so we'll have to do
+             *  it the hard way...
+             */
+            retval = (zip_find_end_of_central_dir(io, NULL) != -1);
+        } /* if */
+    } /* if */
+
+    return retval;
+} /* isZip */
+
+
+static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max)
+{
+    PHYSFS_uint64 i;
+    for (i = 0; i < max; i++)
+    {
+        ZIPentry *entry = &entries[i];
+        if (entry->name != NULL)
+            allocator.Free(entry->name);
+    } /* for */
+
+    allocator.Free(entries);
+} /* zip_free_entries */
+
+
+/*
+ * This will find the ZIPentry associated with a path in platform-independent
+ *  notation. Directories don't have ZIPentries associated with them, but 
+ *  (*isDir) will be set to non-zero if a dir was hit.
+ */
+static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
+                                int *isDir)
+{
+    ZIPentry *a = info->entries;
+    PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path);
+    PHYSFS_sint64 lo = 0;
+    PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
+    PHYSFS_sint64 middle;
+    const char *thispath = NULL;
+    int rc;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        thispath = a[middle].name;
+        rc = strncmp(path, thispath, pathlen);
+
+        if (rc > 0)
+            lo = middle + 1;
+
+        else if (rc < 0)
+            hi = middle - 1;
+
+        else /* substring match...might be dir or entry or nothing. */
+        {
+            if (isDir != NULL)
+            {
+                *isDir = (thispath[pathlen] == '/');
+                if (*isDir)
+                    return NULL;
+            } /* if */
+
+            if (thispath[pathlen] == '\0') /* found entry? */
+                return &a[middle];
+            /* adjust search params, try again. */
+            else if (thispath[pathlen] > '/')
+                hi = middle - 1;
+            else
+                lo = middle + 1;
+        } /* if */
+    } /* while */
+
+    if (isDir != NULL)
+        *isDir = 0;
+
+    BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL);
+} /* zip_find_entry */
+
+
+/* Convert paths from old, buggy DOS zippers... */
+static void zip_convert_dos_path(ZIPentry *entry, char *path)
+{
+    PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF);
+    if (hosttype == 0)  /* FS_FAT_ */
+    {
+        while (*path)
+        {
+            if (*path == '\\')
+                *path = '/';
+            path++;
+        } /* while */
+    } /* if */
+} /* zip_convert_dos_path */
+
+
+static void zip_expand_symlink_path(char *path)
+{
+    char *ptr = path;
+    char *prevptr = path;
+
+    while (1)
+    {
+        ptr = strchr(ptr, '/');
+        if (ptr == NULL)
+            break;
+
+        if (*(ptr + 1) == '.')
+        {
+            if (*(ptr + 2) == '/')
+            {
+                /* current dir in middle of string: ditch it. */
+                memmove(ptr, ptr + 2, strlen(ptr + 2) + 1);
+            } /* else if */
+
+            else if (*(ptr + 2) == '\0')
+            {
+                /* current dir at end of string: ditch it. */
+                *ptr = '\0';
+            } /* else if */
+
+            else if (*(ptr + 2) == '.')
+            {
+                if (*(ptr + 3) == '/')
+                {
+                    /* parent dir in middle: move back one, if possible. */
+                    memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1);
+                    ptr = prevptr;
+                    while (prevptr != path)
+                    {
+                        prevptr--;
+                        if (*prevptr == '/')
+                        {
+                            prevptr++;
+                            break;
+                        } /* if */
+                    } /* while */
+                } /* if */
+
+                if (*(ptr + 3) == '\0')
+                {
+                    /* parent dir at end: move back one, if possible. */
+                    *prevptr = '\0';
+                } /* if */
+            } /* if */
+        } /* if */
+        else
+        {
+            prevptr = ptr;
+            ptr++;
+        } /* else */
+    } /* while */
+} /* zip_expand_symlink_path */
+
+/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */
+static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry);
+
+/*
+ * Look for the entry named by (path). If it exists, resolve it, and return
+ *  a pointer to that entry. If it's another symlink, keep resolving until you
+ *  hit a real file and then return a pointer to the final non-symlink entry.
+ *  If there's a problem, return NULL.
+ */
+static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path)
+{
+    ZIPentry *entry;
+
+    zip_expand_symlink_path(path);
+    entry = zip_find_entry(info, path, NULL);
+    if (entry != NULL)
+    {
+        if (!zip_resolve(io, info, entry))  /* recursive! */
+            entry = NULL;
+        else
+        {
+            if (entry->symlink != NULL)
+                entry = entry->symlink;
+        } /* else */
+    } /* if */
+
+    return entry;
+} /* zip_follow_symlink */
+
+
+static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
+{
+    const PHYSFS_uint64 size = entry->uncompressed_size;
+    char *path = NULL;
+    int rc = 0;
+
+    /*
+     * We've already parsed the local file header of the symlink at this
+     *  point. Now we need to read the actual link from the file data and
+     *  follow it.
+     */
+
+    BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
+
+    path = (char *) __PHYSFS_smallAlloc(size + 1);
+    BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    
+    if (entry->compression_method == COMPMETH_NONE)
+        rc = __PHYSFS_readAll(io, path, size);
+
+    else  /* symlink target path is compressed... */
+    {
+        z_stream stream;
+        const PHYSFS_uint64 complen = entry->compressed_size;
+        PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen);
+        if (compressed != NULL)
+        {
+            if (__PHYSFS_readAll(io, compressed, complen))
+            {
+                initializeZStream(&stream);
+                stream.next_in = compressed;
+                stream.avail_in = complen;
+                stream.next_out = (unsigned char *) path;
+                stream.avail_out = size;
+                if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK)
+                {
+                    rc = zlib_err(inflate(&stream, Z_FINISH));
+                    inflateEnd(&stream);
+
+                    /* both are acceptable outcomes... */
+                    rc = ((rc == Z_OK) || (rc == Z_STREAM_END));
+                } /* if */
+            } /* if */
+            __PHYSFS_smallFree(compressed);
+        } /* if */
+    } /* else */
+
+    if (rc)
+    {
+        path[entry->uncompressed_size] = '\0';    /* null-terminate it. */
+        zip_convert_dos_path(entry, path);
+        entry->symlink = zip_follow_symlink(io, info, path);
+    } /* else */
+
+    __PHYSFS_smallFree(path);
+
+    return (entry->symlink != NULL);
+} /* zip_resolve_symlink */
+
+
+/*
+ * Parse the local file header of an entry, and update entry->offset.
+ */
+static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry)
+{
+    PHYSFS_uint32 ui32;
+    PHYSFS_uint16 ui16;
+    PHYSFS_uint16 fnamelen;
+    PHYSFS_uint16 extralen;
+
+    /*
+     * crc and (un)compressed_size are always zero if this is a "JAR"
+     *  archive created with Sun's Java tools, apparently. We only
+     *  consider this archive corrupted if those entries don't match and
+     *  aren't zero. That seems to work well.
+     * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's
+     *  possible that's a Zip64 thing.
+     */
+
+    BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0);
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+    BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0);
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* general bits. */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+    BAIL_IF_MACRO(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0);
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);  /* date/time */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), PHYSFS_ERR_CORRUPT, 0);
+
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
+                  (ui32 != entry->compressed_size), PHYSFS_ERR_CORRUPT, 0);
+
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) &&
+                 (ui32 != entry->uncompressed_size), PHYSFS_ERR_CORRUPT, 0);
+
+    BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
+
+    entry->offset += fnamelen + extralen + 30;
+    return 1;
+} /* zip_parse_local */
+
+
+static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry)
+{
+    int retval = 1;
+    ZipResolveType resolve_type = entry->resolved;
+
+    /* Don't bother if we've failed to resolve this entry before. */
+    BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0);
+    BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0);
+
+    /* uhoh...infinite symlink loop! */
+    BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, PHYSFS_ERR_SYMLINK_LOOP, 0);
+
+    /*
+     * We fix up the offset to point to the actual data on the
+     *  first open, since we don't want to seek across the whole file on
+     *  archive open (can be SLOW on large, CD-stored files), but we
+     *  need to check the local file header...not just for corruption,
+     *  but since it stores offset info the central directory does not.
+     */
+    if (resolve_type != ZIP_RESOLVED)
+    {
+        entry->resolved = ZIP_RESOLVING;
+
+        retval = zip_parse_local(io, entry);
+        if (retval)
+        {
+            /*
+             * If it's a symlink, find the original file. This will cause
+             *  resolution of other entries (other symlinks and, eventually,
+             *  the real file) if all goes well.
+             */
+            if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
+                retval = zip_resolve_symlink(io, info, entry);
+        } /* if */
+
+        if (resolve_type == ZIP_UNRESOLVED_SYMLINK)
+            entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK);
+        else if (resolve_type == ZIP_UNRESOLVED_FILE)
+            entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE);
+    } /* if */
+
+    return retval;
+} /* zip_resolve */
+
+
+static int zip_version_does_symlinks(PHYSFS_uint32 version)
+{
+    int retval = 0;
+    PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF);
+
+    switch (hosttype)
+    {
+            /*
+             * These are the platforms that can NOT build an archive with
+             *  symlinks, according to the Info-ZIP project.
+             */
+        case 0:  /* FS_FAT_  */
+        case 1:  /* AMIGA_   */
+        case 2:  /* VMS_     */
+        case 4:  /* VM_CSM_  */
+        case 6:  /* FS_HPFS_ */
+        case 11: /* FS_NTFS_ */
+        case 14: /* FS_VFAT_ */
+        case 13: /* ACORN_   */
+        case 15: /* MVS_     */
+        case 18: /* THEOS_   */
+            break;  /* do nothing. */
+
+        default:  /* assume the rest to be unix-like. */
+            retval = 1;
+            break;
+    } /* switch */
+
+    return retval;
+} /* zip_version_does_symlinks */
+
+
+static int zip_entry_is_symlink(const ZIPentry *entry)
+{
+    return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) ||
+            (entry->resolved == ZIP_BROKEN_SYMLINK) ||
+            (entry->symlink));
+} /* zip_entry_is_symlink */
+
+
+static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr)
+{
+    PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF);
+    return ( (zip_version_does_symlinks(entry->version)) &&
+             (entry->uncompressed_size > 0) &&
+             ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK) );
+} /* zip_has_symlink_attr */
+
+
+static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime)
+{
+    PHYSFS_uint32 dosdate;
+    struct tm unixtime;
+    memset(&unixtime, '\0', sizeof (unixtime));
+
+    dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF);
+    dostime &= 0xFFFF;
+
+    /* dissect date */
+    unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80;
+    unixtime.tm_mon  = ((dosdate >> 5) & 0x0F) - 1;
+    unixtime.tm_mday = ((dosdate     ) & 0x1F);
+
+    /* dissect time */
+    unixtime.tm_hour = ((dostime >> 11) & 0x1F);
+    unixtime.tm_min  = ((dostime >>  5) & 0x3F);
+    unixtime.tm_sec  = ((dostime <<  1) & 0x3E);
+
+    /* let mktime calculate daylight savings time. */
+    unixtime.tm_isdst = -1;
+
+    return ((PHYSFS_sint64) mktime(&unixtime));
+} /* zip_dos_time_to_physfs_time */
+
+
+static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry,
+                          PHYSFS_uint64 ofs_fixup)
+{
+    PHYSFS_uint16 fnamelen, extralen, commentlen;
+    PHYSFS_uint32 external_attr;
+    PHYSFS_uint32 starting_disk;
+    PHYSFS_uint64 offset;
+    PHYSFS_uint16 ui16;
+    PHYSFS_uint32 ui32;
+    PHYSFS_sint64 si64;
+
+    /* sanity check with central directory signature... */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+    /* Get the pertinent parts of the record... */
+    BAIL_IF_MACRO(!readui16(io, &entry->version), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui16(io, &entry->version_needed), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* general bits */
+    BAIL_IF_MACRO(!readui16(io, &entry->compression_method), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    entry->last_mod_time = zip_dos_time_to_physfs_time(ui32);
+    BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    entry->compressed_size = (PHYSFS_uint64) ui32;
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    entry->uncompressed_size = (PHYSFS_uint64) ui32;
+    BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+    starting_disk = (PHYSFS_uint32) ui16;
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);  /* internal file attribs */
+    BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0);
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    offset = (PHYSFS_uint64) ui32;
+
+    entry->symlink = NULL;  /* will be resolved later, if necessary. */
+    entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ?
+                            ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE;
+
+    entry->name = (char *) allocator.Malloc(fnamelen + 1);
+    BAIL_IF_MACRO(entry->name == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    if (!__PHYSFS_readAll(io, entry->name, fnamelen))
+        goto zip_load_entry_puked;
+
+    entry->name[fnamelen] = '\0';  /* null-terminate the filename. */
+    zip_convert_dos_path(entry, entry->name);
+
+    si64 = io->tell(io);
+    if (si64 == -1)
+        goto zip_load_entry_puked;
+
+    /*
+     * The actual sizes didn't fit in 32-bits; look for the Zip64
+     *  extended information extra field...
+     */
+    if ( (zip64) &&
+         ((offset == 0xFFFFFFFF) ||
+          (starting_disk == 0xFFFFFFFF) ||
+          (entry->compressed_size == 0xFFFFFFFF) ||
+          (entry->uncompressed_size == 0xFFFFFFFF)) )
+    {
+        int found = 0;
+        PHYSFS_uint16 sig, len;
+        while (extralen > 4)
+        {
+            if (!readui16(io, &sig))
+                goto zip_load_entry_puked;
+            else if (!readui16(io, &len))
+                goto zip_load_entry_puked;
+
+            si64 += 4 + len;
+            extralen -= 4 + len;
+            if (sig != ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG)
+            {
+                if (!io->seek(io, si64))
+                    goto zip_load_entry_puked;
+                continue;
+            } /* if */
+
+            found = 1;
+            break;
+        } /* while */
+
+        GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+
+        if (entry->uncompressed_size == 0xFFFFFFFF)
+        {
+            GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+            if (!readui64(io, &entry->uncompressed_size))
+                goto zip_load_entry_puked;
+            len -= 8;
+        } /* if */
+
+        if (entry->compressed_size == 0xFFFFFFFF)
+        {
+            GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+            if (!readui64(io, &entry->compressed_size))
+                goto zip_load_entry_puked;
+            len -= 8;
+        } /* if */
+
+        if (offset == 0xFFFFFFFF)
+        {
+            GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+            if (!readui64(io, &offset))
+                goto zip_load_entry_puked;
+            len -= 8;
+        } /* if */
+
+        if (starting_disk == 0xFFFFFFFF)
+        {
+            GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+            if (!readui32(io, &starting_disk))
+                goto zip_load_entry_puked;
+            len -= 4;
+        } /* if */
+
+        GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+    } /* if */
+
+    GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked);
+
+    entry->offset = offset + ofs_fixup;
+
+    /* seek to the start of the next entry in the central directory... */
+    if (!io->seek(io, si64 + extralen + commentlen))
+        goto zip_load_entry_puked;
+
+    return 1;  /* success. */
+
+zip_load_entry_puked:
+    allocator.Free(entry->name);
+    return 0;  /* failure. */
+} /* zip_load_entry */
+
+
+static int zip_entry_cmp(void *_a, size_t one, size_t two)
+{
+    if (one != two)
+    {
+        const ZIPentry *a = (const ZIPentry *) _a;
+        return strcmp(a[one].name, a[two].name);
+    } /* if */
+
+    return 0;
+} /* zip_entry_cmp */
+
+
+static void zip_entry_swap(void *_a, size_t one, size_t two)
+{
+    if (one != two)
+    {
+        ZIPentry tmp;
+        ZIPentry *first = &(((ZIPentry *) _a)[one]);
+        ZIPentry *second = &(((ZIPentry *) _a)[two]);
+        memcpy(&tmp, first, sizeof (ZIPentry));
+        memcpy(first, second, sizeof (ZIPentry));
+        memcpy(second, &tmp, sizeof (ZIPentry));
+    } /* if */
+} /* zip_entry_swap */
+
+
+static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info,
+                            const PHYSFS_uint64 data_ofs,
+                            const PHYSFS_uint64 central_ofs)
+{
+    const PHYSFS_uint64 max = info->entryCount;
+    const int zip64 = info->zip64;
+    PHYSFS_uint64 i;
+
+    BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0);
+
+    info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max);
+    BAIL_IF_MACRO(!info->entries, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+    for (i = 0; i < max; i++)
+    {
+        if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs))
+        {
+            zip_free_entries(info->entries, i);
+            return 0;
+        } /* if */
+    } /* for */
+
+    __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap);
+    return 1;
+} /* zip_load_entries */
+
+
+static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io,
+                                                   PHYSFS_sint64 _pos,
+                                                   PHYSFS_uint64 offset)
+{
+    /*
+     * Naturally, the offset is useless to us; it is the offset from the
+     *  start of file, which is meaningless if we've appended this .zip to
+     *  a self-extracting .exe. We need to find this on our own. It should
+     *  be directly before the locator record, but the record in question,
+     *  like the original end-of-central-directory record, ends with a
+     *  variable-length field. Unlike the original, which has to store the
+     *  size of that variable-length field in a 16-bit int and thus has to be
+     *  within 64k, the new one gets 64-bits.
+     *
+     * Fortunately, the only currently-specified record for that variable
+     *  length block is some weird proprietary thing that deals with EBCDIC
+     *  and tape backups or something. So we don't seek far.
+     */
+
+    PHYSFS_uint32 ui32;
+    const PHYSFS_uint64 pos = (PHYSFS_uint64) _pos;
+
+    assert(_pos > 0);
+
+    /* Try offset specified in the Zip64 end of central directory locator. */
+    /* This works if the entire PHYSFS_Io is the zip file. */
+    BAIL_IF_MACRO(!io->seek(io, offset), ERRPASS, -1);
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+    if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+        return offset;
+
+    /* Try 56 bytes before the Zip64 end of central directory locator. */
+    /* This works if the record isn't variable length and is version 1. */
+    if (pos > 56)
+    {
+        BAIL_IF_MACRO(!io->seek(io, pos-56), ERRPASS, -1);
+        BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+        if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+            return pos-56;
+    } /* if */
+
+    /* Try 84 bytes before the Zip64 end of central directory locator. */
+    /* This works if the record isn't variable length and is version 2. */
+    if (pos > 84)
+    {
+        BAIL_IF_MACRO(!io->seek(io, pos-84), ERRPASS, -1);
+        BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1);
+        if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG)
+            return pos-84;
+    } /* if */
+
+    /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */
+    /*  Just try moving back at most 256k. Oh well. */
+    if ((offset < pos) && (pos > 4))
+    {
+        /* we assume you can eat this stack if you handle Zip64 files. */
+        PHYSFS_uint8 buf[256 * 1024];
+        PHYSFS_uint64 len = pos - offset;
+        PHYSFS_sint32 i;
+
+        if (len > sizeof (buf))
+            len = sizeof (buf);
+
+        BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1);
+        BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1);
+        for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--)
+        {
+            if (buf[i] != 0x50)
+                continue;
+            if ( (buf[i+1] == 0x4b) &&
+                 (buf[i+2] == 0x06) &&
+                 (buf[i+3] == 0x06) )
+                return pos - (len - i);
+        } /* for */
+    } /* if */
+
+    BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1);  /* didn't find it. */
+} /* zip64_find_end_of_central_dir */
+
+
+static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
+                                          PHYSFS_uint64 *data_start,
+                                          PHYSFS_uint64 *dir_ofs,
+                                          PHYSFS_sint64 pos)
+{
+    PHYSFS_uint64 ui64;
+    PHYSFS_uint32 ui32;
+    PHYSFS_uint16 ui16;
+
+    /* We should be positioned right past the locator signature. */
+
+    if ((pos < 0) || (!io->seek(io, pos)))
+        return 0;
+
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    if (ui32 != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG)
+        return -1;  /* it's not a Zip64 archive. Not an error, though! */
+
+    info->zip64 = 1;
+
+    /* number of the disk with the start of the central directory. */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+    /* offset of Zip64 end of central directory record. */
+    BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+    /* total number of disks */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != 1, PHYSFS_ERR_CORRUPT, 0);
+
+    pos = zip64_find_end_of_central_dir(io, pos, ui64);
+    if (pos < 0)
+        return 0;  /* oh well. */
+
+    /*
+     * For self-extracting archives, etc, there's crapola in the file
+     *  before the zipfile records; we calculate how much data there is
+     *  prepended by determining how far the zip64-end-of-central-directory
+     *  offset is from where it is supposed to be...the difference in bytes
+     *  is how much arbitrary data is at the start of the physical file.
+     */
+    assert(((PHYSFS_uint64) pos) >= ui64);
+    *data_start = ((PHYSFS_uint64) pos) - ui64;
+
+    BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
+
+    /* check signature again, just in case. */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != ZIP64_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+    /* size of Zip64 end of central directory record. */
+    BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+    /* version made by. */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+    /* version needed to extract. */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+    /* number of this disk. */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+    /* number of disk with start of central directory record. */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+    /* total number of entries in the central dir on this disk */
+    BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+    /* total number of entries in the central dir */
+    BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0);
+    BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0);
+
+    /* size of the central directory */
+    BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0);
+
+    /* offset of central directory */
+    BAIL_IF_MACRO(!readui64(io, dir_ofs), ERRPASS, 0);
+
+    /* Since we know the difference, fix up the central dir offset... */
+    *dir_ofs += *data_start;
+
+    /*
+     * There are more fields here, for encryption and feature-specific things,
+     *  but we don't care about any of them at the moment.
+     */
+
+    return 1;  /* made it. */
+} /* zip64_parse_end_of_central_dir */
+
+
+static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info,
+                                        PHYSFS_uint64 *data_start,
+                                        PHYSFS_uint64 *dir_ofs)
+{
+    PHYSFS_uint16 entryCount16;
+    PHYSFS_uint32 offset32;
+    PHYSFS_uint32 ui32;
+    PHYSFS_uint16 ui16;
+    PHYSFS_sint64 len;
+    PHYSFS_sint64 pos;
+    int rc;
+
+    /* find the end-of-central-dir record, and seek to it. */
+    pos = zip_find_end_of_central_dir(io, &len);
+    BAIL_IF_MACRO(pos == -1, ERRPASS, 0);
+    BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0);
+
+    /* check signature again, just in case. */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+    BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0);
+
+    /* Seek back to see if "Zip64 end of central directory locator" exists. */
+    /* this record is 20 bytes before end-of-central-dir */
+    rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20);
+    BAIL_IF_MACRO(rc == 0, ERRPASS, 0);
+    if (rc == 1)
+        return 1;  /* we're done here. */
+
+    assert(rc == -1);  /* no error, just not a Zip64 archive. */
+
+    /* Not Zip64? Seek back to where we were and keep processing. */
+    BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0);
+
+    /* number of this disk */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+    BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+    /* number of the disk with the start of the central directory */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+    BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0);
+
+    /* total number of entries in the central dir on this disk */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+    /* total number of entries in the central dir */
+    BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0);
+    BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0);
+
+    info->entryCount = entryCount16;
+
+    /* size of the central directory */
+    BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0);
+
+    /* offset of central directory */
+    BAIL_IF_MACRO(!readui32(io, &offset32), ERRPASS, 0);
+    *dir_ofs = (PHYSFS_uint64) offset32;
+    BAIL_IF_MACRO(pos < (*dir_ofs + ui32), PHYSFS_ERR_CORRUPT, 0);
+
+    /*
+     * For self-extracting archives, etc, there's crapola in the file
+     *  before the zipfile records; we calculate how much data there is
+     *  prepended by determining how far the central directory offset is
+     *  from where it is supposed to be (start of end-of-central-dir minus
+     *  sizeof central dir)...the difference in bytes is how much arbitrary
+     *  data is at the start of the physical file.
+     */
+    *data_start = (PHYSFS_uint64) (pos - (*dir_ofs + ui32));
+
+    /* Now that we know the difference, fix up the central dir offset... */
+    *dir_ofs += *data_start;
+
+    /* zipfile comment length */
+    BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0);
+
+    /*
+     * Make sure that the comment length matches to the end of file...
+     *  If it doesn't, we're either in the wrong part of the file, or the
+     *  file is corrupted, but we give up either way.
+     */
+    BAIL_IF_MACRO((pos + 22 + ui16) != len, PHYSFS_ERR_CORRUPT, 0);
+
+    return 1;  /* made it. */
+} /* zip_parse_end_of_central_dir */
+
+
+static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
+{
+    ZIPinfo *info = NULL;
+    PHYSFS_uint64 data_start;
+    PHYSFS_uint64 cent_dir_ofs;
+
+    assert(io != NULL);  /* shouldn't ever happen. */
+
+    BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
+    BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL);
+
+    info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
+    BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    memset(info, '\0', sizeof (ZIPinfo));
+    info->io = io;
+
+    if (!zip_parse_end_of_central_dir(io, info, &data_start, &cent_dir_ofs))
+        goto ZIP_openarchive_failed;
+
+    if (!zip_load_entries(io, info, data_start, cent_dir_ofs))
+        goto ZIP_openarchive_failed;
+
+    return info;
+
+ZIP_openarchive_failed:
+    if (info != NULL)
+        allocator.Free(info);
+
+    return NULL;
+} /* ZIP_openArchive */
+
+
+static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path,
+                                            int stop_on_first_find)
+{
+    PHYSFS_sint64 lo = 0;
+    PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1);
+    PHYSFS_sint64 middle;
+    PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path);
+    PHYSFS_sint64 retval = -1;
+    const char *name;
+    int rc;
+
+    if (*path == '\0')  /* root dir? */
+        return 0;
+
+    if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    while (lo <= hi)
+    {
+        middle = lo + ((hi - lo) / 2);
+        name = info->entries[middle].name;
+        rc = strncmp(path, name, dlen);
+        if (rc == 0)
+        {
+            char ch = name[dlen];
+            if ('/' < ch) /* make sure this isn't just a substr match. */
+                rc = -1;
+            else if ('/' > ch)
+                rc = 1;
+            else 
+            {
+                if (stop_on_first_find) /* Just checking dir's existance? */
+                    return middle;
+
+                if (name[dlen + 1] == '\0') /* Skip initial dir entry. */
+                    return (middle + 1);
+
+                /* there might be more entries earlier in the list. */
+                retval = middle;
+                hi = middle - 1;
+            } /* else */
+        } /* if */
+
+        if (rc > 0)
+            lo = middle + 1;
+        else
+            hi = middle - 1;
+    } /* while */
+
+    return retval;
+} /* zip_find_start_of_dir */
+
+
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata,
+                           const char *odir, const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = __PHYSFS_smallAlloc(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, odir, newstr);
+    __PHYSFS_smallFree(newstr);
+} /* doEnumCallback */
+
+
+static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                               const char *origdir, void *callbackdata)
+{
+    ZIPinfo *info = ((ZIPinfo *) opaque);
+    PHYSFS_sint32 dlen, dlen_inc;
+    PHYSFS_sint64 i, max;
+
+    i = zip_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
+
+    dlen = (PHYSFS_sint32) strlen(dname);
+    if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
+        dlen--;
+
+    dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
+    max = (PHYSFS_sint64) info->entryCount;
+    while (i < max)
+    {
+        char *e = info->entries[i].name;
+        if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
+            break;  /* past end of this dir; we're done. */
+
+        if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
+            i++;
+        else
+        {
+            char *add = e + dlen_inc;
+            char *ptr = strchr(add, '/');
+            PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
+            doEnumCallback(cb, callbackdata, origdir, add, ln);
+            ln += dlen_inc;  /* point past entry to children... */
+
+            /* increment counter and skip children of subdirs... */
+            while ((++i < max) && (ptr != NULL))
+            {
+                char *e_new = info->entries[i].name;
+                if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/'))
+                    break;
+            } /* while */
+        } /* else */
+    } /* while */
+} /* ZIP_enumerateFiles */
+
+
+static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
+{
+    int success;
+    PHYSFS_Io *retval = io->duplicate(io);
+    BAIL_IF_MACRO(!retval, ERRPASS, NULL);
+
+    /* !!! FIXME: if you open a dir here, it should bail ERR_NOT_A_FILE */
+
+    /* (inf) can be NULL if we already resolved. */
+    success = (inf == NULL) || zip_resolve(retval, inf, entry);
+    if (success)
+    {
+        PHYSFS_sint64 offset;
+        offset = ((entry->symlink) ? entry->symlink->offset : entry->offset);
+        success = retval->seek(retval, offset);
+    } /* if */
+
+    if (!success)
+    {
+        retval->destroy(retval);
+        retval = NULL;
+    } /* if */
+
+    return retval;
+} /* zip_get_io */
+
+
+static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm,
+                               int *fileExists)
+{
+    PHYSFS_Io *retval = NULL;
+    ZIPinfo *info = (ZIPinfo *) opaque;
+    ZIPentry *entry = zip_find_entry(info, fnm, NULL);
+    ZIPfileinfo *finfo = NULL;
+
+    *fileExists = (entry != NULL);
+    BAIL_IF_MACRO(!entry, ERRPASS, NULL);
+
+    retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
+
+    finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo));
+    GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
+    memset(finfo, '\0', sizeof (ZIPfileinfo));
+
+    finfo->io = zip_get_io(info->io, info, entry);
+    GOTO_IF_MACRO(!finfo->io, ERRPASS, ZIP_openRead_failed);
+    finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry);
+    initializeZStream(&finfo->stream);
+
+    if (finfo->entry->compression_method != COMPMETH_NONE)
+    {
+        finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
+        if (!finfo->buffer)
+            GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed);
+        else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK)
+            goto ZIP_openRead_failed;
+    } /* if */
+
+    memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io));
+    retval->opaque = finfo;
+
+    return retval;
+
+ZIP_openRead_failed:
+    if (finfo != NULL)
+    {
+        if (finfo->io != NULL)
+            finfo->io->destroy(finfo->io);
+
+        if (finfo->buffer != NULL)
+        {
+            allocator.Free(finfo->buffer);
+            inflateEnd(&finfo->stream);
+        } /* if */
+
+        allocator.Free(finfo);
+    } /* if */
+
+    if (retval != NULL)
+        allocator.Free(retval);
+
+    return NULL;
+} /* ZIP_openRead */
+
+
+static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ZIP_openWrite */
+
+
+static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL);
+} /* ZIP_openAppend */
+
+
+static void ZIP_closeArchive(PHYSFS_Dir *opaque)
+{
+    ZIPinfo *zi = (ZIPinfo *) (opaque);
+    zi->io->destroy(zi->io);
+    zip_free_entries(zi->entries, zi->entryCount);
+    allocator.Free(zi);
+} /* ZIP_closeArchive */
+
+
+static int ZIP_remove(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ZIP_remove */
+
+
+static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name)
+{
+    BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0);
+} /* ZIP_mkdir */
+
+
+static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists,
+                    PHYSFS_Stat *stat)
+{
+    int isDir = 0;
+    const ZIPinfo *info = (const ZIPinfo *) opaque;
+    const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
+
+    /* !!! FIXME: does this need to resolve entries here? */
+
+    *exists = isDir || (entry != 0);
+    if (!*exists)
+        return 0;
+
+    if (isDir)
+    {
+        stat->filesize = 0;
+        stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+    } /* if */
+
+    else if (zip_entry_is_symlink(entry))
+    {
+        stat->filesize = 0;
+        stat->filetype = PHYSFS_FILETYPE_SYMLINK;
+    } /* else if */
+
+    else
+    {
+        stat->filesize = (PHYSFS_sint64) entry->uncompressed_size;
+        stat->filetype = PHYSFS_FILETYPE_REGULAR;
+    } /* else */
+
+    stat->modtime = ((entry) ? entry->last_mod_time : 0);
+    stat->createtime = stat->modtime;
+    stat->accesstime = 0;
+    stat->readonly = 1; /* .zip files are always read only */
+
+    return 1;
+} /* ZIP_stat */
+
+
+const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
+{
+    {
+        "ZIP",
+        "PkZip/WinZip/Info-Zip compatible",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://icculus.org/physfs/",
+    },
+    ZIP_openArchive,        /* openArchive() method    */
+    ZIP_enumerateFiles,     /* enumerateFiles() method */
+    ZIP_openRead,           /* openRead() method       */
+    ZIP_openWrite,          /* openWrite() method      */
+    ZIP_openAppend,         /* openAppend() method     */
+    ZIP_remove,             /* remove() method         */
+    ZIP_mkdir,              /* mkdir() method          */
+    ZIP_closeArchive,       /* closeArchive() method   */
+    ZIP_stat                /* stat() method           */
+};
+
+#endif  /* defined PHYSFS_SUPPORTS_ZIP */
+
+/* end of zip.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2744 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+/* !!! FIXME: ERR_PAST_EOF shouldn't trigger for reads. Just return zero. */
+/* !!! FIXME: use snprintf(), not sprintf(). */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+typedef struct __PHYSFS_DIRHANDLE__
+{
+    void *opaque;  /* Instance data unique to the archiver. */
+    char *dirName;  /* Path to archive in platform-dependent notation. */
+    char *mountPoint; /* Mountpoint in virtual file tree. */
+    const PHYSFS_Archiver *funcs;  /* Ptr to archiver info for this handle. */
+    struct __PHYSFS_DIRHANDLE__ *next;  /* linked list stuff. */
+} DirHandle;
+
+
+typedef struct __PHYSFS_FILEHANDLE__
+{
+    PHYSFS_Io *io;  /* Instance data unique to the archiver for this file. */
+    PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
+    const DirHandle *dirHandle;  /* Archiver instance that created this */
+    PHYSFS_uint8 *buffer;  /* Buffer, if set (NULL otherwise). Don't touch! */
+    PHYSFS_uint32 bufsize;  /* Bufsize, if set (0 otherwise). Don't touch! */
+    PHYSFS_uint32 buffill;  /* Buffer fill size. Don't touch! */
+    PHYSFS_uint32 bufpos;  /* Buffer position. Don't touch! */
+    struct __PHYSFS_FILEHANDLE__ *next;  /* linked list stuff. */
+} FileHandle;
+
+
+typedef struct __PHYSFS_ERRSTATETYPE__
+{
+    void *tid;
+    PHYSFS_ErrorCode code;
+    struct __PHYSFS_ERRSTATETYPE__ *next;
+} ErrState;
+
+
+/* The various i/o drivers...some of these may not be compiled in. */
+extern const PHYSFS_Archiver __PHYSFS_Archiver_ZIP;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_LZMA;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_GRP;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR;
+extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660;
+
+static const PHYSFS_Archiver *staticArchivers[] =
+{
+#if PHYSFS_SUPPORTS_ZIP
+    &__PHYSFS_Archiver_ZIP,
+#endif
+#if PHYSFS_SUPPORTS_7Z
+    &__PHYSFS_Archiver_LZMA,
+#endif
+#if PHYSFS_SUPPORTS_GRP
+    &__PHYSFS_Archiver_GRP,
+#endif
+#if PHYSFS_SUPPORTS_QPAK
+    &__PHYSFS_Archiver_QPAK,
+#endif
+#if PHYSFS_SUPPORTS_HOG
+    &__PHYSFS_Archiver_HOG,
+#endif
+#if PHYSFS_SUPPORTS_MVL
+    &__PHYSFS_Archiver_MVL,
+#endif
+#if PHYSFS_SUPPORTS_WAD
+    &__PHYSFS_Archiver_WAD,
+#endif
+#if PHYSFS_SUPPORTS_ISO9660
+    &__PHYSFS_Archiver_ISO9660,
+#endif
+    NULL
+};
+
+
+
+/* General PhysicsFS state ... */
+static int initialized = 0;
+static ErrState *errorStates = NULL;
+static DirHandle *searchPath = NULL;
+static DirHandle *writeDir = NULL;
+static FileHandle *openWriteList = NULL;
+static FileHandle *openReadList = NULL;
+static char *baseDir = NULL;
+static char *userDir = NULL;
+static char *prefDir = NULL;
+static int allowSymLinks = 0;
+static const PHYSFS_Archiver **archivers = NULL;
+static const PHYSFS_ArchiveInfo **archiveInfo = NULL;
+
+/* mutexes ... */
+static void *errorLock = NULL;     /* protects error message list.        */
+static void *stateLock = NULL;     /* protects other PhysFS static state. */
+
+/* allocator ... */
+static int externalAllocator = 0;
+PHYSFS_Allocator allocator;
+
+
+/* PHYSFS_Io implementation for i/o to physical filesystem... */
+
+/* !!! FIXME: maybe refcount the paths in a string pool? */
+typedef struct __PHYSFS_NativeIoInfo
+{
+    void *handle;
+    const char *path;
+    int mode;   /* 'r', 'w', or 'a' */
+} NativeIoInfo;
+
+static PHYSFS_sint64 nativeIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    return __PHYSFS_platformRead(info->handle, buf, len);
+} /* nativeIo_read */
+
+static PHYSFS_sint64 nativeIo_write(PHYSFS_Io *io, const void *buffer,
+                                    PHYSFS_uint64 len)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    return __PHYSFS_platformWrite(info->handle, buffer, len);
+} /* nativeIo_write */
+
+static int nativeIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    return __PHYSFS_platformSeek(info->handle, offset);
+} /* nativeIo_seek */
+
+static PHYSFS_sint64 nativeIo_tell(PHYSFS_Io *io)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    return __PHYSFS_platformTell(info->handle);
+} /* nativeIo_tell */
+
+static PHYSFS_sint64 nativeIo_length(PHYSFS_Io *io)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    return __PHYSFS_platformFileLength(info->handle);
+} /* nativeIo_length */
+
+static PHYSFS_Io *nativeIo_duplicate(PHYSFS_Io *io)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    return __PHYSFS_createNativeIo(info->path, info->mode);
+} /* nativeIo_duplicate */
+
+static int nativeIo_flush(PHYSFS_Io *io)
+{
+    return __PHYSFS_platformFlush(io->opaque);
+} /* nativeIo_flush */
+
+static void nativeIo_destroy(PHYSFS_Io *io)
+{
+    NativeIoInfo *info = (NativeIoInfo *) io->opaque;
+    __PHYSFS_platformClose(info->handle);
+    allocator.Free((void *) info->path);
+    allocator.Free(info);
+    allocator.Free(io);
+} /* nativeIo_destroy */
+
+static const PHYSFS_Io __PHYSFS_nativeIoInterface =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    nativeIo_read,
+    nativeIo_write,
+    nativeIo_seek,
+    nativeIo_tell,
+    nativeIo_length,
+    nativeIo_duplicate,
+    nativeIo_flush,
+    nativeIo_destroy
+};
+
+PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode)
+{
+    PHYSFS_Io *io = NULL;
+    NativeIoInfo *info = NULL;
+    void *handle = NULL;
+    char *pathdup = NULL;
+
+    assert((mode == 'r') || (mode == 'w') || (mode == 'a'));
+
+    io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+    info = (NativeIoInfo *) allocator.Malloc(sizeof (NativeIoInfo));
+    GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+    pathdup = (char *) allocator.Malloc(strlen(path) + 1);
+    GOTO_IF_MACRO(!pathdup, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed);
+
+    if (mode == 'r')
+        handle = __PHYSFS_platformOpenRead(path);
+    else if (mode == 'w')
+        handle = __PHYSFS_platformOpenWrite(path);
+    else if (mode == 'a')
+        handle = __PHYSFS_platformOpenAppend(path);
+
+    GOTO_IF_MACRO(!handle, ERRPASS, createNativeIo_failed);
+
+    strcpy(pathdup, path);
+    info->handle = handle;
+    info->path = pathdup;
+    info->mode = mode;
+    memcpy(io, &__PHYSFS_nativeIoInterface, sizeof (*io));
+    io->opaque = info;
+    return io;
+
+createNativeIo_failed:
+    if (handle != NULL) __PHYSFS_platformClose(handle);
+    if (pathdup != NULL) allocator.Free(pathdup);
+    if (info != NULL) allocator.Free(info);
+    if (io != NULL) allocator.Free(io);
+    return NULL;
+} /* __PHYSFS_createNativeIo */
+
+
+/* PHYSFS_Io implementation for i/o to a memory buffer... */
+
+typedef struct __PHYSFS_MemoryIoInfo
+{
+    const PHYSFS_uint8 *buf;
+    PHYSFS_uint64 len;
+    PHYSFS_uint64 pos;
+    PHYSFS_Io *parent;
+    volatile PHYSFS_uint32 refcount;
+    void (*destruct)(void *);
+} MemoryIoInfo;
+
+static PHYSFS_sint64 memoryIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+    MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+    const PHYSFS_uint64 avail = info->len - info->pos;
+    assert(avail <= info->len);
+
+    if (avail == 0)
+        return 0;  /* we're at EOF; nothing to do. */
+
+    if (len > avail)
+        len = avail;
+
+    memcpy(buf, info->buf + info->pos, (size_t) len);
+    info->pos += len;
+    return len;
+} /* memoryIo_read */
+
+static PHYSFS_sint64 memoryIo_write(PHYSFS_Io *io, const void *buffer,
+                                    PHYSFS_uint64 len)
+{
+    BAIL_MACRO(PHYSFS_ERR_OPEN_FOR_READING, -1);
+} /* memoryIo_write */
+
+static int memoryIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+    MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+    BAIL_IF_MACRO(offset > info->len, PHYSFS_ERR_PAST_EOF, 0);
+    info->pos = offset;
+    return 1;
+} /* memoryIo_seek */
+
+static PHYSFS_sint64 memoryIo_tell(PHYSFS_Io *io)
+{
+    const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+    return (PHYSFS_sint64) info->pos;
+} /* memoryIo_tell */
+
+static PHYSFS_sint64 memoryIo_length(PHYSFS_Io *io)
+{
+    const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+    return (PHYSFS_sint64) info->len;
+} /* memoryIo_length */
+
+static PHYSFS_Io *memoryIo_duplicate(PHYSFS_Io *io)
+{
+    MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+    MemoryIoInfo *newinfo = NULL;
+    PHYSFS_Io *parent = info->parent;
+    PHYSFS_Io *retval = NULL;
+
+    /* avoid deep copies. */
+    assert((!parent) || (!((MemoryIoInfo *) parent->opaque)->parent) );
+
+    /* share the buffer between duplicates. */
+    if (parent != NULL)  /* dup the parent, increment its refcount. */
+        return parent->duplicate(parent);
+
+    /* we're the parent. */
+
+    retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    newinfo = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
+    if (!newinfo)
+    {
+        allocator.Free(retval);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    /* !!! FIXME: want lockless atomic increment. */
+    __PHYSFS_platformGrabMutex(stateLock);
+    info->refcount++;
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    memset(newinfo, '\0', sizeof (*info));
+    newinfo->buf = info->buf;
+    newinfo->len = info->len;
+    newinfo->pos = 0;
+    newinfo->parent = io;
+    newinfo->refcount = 0;
+    newinfo->destruct = NULL;
+
+    memcpy(retval, io, sizeof (*retval));
+    retval->opaque = newinfo;
+    return retval;
+} /* memoryIo_duplicate */
+
+static int memoryIo_flush(PHYSFS_Io *io) { return 1;  /* it's read-only. */ }
+
+static void memoryIo_destroy(PHYSFS_Io *io)
+{
+    MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+    PHYSFS_Io *parent = info->parent;
+    int should_die = 0;
+
+    if (parent != NULL)
+    {
+        assert(info->buf == ((MemoryIoInfo *) info->parent->opaque)->buf);
+        assert(info->len == ((MemoryIoInfo *) info->parent->opaque)->len);
+        assert(info->refcount == 0);
+        assert(info->destruct == NULL);
+        allocator.Free(info);
+        allocator.Free(io);
+        parent->destroy(parent);  /* decrements refcount. */
+        return;
+    } /* if */
+
+    /* we _are_ the parent. */
+    assert(info->refcount > 0);  /* even in a race, we hold a reference. */
+
+    /* !!! FIXME: want lockless atomic decrement. */
+    __PHYSFS_platformGrabMutex(stateLock);
+    info->refcount--;
+    should_die = (info->refcount == 0);
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    if (should_die)
+    {
+        void (*destruct)(void *) = info->destruct;
+        void *buf = (void *) info->buf;
+        io->opaque = NULL;  /* kill this here in case of race. */
+        allocator.Free(info);
+        allocator.Free(io);
+        if (destruct != NULL)
+            destruct(buf);
+    } /* if */
+} /* memoryIo_destroy */
+
+
+static const PHYSFS_Io __PHYSFS_memoryIoInterface =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    memoryIo_read,
+    memoryIo_write,
+    memoryIo_seek,
+    memoryIo_tell,
+    memoryIo_length,
+    memoryIo_duplicate,
+    memoryIo_flush,
+    memoryIo_destroy
+};
+
+PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
+                                   void (*destruct)(void *))
+{
+    PHYSFS_Io *io = NULL;
+    MemoryIoInfo *info = NULL;
+
+    io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
+    info = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo));
+    GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed);
+
+    memset(info, '\0', sizeof (*info));
+    info->buf = (const PHYSFS_uint8 *) buf;
+    info->len = len;
+    info->pos = 0;
+    info->parent = NULL;
+    info->refcount = 1;
+    info->destruct = destruct;
+
+    memcpy(io, &__PHYSFS_memoryIoInterface, sizeof (*io));
+    io->opaque = info;
+    return io;
+
+createMemoryIo_failed:
+    if (info != NULL) allocator.Free(info);
+    if (io != NULL) allocator.Free(io);
+    return NULL;
+} /* __PHYSFS_createMemoryIo */
+
+
+/* PHYSFS_Io implementation for i/o to a PHYSFS_File... */
+
+static PHYSFS_sint64 handleIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
+{
+    return PHYSFS_readBytes((PHYSFS_File *) io->opaque, buf, len);
+} /* handleIo_read */
+
+static PHYSFS_sint64 handleIo_write(PHYSFS_Io *io, const void *buffer,
+                                    PHYSFS_uint64 len)
+{
+    return PHYSFS_writeBytes((PHYSFS_File *) io->opaque, buffer, len);
+} /* handleIo_write */
+
+static int handleIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
+{
+    return PHYSFS_seek((PHYSFS_File *) io->opaque, offset);
+} /* handleIo_seek */
+
+static PHYSFS_sint64 handleIo_tell(PHYSFS_Io *io)
+{
+    return PHYSFS_tell((PHYSFS_File *) io->opaque);
+} /* handleIo_tell */
+
+static PHYSFS_sint64 handleIo_length(PHYSFS_Io *io)
+{
+    return PHYSFS_fileLength((PHYSFS_File *) io->opaque);
+} /* handleIo_length */
+
+static PHYSFS_Io *handleIo_duplicate(PHYSFS_Io *io)
+{
+    /*
+     * There's no duplicate at the PHYSFS_File level, so we break the
+     *  abstraction. We're allowed to: we're physfs.c!
+     */
+    FileHandle *origfh = (FileHandle *) io->opaque;
+    FileHandle *newfh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+    PHYSFS_Io *retval = NULL;
+
+    GOTO_IF_MACRO(!newfh, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+    memset(newfh, '\0', sizeof (*newfh));
+
+    retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+
+#if 0  /* we don't buffer the duplicate, at least not at the moment. */
+    if (origfh->buffer != NULL)
+    {
+        newfh->buffer = (PHYSFS_uint8 *) allocator.Malloc(origfh->bufsize);
+        if (!newfh->buffer)
+            GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed);
+        newfh->bufsize = origfh->bufsize;
+    } /* if */
+#endif
+
+    newfh->io = origfh->io->duplicate(origfh->io);
+    GOTO_IF_MACRO(!newfh->io, ERRPASS, handleIo_dupe_failed);
+
+    newfh->forReading = origfh->forReading;
+    newfh->dirHandle = origfh->dirHandle;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    if (newfh->forReading)
+    {
+        newfh->next = openReadList;
+        openReadList = newfh;
+    } /* if */
+    else
+    {
+        newfh->next = openWriteList;
+        openWriteList = newfh;
+    } /* else */
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    memcpy(retval, io, sizeof (PHYSFS_Io));
+    retval->opaque = newfh;
+    return retval;
+    
+handleIo_dupe_failed:
+    if (newfh)
+    {
+        if (newfh->io != NULL) newfh->io->destroy(newfh->io);
+        if (newfh->buffer != NULL) allocator.Free(newfh->buffer);
+        allocator.Free(newfh);
+    } /* if */
+
+    return NULL;
+} /* handleIo_duplicate */
+
+static int handleIo_flush(PHYSFS_Io *io)
+{
+    return PHYSFS_flush((PHYSFS_File *) io->opaque);
+} /* handleIo_flush */
+
+static void handleIo_destroy(PHYSFS_Io *io)
+{
+    if (io->opaque != NULL)
+        PHYSFS_close((PHYSFS_File *) io->opaque);
+    allocator.Free(io);
+} /* handleIo_destroy */
+
+static const PHYSFS_Io __PHYSFS_handleIoInterface =
+{
+    CURRENT_PHYSFS_IO_API_VERSION, NULL,
+    handleIo_read,
+    handleIo_write,
+    handleIo_seek,
+    handleIo_tell,
+    handleIo_length,
+    handleIo_duplicate,
+    handleIo_flush,
+    handleIo_destroy
+};
+
+static PHYSFS_Io *__PHYSFS_createHandleIo(PHYSFS_File *f)
+{
+    PHYSFS_Io *io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io));
+    BAIL_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    memcpy(io, &__PHYSFS_handleIoInterface, sizeof (*io));
+    io->opaque = f;
+    return io;
+} /* __PHYSFS_createHandleIo */
+
+
+/* functions ... */
+
+typedef struct
+{
+    char **list;
+    PHYSFS_uint32 size;
+    PHYSFS_ErrorCode errcode;
+} EnumStringListCallbackData;
+
+static void enumStringListCallback(void *data, const char *str)
+{
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    if (pecd->errcode)
+        return;
+
+    ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = (char *) allocator.Malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+    {
+        pecd->errcode = PHYSFS_ERR_OUT_OF_MEMORY;
+        pecd->list[pecd->size] = NULL;
+        PHYSFS_freeList(pecd->list);
+        return;
+    } /* if */
+
+    strcpy(newstr, str);
+    pecd->list[pecd->size] = newstr;
+    pecd->size++;
+} /* enumStringListCallback */
+
+
+static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
+{
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) allocator.Malloc(sizeof (char *));
+    BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    func(enumStringListCallback, &ecd);
+
+    if (ecd.errcode)
+    {
+        __PHYSFS_setError(ecd.errcode);
+        return NULL;
+    } /* if */
+
+    ecd.list[ecd.size] = NULL;
+    return ecd.list;
+} /* doEnumStringList */
+
+
+static void __PHYSFS_bubble_sort(void *a, size_t lo, size_t hi,
+                                 int (*cmpfn)(void *, size_t, size_t),
+                                 void (*swapfn)(void *, size_t, size_t))
+{
+    size_t i;
+    int sorted;
+
+    do
+    {
+        sorted = 1;
+        for (i = lo; i < hi; i++)
+        {
+            if (cmpfn(a, i, i + 1) > 0)
+            {
+                swapfn(a, i, i + 1);
+                sorted = 0;
+            } /* if */
+        } /* for */
+    } while (!sorted);
+} /* __PHYSFS_bubble_sort */
+
+
+static void __PHYSFS_quick_sort(void *a, size_t lo, size_t hi,
+                         int (*cmpfn)(void *, size_t, size_t),
+                         void (*swapfn)(void *, size_t, size_t))
+{
+    size_t i;
+    size_t j;
+    size_t v;
+
+    if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD)
+        __PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn);
+    else
+    {
+        i = (hi + lo) / 2;
+
+        if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i);
+        if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi);
+        if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi);
+
+        j = hi - 1;
+        swapfn(a, i, j);
+        i = lo;
+        v = j;
+        while (1)
+        {
+            while(cmpfn(a, ++i, v) < 0) { /* do nothing */ }
+            while(cmpfn(a, --j, v) > 0) { /* do nothing */ }
+            if (j < i)
+                break;
+            swapfn(a, i, j);
+        } /* while */
+        if (i != (hi-1))
+            swapfn(a, i, hi-1);
+        __PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn);
+        __PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn);
+    } /* else */
+} /* __PHYSFS_quick_sort */
+
+
+void __PHYSFS_sort(void *entries, size_t max,
+                   int (*cmpfn)(void *, size_t, size_t),
+                   void (*swapfn)(void *, size_t, size_t))
+{
+    /*
+     * Quicksort w/ Bubblesort fallback algorithm inspired by code from here:
+     *   http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html
+     */
+    if (max > 0)
+        __PHYSFS_quick_sort(entries, 0, max - 1, cmpfn, swapfn);
+} /* __PHYSFS_sort */
+
+
+static ErrState *findErrorForCurrentThread(void)
+{
+    ErrState *i;
+    void *tid;
+
+    if (errorLock != NULL)
+        __PHYSFS_platformGrabMutex(errorLock);
+
+    if (errorStates != NULL)
+    {
+        tid = __PHYSFS_platformGetThreadID();
+
+        for (i = errorStates; i != NULL; i = i->next)
+        {
+            if (i->tid == tid)
+            {
+                if (errorLock != NULL)
+                    __PHYSFS_platformReleaseMutex(errorLock);
+                return i;
+            } /* if */
+        } /* for */
+    } /* if */
+
+    if (errorLock != NULL)
+        __PHYSFS_platformReleaseMutex(errorLock);
+
+    return NULL;   /* no error available. */
+} /* findErrorForCurrentThread */
+
+
+void __PHYSFS_setError(const PHYSFS_ErrorCode errcode)
+{
+    ErrState *err;
+
+    if (!errcode)
+        return;
+
+    err = findErrorForCurrentThread();
+    if (err == NULL)
+    {
+        err = (ErrState *) allocator.Malloc(sizeof (ErrState));
+        if (err == NULL)
+            return;   /* uhh...? */
+
+        memset(err, '\0', sizeof (ErrState));
+        err->tid = __PHYSFS_platformGetThreadID();
+
+        if (errorLock != NULL)
+            __PHYSFS_platformGrabMutex(errorLock);
+
+        err->next = errorStates;
+        errorStates = err;
+
+        if (errorLock != NULL)
+            __PHYSFS_platformReleaseMutex(errorLock);
+    } /* if */
+
+    err->code = errcode;
+} /* __PHYSFS_setError */
+
+
+PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
+{
+    ErrState *err = findErrorForCurrentThread();
+    const PHYSFS_ErrorCode retval = (err) ? err->code : PHYSFS_ERR_OK;
+    if (err)
+        err->code = PHYSFS_ERR_OK;
+    return retval;
+} /* PHYSFS_getLastErrorCode */
+
+
+PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
+{
+    switch (code)
+    {
+        case PHYSFS_ERR_OK: return "no error";
+        case PHYSFS_ERR_OTHER_ERROR: return "unknown error";
+        case PHYSFS_ERR_OUT_OF_MEMORY: return "out of memory";
+        case PHYSFS_ERR_NOT_INITIALIZED: return "not initialized";
+        case PHYSFS_ERR_IS_INITIALIZED: return "already initialized";
+        case PHYSFS_ERR_ARGV0_IS_NULL: return "argv[0] is NULL";
+        case PHYSFS_ERR_UNSUPPORTED: return "unsupported";
+        case PHYSFS_ERR_PAST_EOF: return "past end of file";
+        case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open";
+        case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument";
+        case PHYSFS_ERR_NOT_MOUNTED: return "not mounted";
+        case PHYSFS_ERR_NO_SUCH_PATH: return "no such path";
+        case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden";
+        case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set";
+        case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading";
+        case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing";
+        case PHYSFS_ERR_NOT_A_FILE: return "not a file";
+        case PHYSFS_ERR_READ_ONLY: return "read-only filesystem";
+        case PHYSFS_ERR_CORRUPT: return "corrupted";
+        case PHYSFS_ERR_SYMLINK_LOOP: return "infinite symbolic link loop";
+        case PHYSFS_ERR_IO: return "i/o error";
+        case PHYSFS_ERR_PERMISSION: return "permission denied";
+        case PHYSFS_ERR_NO_SPACE: return "no space available for writing";
+        case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure";
+        case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs";
+        case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty";
+        case PHYSFS_ERR_OS_ERROR: return "OS reported an error";
+    } /* switch */
+
+    return NULL;  /* don't know this error code. */
+} /* PHYSFS_getErrorByCode */
+
+
+void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
+{
+    __PHYSFS_setError(code);
+} /* PHYSFS_setErrorCode */
+
+
+const char *PHYSFS_getLastError(void)
+{
+    const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
+    return (err) ? PHYSFS_getErrorByCode(err) : NULL;
+} /* PHYSFS_getLastError */
+
+
+/* MAKE SURE that errorLock is held before calling this! */
+static void freeErrorStates(void)
+{
+    ErrState *i;
+    ErrState *next;
+
+    for (i = errorStates; i != NULL; i = next)
+    {
+        next = i->next;
+        allocator.Free(i);
+    } /* for */
+
+    errorStates = NULL;
+} /* freeErrorStates */
+
+
+void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+{
+    if (ver != NULL)
+    {
+        ver->major = PHYSFS_VER_MAJOR;
+        ver->minor = PHYSFS_VER_MINOR;
+        ver->patch = PHYSFS_VER_PATCH;
+    } /* if */
+} /* PHYSFS_getLinkedVersion */
+
+
+static const char *find_filename_extension(const char *fname)
+{
+    const char *retval = NULL;
+    if (fname != NULL)
+    {
+        const char *p = strchr(fname, '.');
+        retval = p;
+
+        while (p != NULL)
+        {
+            p = strchr(p + 1, '.');
+            if (p != NULL)
+                retval = p;
+        } /* while */
+
+        if (retval != NULL)
+            retval++;  /* skip '.' */
+    } /* if */
+
+    return retval;
+} /* find_filename_extension */
+
+
+static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
+                             const char *d, int forWriting)
+{
+    DirHandle *retval = NULL;
+    void *opaque = NULL;
+
+    if (io != NULL)
+        BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL);
+
+    opaque = funcs->openArchive(io, d, forWriting);
+    if (opaque != NULL)
+    {
+        retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
+        if (retval == NULL)
+            funcs->closeArchive(opaque);
+        else
+        {
+            memset(retval, '\0', sizeof (DirHandle));
+            retval->mountPoint = NULL;
+            retval->funcs = funcs;
+            retval->opaque = opaque;
+        } /* else */
+    } /* if */
+
+    return retval;
+} /* tryOpenDir */
+
+
+static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
+{
+    DirHandle *retval = NULL;
+    const PHYSFS_Archiver **i;
+    const char *ext;
+
+    assert((io != NULL) || (d != NULL));
+
+    if (io == NULL)
+    {
+        /* DIR gets first shot (unlike the rest, it doesn't deal with files). */
+        retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
+        if (retval != NULL)
+            return retval;
+
+        io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
+        BAIL_IF_MACRO(!io, ERRPASS, 0);
+    } /* if */
+
+    ext = find_filename_extension(d);
+    if (ext != NULL)
+    {
+        /* Look for archivers with matching file extensions first... */
+        for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+        {
+            if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0)
+                retval = tryOpenDir(io, *i, d, forWriting);
+        } /* for */
+
+        /* failing an exact file extension match, try all the others... */
+        for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+        {
+            if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) != 0)
+                retval = tryOpenDir(io, *i, d, forWriting);
+        } /* for */
+    } /* if */
+
+    else  /* no extension? Try them all. */
+    {
+        for (i = archivers; (*i != NULL) && (retval == NULL); i++)
+            retval = tryOpenDir(io, *i, d, forWriting);
+    } /* else */
+
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL);
+    return retval;
+} /* openDirectory */
+
+
+/*
+ * Make a platform-independent path string sane. Doesn't actually check the
+ *  file hierarchy, it just cleans up the string.
+ *  (dst) must be a buffer at least as big as (src), as this is where the
+ *  cleaned up string is deposited.
+ * If there are illegal bits in the path (".." entries, etc) then we
+ *  return zero and (dst) is undefined. Non-zero if the path was sanitized.
+ */
+static int sanitizePlatformIndependentPath(const char *src, char *dst)
+{
+    char *prev;
+    char ch;
+
+    while (*src == '/')  /* skip initial '/' chars... */
+        src++;
+
+    prev = dst;
+    do
+    {
+        ch = *(src++);
+
+        if ((ch == ':') || (ch == '\\'))  /* illegal chars in a physfs path. */
+            BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
+
+        if (ch == '/')   /* path separator. */
+        {
+            *dst = '\0';  /* "." and ".." are illegal pathnames. */
+            if ((strcmp(prev, ".") == 0) || (strcmp(prev, "..") == 0))
+                BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0);
+
+            while (*src == '/')   /* chop out doubles... */
+                src++;
+
+            if (*src == '\0') /* ends with a pathsep? */
+                break;  /* we're done, don't add final pathsep to dst. */
+
+            prev = dst + 1;
+        } /* if */
+
+        *(dst++) = ch;
+    } while (ch != '\0');
+
+    return 1;
+} /* sanitizePlatformIndependentPath */
+
+
+/*
+ * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
+ *  output from sanitizePlatformIndependentPath(), so that it is in a known
+ *  state.
+ *
+ * This only finds legitimate segments of a mountpoint. If the mountpoint is
+ *  "/a/b/c" and (fname) is "/a/b/c", "/", or "/a/b/c/d", then the results are
+ *  all zero. "/a/b" will succeed, though.
+ */
+static int partOfMountPoint(DirHandle *h, char *fname)
+{
+    /* !!! FIXME: This code feels gross. */
+    int rc;
+    size_t len, mntpntlen;
+
+    if (h->mountPoint == NULL)
+        return 0;
+    else if (*fname == '\0')
+        return 1;
+
+    len = strlen(fname);
+    mntpntlen = strlen(h->mountPoint);
+    if (len > mntpntlen)  /* can't be a subset of mountpoint. */
+        return 0;
+
+    /* if true, must be not a match or a complete match, but not a subset. */
+    if ((len + 1) == mntpntlen)
+        return 0;
+
+    rc = strncmp(fname, h->mountPoint, len); /* !!! FIXME: case insensitive? */
+    if (rc != 0)
+        return 0;  /* not a match. */
+
+    /* make sure /a/b matches /a/b/ and not /a/bc ... */
+    return h->mountPoint[len] == '/';
+} /* partOfMountPoint */
+
+
+static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
+                                  const char *mountPoint, int forWriting)
+{
+    DirHandle *dirHandle = NULL;
+    char *tmpmntpnt = NULL;
+
+    if (mountPoint != NULL)
+    {
+        const size_t len = strlen(mountPoint) + 1;
+        tmpmntpnt = (char *) __PHYSFS_smallAlloc(len);
+        GOTO_IF_MACRO(!tmpmntpnt, PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+        if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt))
+            goto badDirHandle;
+        mountPoint = tmpmntpnt;  /* sanitized version. */
+    } /* if */
+
+    dirHandle = openDirectory(io, newDir, forWriting);
+    GOTO_IF_MACRO(!dirHandle, ERRPASS, badDirHandle);
+
+    if (newDir == NULL)
+        dirHandle->dirName = NULL;
+    else
+    {
+        dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
+        if (!dirHandle->dirName)
+            GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+        strcpy(dirHandle->dirName, newDir);
+    } /* else */
+
+    if ((mountPoint != NULL) && (*mountPoint != '\0'))
+    {
+        dirHandle->mountPoint = (char *)allocator.Malloc(strlen(mountPoint)+2);
+        if (!dirHandle->mountPoint)
+            GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
+        strcpy(dirHandle->mountPoint, mountPoint);
+        strcat(dirHandle->mountPoint, "/");
+    } /* if */
+
+    __PHYSFS_smallFree(tmpmntpnt);
+    return dirHandle;
+
+badDirHandle:
+    if (dirHandle != NULL)
+    {
+        dirHandle->funcs->closeArchive(dirHandle->opaque);
+        allocator.Free(dirHandle->dirName);
+        allocator.Free(dirHandle->mountPoint);
+        allocator.Free(dirHandle);
+    } /* if */
+
+    __PHYSFS_smallFree(tmpmntpnt);
+    return NULL;
+} /* createDirHandle */
+
+
+/* MAKE SURE you've got the stateLock held before calling this! */
+static int freeDirHandle(DirHandle *dh, FileHandle *openList)
+{
+    FileHandle *i;
+
+    if (dh == NULL)
+        return 1;
+
+    for (i = openList; i != NULL; i = i->next)
+        BAIL_IF_MACRO(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0);
+
+    dh->funcs->closeArchive(dh->opaque);
+    allocator.Free(dh->dirName);
+    allocator.Free(dh->mountPoint);
+    allocator.Free(dh);
+    return 1;
+} /* freeDirHandle */
+
+
+static char *calculateBaseDir(const char *argv0)
+{
+    const char dirsep = __PHYSFS_platformDirSeparator;
+    char *retval = NULL;
+    char *ptr = NULL;
+
+    /* Give the platform layer first shot at this. */
+    retval = __PHYSFS_platformCalcBaseDir(argv0);
+    if (retval != NULL)
+        return retval;
+
+    /* We need argv0 to go on. */
+    BAIL_IF_MACRO(argv0 == NULL, PHYSFS_ERR_ARGV0_IS_NULL, NULL);
+
+    ptr = strrchr(argv0, dirsep);
+    if (ptr != NULL)
+    {
+        const size_t size = ((size_t) (ptr - argv0)) + 1;
+        retval = (char *) allocator.Malloc(size + 1);
+        BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+        memcpy(retval, argv0, size);
+        retval[size] = '\0';
+        return retval;
+    } /* if */
+
+    /* argv0 wasn't helpful. */
+    BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+} /* calculateBaseDir */
+
+
+static int initializeMutexes(void)
+{
+    errorLock = __PHYSFS_platformCreateMutex();
+    if (errorLock == NULL)
+        goto initializeMutexes_failed;
+
+    stateLock = __PHYSFS_platformCreateMutex();
+    if (stateLock == NULL)
+        goto initializeMutexes_failed;
+
+    return 1;  /* success. */
+
+initializeMutexes_failed:
+    if (errorLock != NULL)
+        __PHYSFS_platformDestroyMutex(errorLock);
+
+    if (stateLock != NULL)
+        __PHYSFS_platformDestroyMutex(stateLock);
+
+    errorLock = stateLock = NULL;
+    return 0;  /* failed. */
+} /* initializeMutexes */
+
+
+static void setDefaultAllocator(void);
+
+static int initStaticArchivers(void)
+{
+    const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers);
+    const size_t len = numStaticArchivers * sizeof (void *);
+    size_t i;
+
+    assert(numStaticArchivers > 0);  /* seriously, none at all?! */
+    assert(staticArchivers[numStaticArchivers - 1] == NULL);
+
+    archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len);
+    BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    archivers = (const PHYSFS_Archiver **) allocator.Malloc(len);
+    BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+    for (i = 0; i < numStaticArchivers - 1; i++)
+        archiveInfo[i] = &staticArchivers[i]->info;
+    archiveInfo[numStaticArchivers - 1] = NULL;
+
+    memcpy(archivers, staticArchivers, len);
+
+    return 1;
+} /* initStaticArchivers */
+
+
+static int doDeinit(void);
+
+int PHYSFS_init(const char *argv0)
+{
+    BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
+
+    if (!externalAllocator)
+        setDefaultAllocator();
+
+    if ((allocator.Init != NULL) && (!allocator.Init())) return 0;
+
+    if (!__PHYSFS_platformInit())
+    {
+        if (allocator.Deinit != NULL) allocator.Deinit();
+        return 0;
+    } /* if */
+
+    /* everything below here can be cleaned up safely by doDeinit(). */
+
+    if (!initializeMutexes()) goto initFailed;
+
+    baseDir = calculateBaseDir(argv0);
+    if (!baseDir) goto initFailed;
+
+    userDir = __PHYSFS_platformCalcUserDir();
+    if (!userDir) goto initFailed;
+
+    /* Platform layer is required to append a dirsep. */
+    assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator);
+    assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator);
+
+    if (!initStaticArchivers()) goto initFailed;
+
+    initialized = 1;
+
+    /* This makes sure that the error subsystem is initialized. */
+    __PHYSFS_setError(PHYSFS_getLastErrorCode());
+
+    return 1;
+
+initFailed:
+    doDeinit();
+    return 0;
+} /* PHYSFS_init */
+
+
+/* MAKE SURE you hold stateLock before calling this! */
+static int closeFileHandleList(FileHandle **list)
+{
+    FileHandle *i;
+    FileHandle *next = NULL;
+
+    for (i = *list; i != NULL; i = next)
+    {
+        PHYSFS_Io *io = i->io;
+        next = i->next;
+
+        if (!io->flush(io))
+        {
+            *list = i;
+            return 0;
+        } /* if */
+
+        io->destroy(io);
+        allocator.Free(i);
+    } /* for */
+
+    *list = NULL;
+    return 1;
+} /* closeFileHandleList */
+
+
+/* MAKE SURE you hold the stateLock before calling this! */
+static void freeSearchPath(void)
+{
+    DirHandle *i;
+    DirHandle *next = NULL;
+
+    closeFileHandleList(&openReadList);
+
+    if (searchPath != NULL)
+    {
+        for (i = searchPath; i != NULL; i = next)
+        {
+            next = i->next;
+            freeDirHandle(i, openReadList);
+        } /* for */
+        searchPath = NULL;
+    } /* if */
+} /* freeSearchPath */
+
+
+static int doDeinit(void)
+{
+    BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0);
+
+    closeFileHandleList(&openWriteList);
+    BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0);
+
+    freeSearchPath();
+    freeErrorStates();
+
+    if (baseDir != NULL)
+    {
+        allocator.Free(baseDir);
+        baseDir = NULL;
+    } /* if */
+
+    if (userDir != NULL)
+    {
+        allocator.Free(userDir);
+        userDir = NULL;
+    } /* if */
+
+    if (prefDir != NULL)
+    {
+        allocator.Free(prefDir);
+        prefDir = NULL;
+    } /* if */
+
+    if (archiveInfo != NULL)
+    {
+        allocator.Free(archiveInfo);
+        archiveInfo = NULL;
+    } /* if */
+
+    if (archivers != NULL)
+    {
+        allocator.Free(archivers);
+        archivers = NULL;
+    } /* if */
+
+    allowSymLinks = 0;
+    initialized = 0;
+
+    if (errorLock) __PHYSFS_platformDestroyMutex(errorLock);
+    if (stateLock) __PHYSFS_platformDestroyMutex(stateLock);
+
+    if (allocator.Deinit != NULL)
+        allocator.Deinit();
+
+    errorLock = stateLock = NULL;
+    return 1;
+} /* doDeinit */
+
+
+int PHYSFS_deinit(void)
+{
+    BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+    return doDeinit();
+} /* PHYSFS_deinit */
+
+
+int PHYSFS_isInit(void)
+{
+    return initialized;
+} /* PHYSFS_isInit */
+
+
+const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+{
+    BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
+    return archiveInfo;
+} /* PHYSFS_supportedArchiveTypes */
+
+
+void PHYSFS_freeList(void *list)
+{
+    void **i;
+    if (list != NULL)
+    {
+        for (i = (void **) list; *i != NULL; i++)
+            allocator.Free(*i);
+
+        allocator.Free(list);
+    } /* if */
+} /* PHYSFS_freeList */
+
+
+const char *PHYSFS_getDirSeparator(void)
+{
+    static char retval[2] = { __PHYSFS_platformDirSeparator, '\0' };
+    return retval;
+} /* PHYSFS_getDirSeparator */
+
+
+char **PHYSFS_getCdRomDirs(void)
+{
+    return doEnumStringList(__PHYSFS_platformDetectAvailableCDs);
+} /* PHYSFS_getCdRomDirs */
+
+
+void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
+{
+    __PHYSFS_platformDetectAvailableCDs(callback, data);
+} /* PHYSFS_getCdRomDirsCallback */
+
+
+const char *PHYSFS_getPrefDir(const char *org, const char *app)
+{
+    const char dirsep = __PHYSFS_platformDirSeparator;
+    PHYSFS_Stat statbuf;
+    char *ptr = NULL;
+    char *endstr = NULL;
+    int exists = 0;
+
+    BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+    BAIL_IF_MACRO(!org, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+    BAIL_IF_MACRO(*org == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+    BAIL_IF_MACRO(!app, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+    BAIL_IF_MACRO(*app == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+
+    allocator.Free(prefDir);
+    prefDir = __PHYSFS_platformCalcPrefDir(org, app);
+    BAIL_IF_MACRO(!prefDir, ERRPASS, NULL);
+
+    assert(strlen(prefDir) > 0);
+    endstr = prefDir + (strlen(prefDir) - 1);
+    assert(*endstr == dirsep);
+    *endstr = '\0';  /* mask out the final dirsep for now. */
+
+    if (!__PHYSFS_platformStat(prefDir, &exists, &statbuf))
+    {
+        for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep))
+        {
+            *ptr = '\0';
+            __PHYSFS_platformMkDir(prefDir);
+            *ptr = dirsep;
+        } /* for */
+
+        if (!__PHYSFS_platformMkDir(prefDir))
+        {
+            allocator.Free(prefDir);
+            prefDir = NULL;
+        } /* if */
+    } /* if */
+
+    *endstr = dirsep;  /* readd the final dirsep. */
+
+    return prefDir;
+} /* PHYSFS_getPrefDir */
+
+
+const char *PHYSFS_getBaseDir(void)
+{
+    return baseDir;   /* this is calculated in PHYSFS_init()... */
+} /* PHYSFS_getBaseDir */
+
+
+const char *__PHYSFS_getUserDir(void)  /* not deprecated internal version. */
+{
+    return userDir;   /* this is calculated in PHYSFS_init()... */
+} /* __PHYSFS_getUserDir */
+
+
+const char *PHYSFS_getUserDir(void)
+{
+    return __PHYSFS_getUserDir();
+} /* PHYSFS_getUserDir */
+
+
+const char *PHYSFS_getWriteDir(void)
+{
+    const char *retval = NULL;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    if (writeDir != NULL)
+        retval = writeDir->dirName;
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    return retval;
+} /* PHYSFS_getWriteDir */
+
+
+int PHYSFS_setWriteDir(const char *newDir)
+{
+    int retval = 1;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    if (writeDir != NULL)
+    {
+        BAIL_IF_MACRO_MUTEX(!freeDirHandle(writeDir, openWriteList), ERRPASS,
+                            stateLock, 0);
+        writeDir = NULL;
+    } /* if */
+
+    if (newDir != NULL)
+    {
+        /* !!! FIXME: PHYSFS_Io shouldn't be NULL */
+        writeDir = createDirHandle(NULL, newDir, NULL, 1);
+        retval = (writeDir != NULL);
+    } /* if */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    return retval;
+} /* PHYSFS_setWriteDir */
+
+
+static int doMount(PHYSFS_Io *io, const char *fname,
+                   const char *mountPoint, int appendToPath)
+{
+    DirHandle *dh;
+    DirHandle *prev = NULL;
+    DirHandle *i;
+
+    if (mountPoint == NULL)
+        mountPoint = "/";
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    if (fname != NULL)
+    {
+        for (i = searchPath; i != NULL; i = i->next)
+        {
+            /* already in search path? */
+            if ((i->dirName != NULL) && (strcmp(fname, i->dirName) == 0))
+                BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
+            prev = i;
+        } /* for */
+    } /* if */
+
+    dh = createDirHandle(io, fname, mountPoint, 0);
+    BAIL_IF_MACRO_MUTEX(!dh, ERRPASS, stateLock, 0);
+
+    if (appendToPath)
+    {
+        if (prev == NULL)
+            searchPath = dh;
+        else
+            prev->next = dh;
+    } /* if */
+    else
+    {
+        dh->next = searchPath;
+        searchPath = dh;
+    } /* else */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    return 1;
+} /* doMount */
+
+
+int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
+                   const char *mountPoint, int appendToPath)
+{
+    BAIL_IF_MACRO(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0);
+    return doMount(io, fname, mountPoint, appendToPath);
+} /* PHYSFS_mountIo */
+
+
+int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *),
+                       const char *fname, const char *mountPoint,
+                       int appendToPath)
+{
+    int retval = 0;
+    PHYSFS_Io *io = NULL;
+
+    BAIL_IF_MACRO(!buf, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+
+    io = __PHYSFS_createMemoryIo(buf, len, del);
+    BAIL_IF_MACRO(!io, ERRPASS, 0);
+    retval = doMount(io, fname, mountPoint, appendToPath);
+    if (!retval)
+    {
+        /* docs say not to call (del) in case of failure, so cheat. */
+        MemoryIoInfo *info = (MemoryIoInfo *) io->opaque;
+        info->destruct = NULL;
+        io->destroy(io);
+    } /* if */
+
+    return retval;
+} /* PHYSFS_mountMemory */
+
+
+int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
+                       const char *mountPoint, int appendToPath)
+{
+    int retval = 0;
+    PHYSFS_Io *io = NULL;
+
+    BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+
+    io = __PHYSFS_createHandleIo(file);
+    BAIL_IF_MACRO(!io, ERRPASS, 0);
+    retval = doMount(io, fname, mountPoint, appendToPath);
+    if (!retval)
+    {
+        /* docs say not to destruct in case of failure, so cheat. */
+        io->opaque = NULL;
+        io->destroy(io);
+    } /* if */
+
+    return retval;
+} /* PHYSFS_mountHandle */
+
+
+int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+{
+    BAIL_IF_MACRO(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    return doMount(NULL, newDir, mountPoint, appendToPath);
+} /* PHYSFS_mount */
+
+
+int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+{
+    return doMount(NULL, newDir, NULL, appendToPath);
+} /* PHYSFS_addToSearchPath */
+
+
+int PHYSFS_removeFromSearchPath(const char *oldDir)
+{
+    return PHYSFS_unmount(oldDir);
+} /* PHYSFS_removeFromSearchPath */
+
+
+int PHYSFS_unmount(const char *oldDir)
+{
+    DirHandle *i;
+    DirHandle *prev = NULL;
+    DirHandle *next = NULL;
+
+    BAIL_IF_MACRO(oldDir == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        if (strcmp(i->dirName, oldDir) == 0)
+        {
+            next = i->next;
+            BAIL_IF_MACRO_MUTEX(!freeDirHandle(i, openReadList), ERRPASS,
+                                stateLock, 0);
+
+            if (prev == NULL)
+                searchPath = next;
+            else
+                prev->next = next;
+
+            BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1);
+        } /* if */
+        prev = i;
+    } /* for */
+
+    BAIL_MACRO_MUTEX(PHYSFS_ERR_NOT_MOUNTED, stateLock, 0);
+} /* PHYSFS_unmount */
+
+
+char **PHYSFS_getSearchPath(void)
+{
+    return doEnumStringList(PHYSFS_getSearchPathCallback);
+} /* PHYSFS_getSearchPath */
+
+
+const char *PHYSFS_getMountPoint(const char *dir)
+{
+    DirHandle *i;
+    __PHYSFS_platformGrabMutex(stateLock);
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        if (strcmp(i->dirName, dir) == 0)
+        {
+            const char *retval = ((i->mountPoint) ? i->mountPoint : "/");
+            __PHYSFS_platformReleaseMutex(stateLock);
+            return retval;
+        } /* if */
+    } /* for */
+    __PHYSFS_platformReleaseMutex(stateLock);
+
+    BAIL_MACRO(PHYSFS_ERR_NOT_MOUNTED, NULL);
+} /* PHYSFS_getMountPoint */
+
+
+void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data)
+{
+    DirHandle *i;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    for (i = searchPath; i != NULL; i = i->next)
+        callback(data, i->dirName);
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+} /* PHYSFS_getSearchPathCallback */
+
+
+/* Split out to avoid stack allocation in a loop. */
+static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep,
+                              int archivesFirst)
+{
+    const char *d = PHYSFS_getRealDir(i);
+    const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1;
+    char *str = (char *) __PHYSFS_smallAlloc(allocsize);
+    if (str != NULL)
+    {
+        sprintf(str, "%s%s%s", d, dirsep, i);
+        PHYSFS_mount(str, NULL, archivesFirst == 0);
+        __PHYSFS_smallFree(str);
+    } /* if */
+} /* setSaneCfgAddPath */
+
+
+int PHYSFS_setSaneConfig(const char *organization, const char *appName,
+                         const char *archiveExt, int includeCdRoms,
+                         int archivesFirst)
+{
+    const char *dirsep = PHYSFS_getDirSeparator();
+    const char *basedir;
+    const char *prefdir;
+
+    BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0);
+
+    prefdir = PHYSFS_getPrefDir(organization, appName);
+    BAIL_IF_MACRO(!prefdir, ERRPASS, 0);
+
+    basedir = PHYSFS_getBaseDir();
+    BAIL_IF_MACRO(!basedir, ERRPASS, 0);
+
+    BAIL_IF_MACRO(!PHYSFS_setWriteDir(prefdir), PHYSFS_ERR_NO_WRITE_DIR, 0);
+
+    /* Put write dir first in search path... */
+    PHYSFS_mount(prefdir, NULL, 0);
+
+    /* Put base path on search path... */
+    PHYSFS_mount(basedir, NULL, 1);
+
+    /* handle CD-ROMs... */
+    if (includeCdRoms)
+    {
+        char **cds = PHYSFS_getCdRomDirs();
+        char **i;
+        for (i = cds; *i != NULL; i++)
+            PHYSFS_mount(*i, NULL, 1);
+        PHYSFS_freeList(cds);
+    } /* if */
+
+    /* Root out archives, and add them to search path... */
+    if (archiveExt != NULL)
+    {
+        char **rc = PHYSFS_enumerateFiles("/");
+        char **i;
+        size_t extlen = strlen(archiveExt);
+        char *ext;
+
+        for (i = rc; *i != NULL; i++)
+        {
+            size_t l = strlen(*i);
+            if ((l > extlen) && ((*i)[l - extlen - 1] == '.'))
+            {
+                ext = (*i) + (l - extlen);
+                if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0)
+                    setSaneCfgAddPath(*i, l, dirsep, archivesFirst);
+            } /* if */
+        } /* for */
+
+        PHYSFS_freeList(rc);
+    } /* if */
+
+    return 1;
+} /* PHYSFS_setSaneConfig */
+
+
+void PHYSFS_permitSymbolicLinks(int allow)
+{
+    allowSymLinks = allow;
+} /* PHYSFS_permitSymbolicLinks */
+
+
+int PHYSFS_symbolicLinksPermitted(void)
+{
+    return allowSymLinks;
+} /* PHYSFS_symbolicLinksPermitted */
+
+
+/*
+ * Verify that (fname) (in platform-independent notation), in relation
+ *  to (h) is secure. That means that each element of fname is checked
+ *  for symlinks (if they aren't permitted). This also allows for quick
+ *  rejection of files that exist outside an archive's mountpoint.
+ *
+ * With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs
+ *  at a time), you should always pass zero for "allowMissing" for efficiency.
+ *
+ * (fname) must point to an output from sanitizePlatformIndependentPath(),
+ *  since it will make sure that path names are in the right format for
+ *  passing certain checks. It will also do checks for "insecure" pathnames
+ *  like ".." which should be done once instead of once per archive. This also
+ *  gives us license to treat (fname) as scratch space in this function.
+ *
+ * Returns non-zero if string is safe, zero if there's a security issue.
+ *  PHYSFS_getLastError() will specify what was wrong. (*fname) will be
+ *  updated to point past any mount point elements so it is prepared to
+ *  be used with the archiver directly.
+ */
+static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
+{
+    char *fname = *_fname;
+    int retval = 1;
+    char *start;
+    char *end;
+
+    if (*fname == '\0')  /* quick rejection. */
+        return 1;
+
+    /* !!! FIXME: This codeblock sucks. */
+    if (h->mountPoint != NULL)  /* NULL mountpoint means "/". */
+    {
+        size_t mntpntlen = strlen(h->mountPoint);
+        size_t len = strlen(fname);
+        assert(mntpntlen > 1); /* root mount points should be NULL. */
+        /* not under the mountpoint, so skip this archive. */
+        BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0);
+        /* !!! FIXME: Case insensitive? */
+        retval = strncmp(h->mountPoint, fname, mntpntlen-1);
+        BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0);
+        if (len > mntpntlen-1)  /* corner case... */
+            BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0);
+        fname += mntpntlen-1;  /* move to start of actual archive path. */
+        if (*fname == '/')
+            fname++;
+        *_fname = fname;  /* skip mountpoint for later use. */
+        retval = 1;  /* may be reset, below. */
+    } /* if */
+
+    start = fname;
+    if (!allowSymLinks)
+    {
+        while (1)
+        {
+            PHYSFS_Stat statbuf;
+            int rc = 0;
+            end = strchr(start, '/');
+
+            if (end != NULL) *end = '\0';
+            rc = h->funcs->stat(h->opaque, fname, &retval, &statbuf);
+            if (rc)
+                rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
+            if (end != NULL) *end = '/';
+
+            /* insecure path (has a disallowed symlink in it)? */
+            BAIL_IF_MACRO(rc, PHYSFS_ERR_SYMLINK_FORBIDDEN, 0);
+
+            /* break out early if path element is missing. */
+            if (!retval)
+            {
+                /*
+                 * We need to clear it if it's the last element of the path,
+                 *  since this might be a non-existant file we're opening
+                 *  for writing...
+                 */
+                if ((end == NULL) || (allowMissing))
+                    retval = 1;
+                break;
+            } /* if */
+
+            if (end == NULL)
+                break;
+
+            start = end + 1;
+        } /* while */
+    } /* if */
+
+    return retval;
+} /* verifyPath */
+
+
+static int doMkdir(const char *_dname, char *dname)
+{
+    DirHandle *h;
+    char *start;
+    char *end;
+    int retval = 0;
+    int exists = 1;  /* force existance check on first path element. */
+
+    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), ERRPASS, 0);
+
+    __PHYSFS_platformGrabMutex(stateLock);
+    BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
+    h = writeDir;
+    BAIL_IF_MACRO_MUTEX(!verifyPath(h, &dname, 1), ERRPASS, stateLock, 0);
+
+    start = dname;
+    while (1)
+    {
+        end = strchr(start, '/');
+        if (end != NULL)
+            *end = '\0';
+
+        /* only check for existance if all parent dirs existed, too... */
+        if (exists)
+        {
+            PHYSFS_Stat statbuf;
+            const int rc = h->funcs->stat(h->opaque, dname, &exists, &statbuf);
+            retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY));
+        } /* if */
+
+        if (!exists)
+            retval = h->funcs->mkdir(h->opaque, dname);
+
+        if (!retval)
+            break;
+
+        if (end == NULL)
+            break;
+
+        *end = '/';
+        start = end + 1;
+    } /* while */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    return retval;
+} /* doMkdir */
+
+
+int PHYSFS_mkdir(const char *_dname)
+{
+    int retval = 0;
+    char *dname;
+    size_t len;
+
+    BAIL_IF_MACRO(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_dname) + 1;
+    dname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    retval = doMkdir(_dname, dname);
+    __PHYSFS_smallFree(dname);
+    return retval;
+} /* PHYSFS_mkdir */
+
+
+static int doDelete(const char *_fname, char *fname)
+{
+    int retval;
+    DirHandle *h;
+    BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), ERRPASS, 0);
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
+    h = writeDir;
+    BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), ERRPASS, stateLock, 0);
+    retval = h->funcs->remove(h->opaque, fname);
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    return retval;
+} /* doDelete */
+
+
+int PHYSFS_delete(const char *_fname)
+{
+    int retval;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    retval = doDelete(_fname, fname);
+    __PHYSFS_smallFree(fname);
+    return retval;
+} /* PHYSFS_delete */
+
+
+const char *PHYSFS_getRealDir(const char *_fname)
+{
+    const char *retval = NULL;
+    char *fname = NULL;
+    size_t len;
+
+    BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
+    len = strlen(_fname) + 1;
+    fname = __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        DirHandle *i;
+        __PHYSFS_platformGrabMutex(stateLock);
+        for (i = searchPath; i != NULL; i = i->next)
+        {
+            char *arcfname = fname;
+            if (partOfMountPoint(i, arcfname))
+            {
+                retval = i->dirName;
+                break;
+            } /* if */
+            else if (verifyPath(i, &arcfname, 0))
+            {
+                PHYSFS_Stat statbuf;
+                int exists = 0;
+                if (i->funcs->stat(i->opaque, arcfname, &exists, &statbuf))
+                {
+                    if (exists)
+                        retval = i->dirName;
+                    break;
+                } /* if */
+            } /* if */
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return retval;
+} /* PHYSFS_getRealDir */
+
+
+static int locateInStringList(const char *str,
+                              char **list,
+                              PHYSFS_uint32 *pos)
+{
+    PHYSFS_uint32 len = *pos;
+    PHYSFS_uint32 half_len;
+    PHYSFS_uint32 lo = 0;
+    PHYSFS_uint32 middle;
+    int cmp;
+
+    while (len > 0)
+    {
+        half_len = len >> 1;
+        middle = lo + half_len;
+        cmp = strcmp(list[middle], str);
+
+        if (cmp == 0)  /* it's in the list already. */
+            return 1;
+        else if (cmp > 0)
+            len = half_len;
+        else
+        {
+            lo = middle + 1;
+            len -= half_len + 1;
+        } /* else */
+    } /* while */
+
+    *pos = lo;
+    return 0;
+} /* locateInStringList */
+
+
+static void enumFilesCallback(void *data, const char *origdir, const char *str)
+{
+    PHYSFS_uint32 pos;
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    /*
+     * See if file is in the list already, and if not, insert it in there
+     *  alphabetically...
+     */
+    pos = pecd->size;
+    if (locateInStringList(str, pecd->list, &pos))
+        return;  /* already in the list. */
+
+    ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = (char *) allocator.Malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+        return;  /* better luck next time. */
+
+    strcpy(newstr, str);
+
+    if (pos != pecd->size)
+    {
+        memmove(&pecd->list[pos+1], &pecd->list[pos],
+                 sizeof (char *) * ((pecd->size) - pos));
+    } /* if */
+
+    pecd->list[pos] = newstr;
+    pecd->size++;
+} /* enumFilesCallback */
+
+
+char **PHYSFS_enumerateFiles(const char *path)
+{
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) allocator.Malloc(sizeof (char *));
+    BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd);
+    ecd.list[ecd.size] = NULL;
+    return ecd.list;
+} /* PHYSFS_enumerateFiles */
+
+
+/*
+ * Broke out to seperate function so we can use stack allocation gratuitously.
+ */
+static void enumerateFromMountPoint(DirHandle *i, const char *arcfname,
+                                    PHYSFS_EnumFilesCallback callback,
+                                    const char *_fname, void *data)
+{
+    const size_t len = strlen(arcfname);
+    char *ptr = NULL;
+    char *end = NULL;
+    const size_t slen = strlen(i->mountPoint) + 1;
+    char *mountPoint = (char *) __PHYSFS_smallAlloc(slen);
+
+    if (mountPoint == NULL)
+        return;  /* oh well. */
+
+    strcpy(mountPoint, i->mountPoint);
+    ptr = mountPoint + ((len) ? len + 1 : 0);
+    end = strchr(ptr, '/');
+    assert(end);  /* should always find a terminating '/'. */
+    *end = '\0';
+    callback(data, _fname, ptr);
+    __PHYSFS_smallFree(mountPoint);
+} /* enumerateFromMountPoint */
+
+
+/* !!! FIXME: this should report error conditions. */
+void PHYSFS_enumerateFilesCallback(const char *_fname,
+                                   PHYSFS_EnumFilesCallback callback,
+                                   void *data)
+{
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
+    BAIL_IF_MACRO(!callback, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/;
+
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/;
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        DirHandle *i;
+        int noSyms;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+        noSyms = !allowSymLinks;
+        for (i = searchPath; i != NULL; i = i->next)
+        {
+            char *arcfname = fname;
+            if (partOfMountPoint(i, arcfname))
+                enumerateFromMountPoint(i, arcfname, callback, _fname, data);
+
+            else if (verifyPath(i, &arcfname, 0))
+            {
+                i->funcs->enumerateFiles(i->opaque, arcfname, noSyms,
+                                         callback, _fname, data);
+            } /* else if */
+        } /* for */
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+} /* PHYSFS_enumerateFilesCallback */
+
+
+int PHYSFS_exists(const char *fname)
+{
+    return (PHYSFS_getRealDir(fname) != NULL);
+} /* PHYSFS_exists */
+
+
+PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname)
+{
+    PHYSFS_Stat statbuf;
+    BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, -1);
+    return statbuf.modtime;
+} /* PHYSFS_getLastModTime */
+
+
+int PHYSFS_isDirectory(const char *fname)
+{
+    PHYSFS_Stat statbuf;
+    BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
+    return (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
+} /* PHYSFS_isDirectory */
+
+
+int PHYSFS_isSymbolicLink(const char *fname)
+{
+    PHYSFS_Stat statbuf;
+    BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0);
+    return (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
+} /* PHYSFS_isSymbolicLink */
+
+
+static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
+{
+    FileHandle *fh = NULL;
+    size_t len;
+    char *fname;
+
+    BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        PHYSFS_Io *io = NULL;
+        DirHandle *h = NULL;
+        const PHYSFS_Archiver *f;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+
+        GOTO_IF_MACRO(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd);
+
+        h = writeDir;
+        GOTO_IF_MACRO(!verifyPath(h, &fname, 0), ERRPASS, doOpenWriteEnd);
+
+        f = h->funcs;
+        if (appending)
+            io = f->openAppend(h->opaque, fname);
+        else
+            io = f->openWrite(h->opaque, fname);
+
+        GOTO_IF_MACRO(!io, ERRPASS, doOpenWriteEnd);
+
+        fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+        if (fh == NULL)
+        {
+            io->destroy(io);
+            GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd);
+        } /* if */
+        else
+        {
+            memset(fh, '\0', sizeof (FileHandle));
+            fh->io = io;
+            fh->dirHandle = h;
+            fh->next = openWriteList;
+            openWriteList = fh;
+        } /* else */
+
+        doOpenWriteEnd:
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return ((PHYSFS_File *) fh);
+} /* doOpenWrite */
+
+
+PHYSFS_File *PHYSFS_openWrite(const char *filename)
+{
+    return doOpenWrite(filename, 0);
+} /* PHYSFS_openWrite */
+
+
+PHYSFS_File *PHYSFS_openAppend(const char *filename)
+{
+    return doOpenWrite(filename, 1);
+} /* PHYSFS_openAppend */
+
+
+PHYSFS_File *PHYSFS_openRead(const char *_fname)
+{
+    FileHandle *fh = NULL;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        int fileExists = 0;
+        DirHandle *i = NULL;
+        PHYSFS_Io *io = NULL;
+
+        __PHYSFS_platformGrabMutex(stateLock);
+
+        GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd);
+
+        for (i = searchPath; (i != NULL) && (!fileExists); i = i->next)
+        {
+            char *arcfname = fname;
+            if (verifyPath(i, &arcfname, 0))
+            {
+                io = i->funcs->openRead(i->opaque, arcfname, &fileExists);
+                if (io)
+                    break;
+            } /* if */
+        } /* for */
+
+        GOTO_IF_MACRO(!io, ERRPASS, openReadEnd);
+
+        fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
+        if (fh == NULL)
+        {
+            io->destroy(io);
+            GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd);
+        } /* if */
+
+        memset(fh, '\0', sizeof (FileHandle));
+        fh->io = io;
+        fh->forReading = 1;
+        fh->dirHandle = i;
+        fh->next = openReadList;
+        openReadList = fh;
+
+        openReadEnd:
+        __PHYSFS_platformReleaseMutex(stateLock);
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return ((PHYSFS_File *) fh);
+} /* PHYSFS_openRead */
+
+
+static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
+{
+    FileHandle *prev = NULL;
+    FileHandle *i;
+    int rc = 1;
+
+    for (i = *list; i != NULL; i = i->next)
+    {
+        if (i == handle)  /* handle is in this list? */
+        {
+            PHYSFS_Io *io = handle->io;
+            PHYSFS_uint8 *tmp = handle->buffer;
+            rc = PHYSFS_flush((PHYSFS_File *) handle);
+            if (!rc)
+                return -1;
+            io->destroy(io);
+
+            if (tmp != NULL)  /* free any associated buffer. */
+                allocator.Free(tmp);
+
+            if (prev == NULL)
+                *list = handle->next;
+            else
+                prev->next = handle->next;
+
+            allocator.Free(handle);
+            return 1;
+        } /* if */
+        prev = i;
+    } /* for */
+
+    return 0;
+} /* closeHandleInOpenList */
+
+
+int PHYSFS_close(PHYSFS_File *_handle)
+{
+    FileHandle *handle = (FileHandle *) _handle;
+    int rc;
+
+    __PHYSFS_platformGrabMutex(stateLock);
+
+    /* -1 == close failure. 0 == not found. 1 == success. */
+    rc = closeHandleInOpenList(&openReadList, handle);
+    BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
+    if (!rc)
+    {
+        rc = closeHandleInOpenList(&openWriteList, handle);
+        BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0);
+    } /* if */
+
+    __PHYSFS_platformReleaseMutex(stateLock);
+    BAIL_IF_MACRO(!rc, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    return 1;
+} /* PHYSFS_close */
+
+
+static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer,
+                                    PHYSFS_uint64 len)
+{
+    PHYSFS_Io *io = NULL;
+    PHYSFS_sint64 retval = 0;
+    PHYSFS_uint32 buffered = 0;
+    PHYSFS_sint64 rc = 0;
+
+    if (len == 0)
+        return 0;
+
+    buffered = fh->buffill - fh->bufpos;
+    if (buffered >= len)  /* totally in the buffer, just copy and return! */
+    {
+        memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len);
+        fh->bufpos += (PHYSFS_uint32) len;
+        return (PHYSFS_sint64) len;
+    } /* else if */
+
+    if (buffered > 0) /* partially in the buffer... */
+    {
+        memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered);
+        buffer = ((PHYSFS_uint8 *) buffer) + buffered;
+        len -= buffered;
+        retval = buffered;
+        fh->buffill = fh->bufpos = 0;
+    } /* if */
+
+    /* if you got here, the buffer is drained and we still need bytes. */
+    assert(len > 0);
+
+    io = fh->io;
+    if (len >= fh->bufsize)  /* need more than the buffer takes. */
+    {
+        /* leave buffer empty, go right to output instead. */
+        rc = io->read(io, buffer, len);
+        if (rc < 0)
+            return ((retval == 0) ? rc : retval);
+        return retval + rc;
+    } /* if */
+
+    /* need less than buffer can take. Fill buffer. */
+    rc = io->read(io, fh->buffer, fh->bufsize);
+    if (rc < 0)
+        return ((retval == 0) ? rc : retval);
+
+    assert(fh->bufpos == 0);
+    fh->buffill = (PHYSFS_uint32) rc;
+    rc = doBufferedRead(fh, buffer, len);  /* go from the start, again. */
+    if (rc < 0)
+        return ((retval == 0) ? rc : retval);
+
+    return retval + rc;
+} /* doBufferedRead */
+
+
+PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer,
+                          PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
+    const PHYSFS_sint64 retval = PHYSFS_readBytes(handle, buffer, len);
+    return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
+} /* PHYSFS_read */
+
+
+PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
+                               PHYSFS_uint64 len)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+#ifdef PHYSFS_NO_64BIT_SUPPORT
+    const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
+#else
+    const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
+#endif
+
+    if (!__PHYSFS_ui64FitsAddressSpace(len))
+        BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+    BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+    BAIL_IF_MACRO(!fh->forReading, PHYSFS_ERR_OPEN_FOR_WRITING, -1);
+    BAIL_IF_MACRO(len == 0, ERRPASS, 0);
+    if (fh->buffer)
+        return doBufferedRead(fh, buffer, len);
+
+    return fh->io->read(fh->io, buffer, len);
+} /* PHYSFS_readBytes */
+
+
+static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer,
+                                     PHYSFS_uint64 len)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+    /* whole thing fits in the buffer? */
+    if ( (((PHYSFS_uint64) fh->buffill) + len) < fh->bufsize )
+    {
+        memcpy(fh->buffer + fh->buffill, buffer, (size_t) len);
+        fh->buffill += (PHYSFS_uint32) len;
+        return (PHYSFS_sint64) len;
+    } /* if */
+
+    /* would overflow buffer. Flush and then write the new objects, too. */
+    BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, -1);
+    return fh->io->write(fh->io, buffer, len);
+} /* doBufferedWrite */
+
+
+PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer,
+                           PHYSFS_uint32 size, PHYSFS_uint32 count)
+{
+    const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count);
+    const PHYSFS_sint64 retval = PHYSFS_writeBytes(handle, buffer, len);
+    return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) );
+} /* PHYSFS_write */
+
+
+PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer,
+                                PHYSFS_uint64 len)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+#ifdef PHYSFS_NO_64BIT_SUPPORT
+    const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF);
+#else
+    const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF);
+#endif
+
+    if (!__PHYSFS_ui64FitsAddressSpace(len))
+        BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+    BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+    BAIL_IF_MACRO(fh->forReading, PHYSFS_ERR_OPEN_FOR_READING, -1);
+    BAIL_IF_MACRO(len == 0, ERRPASS, 0);
+    if (fh->buffer)
+        return doBufferedWrite(handle, buffer, len);
+
+    return fh->io->write(fh->io, buffer, len);
+} /* PHYSFS_write */
+
+
+int PHYSFS_eof(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+
+    if (!fh->forReading)  /* never EOF on files opened for write/append. */
+        return 0;
+
+    /* can't be eof if buffer isn't empty */
+    if (fh->bufpos == fh->buffill)
+    {
+        /* check the Io. */
+        PHYSFS_Io *io = fh->io;
+        const PHYSFS_sint64 pos = io->tell(io);
+        const PHYSFS_sint64 len = io->length(io);
+        if ((pos < 0) || (len < 0))
+            return 0;  /* beats me. */
+        return (pos >= len);
+    } /* if */
+
+    return 0;
+} /* PHYSFS_eof */
+
+
+PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    const PHYSFS_sint64 pos = fh->io->tell(fh->io);
+    const PHYSFS_sint64 retval = fh->forReading ?
+                                 (pos - fh->buffill) + fh->bufpos :
+                                 (pos + fh->buffill);
+    return retval;
+} /* PHYSFS_tell */
+
+
+int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
+
+    if (fh->buffer && fh->forReading)
+    {
+        /* avoid throwing away our precious buffer if seeking within it. */
+        PHYSFS_sint64 offset = pos - PHYSFS_tell(handle);
+        if ( /* seeking within the already-buffered range? */
+            ((offset >= 0) && (offset <= fh->buffill - fh->bufpos)) /* fwd */
+            || ((offset < 0) && (-offset <= fh->bufpos)) /* backward */ )
+        {
+            fh->bufpos += (PHYSFS_uint32) offset;
+            return 1; /* successful seek */
+        } /* if */
+    } /* if */
+
+    /* we have to fall back to a 'raw' seek. */
+    fh->buffill = fh->bufpos = 0;
+    return fh->io->seek(fh->io, pos);
+} /* PHYSFS_seek */
+
+
+PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+{
+    PHYSFS_Io *io = ((FileHandle *) handle)->io;
+    return io->length(io);
+} /* PHYSFS_filelength */
+
+
+int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    PHYSFS_uint32 bufsize;
+
+    /* !!! FIXME: actually, why use 32 bits here? */
+    /*BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, "buffer must fit in 32-bits", 0);*/
+    BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, PHYSFS_ERR_INVALID_ARGUMENT, 0);
+    bufsize = (PHYSFS_uint32) _bufsize;
+
+    BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0);
+
+    /*
+     * For reads, we need to move the file pointer to where it would be
+     *  if we weren't buffering, so that the next read will get the
+     *  right chunk of stuff from the file. PHYSFS_flush() handles writes.
+     */
+    if ((fh->forReading) && (fh->buffill != fh->bufpos))
+    {
+        PHYSFS_uint64 pos;
+        const PHYSFS_sint64 curpos = fh->io->tell(fh->io);
+        BAIL_IF_MACRO(curpos == -1, ERRPASS, 0);
+        pos = ((curpos - fh->buffill) + fh->bufpos);
+        BAIL_IF_MACRO(!fh->io->seek(fh->io, pos), ERRPASS, 0);
+    } /* if */
+
+    if (bufsize == 0)  /* delete existing buffer. */
+    {
+        if (fh->buffer)
+        {
+            allocator.Free(fh->buffer);
+            fh->buffer = NULL;
+        } /* if */
+    } /* if */
+
+    else
+    {
+        PHYSFS_uint8 *newbuf;
+        newbuf = (PHYSFS_uint8 *) allocator.Realloc(fh->buffer, bufsize);
+        BAIL_IF_MACRO(!newbuf, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+        fh->buffer = newbuf;
+    } /* else */
+
+    fh->bufsize = bufsize;
+    fh->buffill = fh->bufpos = 0;
+    return 1;
+} /* PHYSFS_setBuffer */
+
+
+int PHYSFS_flush(PHYSFS_File *handle)
+{
+    FileHandle *fh = (FileHandle *) handle;
+    PHYSFS_Io *io;
+    PHYSFS_sint64 rc;
+
+    if ((fh->forReading) || (fh->bufpos == fh->buffill))
+        return 1;  /* open for read or buffer empty are successful no-ops. */
+
+    /* dump buffer to disk. */
+    io = fh->io;
+    rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
+    BAIL_IF_MACRO(rc <= 0, ERRPASS, 0);
+    fh->bufpos = fh->buffill = 0;
+    return io->flush(io);
+} /* PHYSFS_flush */
+
+
+int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
+{
+    int retval = 0;
+    char *fname;
+    size_t len;
+
+    BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+    BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, -1);
+    len = strlen(_fname) + 1;
+    fname = (char *) __PHYSFS_smallAlloc(len);
+    BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, -1);
+
+    /* set some sane defaults... */
+    stat->filesize = -1;
+    stat->modtime = -1;
+    stat->createtime = -1;
+    stat->accesstime = -1;
+    stat->filetype = PHYSFS_FILETYPE_OTHER;
+    stat->readonly = 1;  /* !!! FIXME */
+
+    if (sanitizePlatformIndependentPath(_fname, fname))
+    {
+        if (*fname == '\0')
+        {
+            stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+            stat->readonly = !writeDir; /* Writeable if we have a writeDir */
+            retval = 1;
+        } /* if */
+        else
+        {
+            DirHandle *i;
+            int exists = 0;
+            __PHYSFS_platformGrabMutex(stateLock);
+            for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
+            {
+                char *arcfname = fname;
+                exists = partOfMountPoint(i, arcfname);
+                if (exists)
+                {
+                    stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+                    stat->readonly = 1;  /* !!! FIXME */
+                    retval = 1;
+                } /* if */
+                else if (verifyPath(i, &arcfname, 0))
+                {
+                    /* !!! FIXME: this test is wrong and should be elsewhere. */
+                    stat->readonly = !(writeDir &&
+                                 (strcmp(writeDir->dirName, i->dirName) == 0));
+                    retval = i->funcs->stat(i->opaque, arcfname, &exists, stat);
+                } /* else if */
+            } /* for */
+            __PHYSFS_platformReleaseMutex(stateLock);
+        } /* else */
+    } /* if */
+
+    __PHYSFS_smallFree(fname);
+    return retval;
+} /* PHYSFS_stat */
+
+
+int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len)
+{
+    return (io->read(io, buf, len) == len);
+} /* __PHYSFS_readAll */
+
+
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len)
+{
+    void *useHeap = ((ptr == NULL) ? ((void *) 1) : ((void *) 0));
+    if (useHeap)  /* too large for stack allocation or alloca() failed. */
+        ptr = allocator.Malloc(len+sizeof (void *));
+
+    if (ptr != NULL)
+    {
+        void **retval = (void **) ptr;
+        /*printf("%s alloc'd (%d) bytes at (%p).\n",
+                useHeap ? "heap" : "stack", (int) len, ptr);*/
+        *retval = useHeap;
+        return retval + 1;
+    } /* if */
+
+    return NULL;  /* allocation failed. */
+} /* __PHYSFS_initSmallAlloc */
+
+
+void __PHYSFS_smallFree(void *ptr)
+{
+    if (ptr != NULL)
+    {
+        void **block = ((void **) ptr) - 1;
+        const int useHeap = (*block != 0);
+        if (useHeap)
+            allocator.Free(block);
+        /*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/
+    } /* if */
+} /* __PHYSFS_smallFree */
+
+
+int PHYSFS_setAllocator(const PHYSFS_Allocator *a)
+{
+    BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0);
+    externalAllocator = (a != NULL);
+    if (externalAllocator)
+        memcpy(&allocator, a, sizeof (PHYSFS_Allocator));
+
+    return 1;
+} /* PHYSFS_setAllocator */
+
+
+const PHYSFS_Allocator *PHYSFS_getAllocator(void)
+{
+    BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL);
+    return &allocator;
+} /* PHYSFS_getAllocator */
+
+
+static void *mallocAllocatorMalloc(PHYSFS_uint64 s)
+{
+    if (!__PHYSFS_ui64FitsAddressSpace(s))
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    #undef malloc
+    return malloc((size_t) s);
+} /* mallocAllocatorMalloc */
+
+
+static void *mallocAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+    if (!__PHYSFS_ui64FitsAddressSpace(s))
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    #undef realloc
+    return realloc(ptr, (size_t) s);
+} /* mallocAllocatorRealloc */
+
+
+static void mallocAllocatorFree(void *ptr)
+{
+    #undef free
+    free(ptr);
+} /* mallocAllocatorFree */
+
+
+static void setDefaultAllocator(void)
+{
+    assert(!externalAllocator);
+    if (!__PHYSFS_platformSetDefaultAllocator(&allocator))
+    {
+        allocator.Init = NULL;
+        allocator.Deinit = NULL;
+        allocator.Malloc = mallocAllocatorMalloc;
+        allocator.Realloc = mallocAllocatorRealloc;
+        allocator.Free = mallocAllocatorFree;
+    } /* if */
+} /* setDefaultAllocator */
+
+/* end of physfs.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,3324 @@
+/**
+ * \file physfs.h
+ *
+ * Main header file for PhysicsFS.
+ */
+
+/**
+ * \mainpage PhysicsFS
+ *
+ * The latest version of PhysicsFS can be found at:
+ *     http://icculus.org/physfs/
+ *
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * This API gives you access to a system file system in ways superior to the
+ *  stdio or system i/o calls. The brief benefits:
+ *
+ *   - It's portable.
+ *   - It's safe. No file access is permitted outside the specified dirs.
+ *   - It's flexible. Archives (.ZIP files) can be used transparently as
+ *      directory structures.
+ *
+ * This system is largely inspired by Quake 3's PK3 files and the related
+ *  fs_* cvars. If you've ever tinkered with these, then this API will be
+ *  familiar to you.
+ *
+ * With PhysicsFS, you have a single writing directory and multiple
+ *  directories (the "search path") for reading. You can think of this as a
+ *  filesystem within a filesystem. If (on Windows) you were to set the
+ *  writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls
+ *  could touch anything above this directory, including the "C:\MyGame" and
+ *  "C:\" directories. This prevents an application's internal scripting
+ *  language from piddling over c:\\config.sys, for example. If you'd rather
+ *  give PHYSFS full access to the system's REAL file system, set the writing
+ *  dir to "C:\", but that's generally A Bad Thing for several reasons.
+ *
+ * Drive letters are hidden in PhysicsFS once you set up your initial paths.
+ *  The search path creates a single, hierarchical directory structure.
+ *  Not only does this lend itself well to general abstraction with archives,
+ *  it also gives better support to operating systems like MacOS and Unix.
+ *  Generally speaking, you shouldn't ever hardcode a drive letter; not only
+ *  does this hurt portability to non-Microsoft OSes, but it limits your win32
+ *  users to a single drive, too. Use the PhysicsFS abstraction functions and
+ *  allow user-defined configuration options, too. When opening a file, you
+ *  specify it like it was on a Unix filesystem: if you want to write to
+ *  "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to
+ *  "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an
+ *  abstraction across all platforms. Specifying a file in this way is termed
+ *  "platform-independent notation" in this documentation. Specifying a
+ *  a filename in a form such as "C:\mydir\myfile" or
+ *  "MacOS hard drive:My Directory:My File" is termed "platform-dependent
+ *  notation". The only time you use platform-dependent notation is when
+ *  setting up your write directory and search path; after that, all file
+ *  access into those directories are done with platform-independent notation.
+ *
+ * All files opened for writing are opened in relation to the write directory,
+ *  which is the root of the writable filesystem. When opening a file for
+ *  reading, PhysicsFS goes through the search path. This is NOT the
+ *  same thing as the PATH environment variable. An application using
+ *  PhysicsFS specifies directories to be searched which may be actual
+ *  directories, or archive files that contain files and subdirectories of
+ *  their own. See the end of these docs for currently supported archive
+ *  formats.
+ *
+ * Once the search path is defined, you may open files for reading. If you've
+ *  got the following search path defined (to use a win32 example again):
+ *
+ *  - C:\\mygame
+ *  - C:\\mygame\\myuserfiles
+ *  - D:\\mygamescdromdatafiles
+ *  - C:\\mygame\\installeddatafiles.zip
+ *
+ * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory
+ *  separator, lack of drive letter, and lack of dir separator at the start of
+ *  the string; this is platform-independent notation) will check for
+ *  C:\\mygame\\textfiles\\myfile.txt, then
+ *  C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then
+ *  D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for
+ *  textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip.
+ *  Remember that most archive types and platform filesystems store their
+ *  filenames in a case-sensitive manner, so you should be careful to specify
+ *  it correctly.
+ *
+ * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir
+ *  elements. Not only are these meaningless on MacOS Classic and/or Unix,
+ *  they are a security hole. Also, symbolic links (which can be found in
+ *  some archive types and directly in the filesystem on Unix platforms) are
+ *  NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to
+ *  your own discretion, as following a symlink can allow for access outside
+ *  the write dir and search paths. For portability, there is no mechanism for
+ *  creating new symlinks in PhysicsFS.
+ *
+ * The write dir is not included in the search path unless you specifically
+ *  add it. While you CAN change the write dir as many times as you like,
+ *  you should probably set it once and stick to it. Remember that your
+ *  program will not have permission to write in every directory on Unix and
+ *  NT systems.
+ *
+ * All files are opened in binary mode; there is no endline conversion for
+ *  textfiles. Other than that, PhysicsFS has some convenience functions for
+ *  platform-independence. There is a function to tell you the current
+ *  platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS),
+ *  which is needed only to set up your search/write paths. There is a
+ *  function to tell you what CD-ROM drives contain accessible discs, and a
+ *  function to recommend a good search path, etc.
+ *
+ * A recommended order for the search path is the write dir, then the base dir,
+ *  then the cdrom dir, then any archives discovered. Quake 3 does something
+ *  like this, but moves the archives to the start of the search path. Build
+ *  Engine games, like Duke Nukem 3D and Blood, place the archives last, and
+ *  use the base dir for both searching and writing. There is a helper
+ *  function (PHYSFS_setSaneConfig()) that puts together a basic configuration
+ *  for you, based on a few parameters. Also see the comments on
+ *  PHYSFS_getBaseDir(), and PHYSFS_getPrefDir() for info on what those
+ *  are and how they can help you determine an optimal search path.
+ *
+ * PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points
+ *  in the search path. If a zipfile contains "maps/level.map" and you mount
+ *  that archive at "mods/mymod", then you would have to open
+ *  "mods/mymod/maps/level.map" to access the file, even though "mods/mymod"
+ *  isn't actually specified in the .zip file. Unlike the Unix mentality of
+ *  mounting a filesystem, "mods/mymod" doesn't actually have to exist when
+ *  mounting the zipfile. It's a "virtual" directory. The mounting mechanism
+ *  allows the developer to seperate archives in the tree and avoid trampling
+ *  over files when added new archives, such as including mod support in a
+ *  game...keeping external content on a tight leash in this manner can be of
+ *  utmost importance to some applications.
+ *
+ * PhysicsFS is mostly thread safe. The error messages returned by
+ *  PHYSFS_getLastError() are unique by thread, and library-state-setting
+ *  functions are mutex'd. For efficiency, individual file accesses are 
+ *  not locked, so you can not safely read/write/seek/close/etc the same 
+ *  file from two threads at the same time. Other race conditions are bugs 
+ *  that should be reported/patched.
+ *
+ * While you CAN use stdio/syscall file access in a program that has PHYSFS_*
+ *  calls, doing so is not recommended, and you can not use system
+ *  filehandles with PhysicsFS and vice versa.
+ *
+ * Note that archives need not be named as such: if you have a ZIP file and
+ *  rename it with a .PKG extension, the file will still be recognized as a
+ *  ZIP archive by PhysicsFS; the file's contents are used to determine its
+ *  type where possible.
+ *
+ * Currently supported archive types:
+ *   - .ZIP (pkZip/WinZip/Info-ZIP compatible)
+ *   - .7Z  (7zip archives)
+ *   - .ISO (ISO9660 files, CD-ROM images)
+ *   - .GRP (Build Engine groupfile archives)
+ *   - .PAK (Quake I/II archive format)
+ *   - .HOG (Descent I/II HOG file archives)
+ *   - .MVL (Descent II movielib archives)
+ *   - .WAD (DOOM engine archives)
+ *
+ *
+ * String policy for PhysicsFS 2.0 and later:
+ *
+ * PhysicsFS 1.0 could only deal with null-terminated ASCII strings. All high
+ *  ASCII chars resulted in undefined behaviour, and there was no Unicode
+ *  support at all. PhysicsFS 2.0 supports Unicode without breaking binary
+ *  compatibility with the 1.0 API by using UTF-8 encoding of all strings
+ *  passed in and out of the library.
+ *
+ * All strings passed through PhysicsFS are in null-terminated UTF-8 format.
+ *  This means that if all you care about is English (ASCII characters <= 127)
+ *  then you just use regular C strings. If you care about Unicode (and you
+ *  should!) then you need to figure out what your platform wants, needs, and
+ *  offers. If you are on Windows before Win2000 and build with Unicode
+ *  support, your TCHAR strings are two bytes per character (this is called
+ *  "UCS-2 encoding"). Any modern Windows uses UTF-16, which is two bytes
+ *  per character for most characters, but some characters are four. You
+ *  should convert them to UTF-8 before handing them to PhysicsFS with
+ *  PHYSFS_utf8FromUtf16(), which handles both UTF-16 and UCS-2. If you're
+ *  using Unix or Mac OS X, your wchar_t strings are four bytes per character
+ *  ("UCS-4 encoding"). Use PHYSFS_utf8FromUcs4(). Mac OS X can give you UTF-8
+ *  directly from a CFString or NSString, and many Unixes generally give you C
+ *  strings in UTF-8 format everywhere. If you have a single-byte high ASCII
+ *  charset, like so-many European "codepages" you may be out of luck. We'll
+ *  convert from "Latin1" to UTF-8 only, and never back to Latin1. If you're
+ *  above ASCII 127, all bets are off: move to Unicode or use your platform's
+ *  facilities. Passing a C string with high-ASCII data that isn't UTF-8
+ *  encoded will NOT do what you expect!
+ *
+ * Naturally, there's also PHYSFS_utf8ToUcs2(), PHYSFS_utf8ToUtf16(), and
+ *  PHYSFS_utf8ToUcs4() to get data back into a format you like. Behind the
+ *  scenes, PhysicsFS will use Unicode where possible: the UTF-8 strings on
+ *  Windows will be converted and used with the multibyte Windows APIs, for
+ *  example.
+ *
+ * PhysicsFS offers basic encoding conversion support, but not a whole string
+ *  library. Get your stuff into whatever format you can work with.
+ *
+ * All platforms supported by PhysicsFS 2.1 and later fully support Unicode.
+ *  We have dropped platforms that don't (OS/2, Mac OS 9, Windows 95, etc), as
+ *  even an OS that's over a decade old should be expected to handle this well.
+ *  If you absolutely must support one of these platforms, you should use an
+ *  older release of PhysicsFS.
+ *
+ * Many game-specific archivers are seriously unprepared for Unicode (the
+ *  Descent HOG/MVL and Build Engine GRP archivers, for example, only offer a
+ *  DOS 8.3 filename, for example). Nothing can be done for these, but they
+ *  tend to be legacy formats for existing content that was all ASCII (and
+ *  thus, valid UTF-8) anyhow. Other formats, like .ZIP, don't explicitly
+ *  offer Unicode support, but unofficially expect filenames to be UTF-8
+ *  encoded, and thus Just Work. Most everything does the right thing without
+ *  bothering you, but it's good to be aware of these nuances in case they
+ *  don't.
+ *
+ *
+ * Other stuff:
+ *
+ * Please see the file LICENSE.txt in the source's root directory for
+ *  licensing and redistribution rights.
+ *
+ * Please see the file CREDITS.txt in the source's "docs" directory for
+ *  a more or less complete list of who's responsible for this.
+ *
+ *  \author Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_H_
+#define _INCLUDE_PHYSFS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(PHYSFS_DECL)
+/* do nothing. */
+#elif (defined SWIG)
+#define PHYSFS_DECL extern
+#elif (defined _MSC_VER)
+#define PHYSFS_DECL __declspec(dllexport)
+#elif (defined __SUNPRO_C)
+#define PHYSFS_DECL __global
+#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
+#define PHYSFS_DECL __attribute__((visibility("default")))
+#else
+#define PHYSFS_DECL
+#endif
+
+#if defined(PHYSFS_DEPRECATED)
+/* do nothing. */
+#elif (defined SWIG)  /* ignore deprecated, since bindings use everything. */
+#define PHYSFS_DEPRECATED
+#elif (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
+#define PHYSFS_DEPRECATED __attribute__((deprecated))
+#else
+#define PHYSFS_DEPRECATED
+#endif
+
+#if 0  /* !!! FIXME: look into this later. */
+#if defined(PHYSFS_CALL)
+/* do nothing. */
+#elif defined(__WIN32__) && !defined(__GNUC__)
+#define PHYSFS_CALL __cdecl
+#else
+#define PHYSFS_CALL
+#endif
+#endif
+
+/**
+ * \typedef PHYSFS_uint8
+ * \brief An unsigned, 8-bit integer type.
+ */
+typedef unsigned char         PHYSFS_uint8;
+
+/**
+ * \typedef PHYSFS_sint8
+ * \brief A signed, 8-bit integer type.
+ */
+typedef signed char           PHYSFS_sint8;
+
+/**
+ * \typedef PHYSFS_uint16
+ * \brief An unsigned, 16-bit integer type.
+ */
+typedef unsigned short        PHYSFS_uint16;
+
+/**
+ * \typedef PHYSFS_sint16
+ * \brief A signed, 16-bit integer type.
+ */
+typedef signed short          PHYSFS_sint16;
+
+/**
+ * \typedef PHYSFS_uint32
+ * \brief An unsigned, 32-bit integer type.
+ */
+typedef unsigned int          PHYSFS_uint32;
+
+/**
+ * \typedef PHYSFS_sint32
+ * \brief A signed, 32-bit integer type.
+ */
+typedef signed int            PHYSFS_sint32;
+
+/**
+ * \typedef PHYSFS_uint64
+ * \brief An unsigned, 64-bit integer type.
+ * \warning on platforms without any sort of 64-bit datatype, this is
+ *           equivalent to PHYSFS_uint32!
+ */
+
+/**
+ * \typedef PHYSFS_sint64
+ * \brief A signed, 64-bit integer type.
+ * \warning on platforms without any sort of 64-bit datatype, this is
+ *           equivalent to PHYSFS_sint32!
+ */
+
+
+#if (defined PHYSFS_NO_64BIT_SUPPORT)  /* oh well. */
+typedef PHYSFS_uint32         PHYSFS_uint64;
+typedef PHYSFS_sint32         PHYSFS_sint64;
+#elif (defined _MSC_VER)
+typedef signed __int64        PHYSFS_sint64;
+typedef unsigned __int64      PHYSFS_uint64;
+#else
+typedef unsigned long long    PHYSFS_uint64;
+typedef signed long long      PHYSFS_sint64;
+#endif
+
+
+#ifndef SWIG
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+/* Make sure the types really have the right sizes */
+#define PHYSFS_COMPILE_TIME_ASSERT(name, x)               \
+       typedef int PHYSFS_dummy_ ## name[(x) * 2 - 1]
+
+PHYSFS_COMPILE_TIME_ASSERT(uint8, sizeof(PHYSFS_uint8) == 1);
+PHYSFS_COMPILE_TIME_ASSERT(sint8, sizeof(PHYSFS_sint8) == 1);
+PHYSFS_COMPILE_TIME_ASSERT(uint16, sizeof(PHYSFS_uint16) == 2);
+PHYSFS_COMPILE_TIME_ASSERT(sint16, sizeof(PHYSFS_sint16) == 2);
+PHYSFS_COMPILE_TIME_ASSERT(uint32, sizeof(PHYSFS_uint32) == 4);
+PHYSFS_COMPILE_TIME_ASSERT(sint32, sizeof(PHYSFS_sint32) == 4);
+
+#ifndef PHYSFS_NO_64BIT_SUPPORT
+PHYSFS_COMPILE_TIME_ASSERT(uint64, sizeof(PHYSFS_uint64) == 8);
+PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8);
+#endif
+
+#undef PHYSFS_COMPILE_TIME_ASSERT
+
+#endif  /* DOXYGEN_SHOULD_IGNORE_THIS */
+#endif  /* SWIG */
+
+
+/**
+ * \struct PHYSFS_File
+ * \brief A PhysicsFS file handle.
+ *
+ * You get a pointer to one of these when you open a file for reading,
+ *  writing, or appending via PhysicsFS.
+ *
+ * As you can see from the lack of meaningful fields, you should treat this
+ *  as opaque data. Don't try to manipulate the file handle, just pass the
+ *  pointer you got, unmolested, to various PhysicsFS APIs.
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_close
+ * \sa PHYSFS_read
+ * \sa PHYSFS_write
+ * \sa PHYSFS_seek
+ * \sa PHYSFS_tell
+ * \sa PHYSFS_eof
+ * \sa PHYSFS_setBuffer
+ * \sa PHYSFS_flush
+ */
+typedef struct PHYSFS_File
+{
+    void *opaque;  /**< That's all you get. Don't touch. */
+} PHYSFS_File;
+
+
+/**
+ * \def PHYSFS_file
+ * \brief 1.0 API compatibility define.
+ *
+ * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards
+ *  compatibility with the 1.0 API, which had an inconsistent capitalization
+ *  convention in this case. New code should use PHYSFS_File, as this #define
+ *  may go away someday.
+ *
+ * \sa PHYSFS_File
+ */
+#define PHYSFS_file PHYSFS_File
+
+
+/**
+ * \struct PHYSFS_ArchiveInfo
+ * \brief Information on various PhysicsFS-supported archives.
+ *
+ * This structure gives you details on what sort of archives are supported
+ *  by this implementation of PhysicsFS. Archives tend to be things like
+ *  ZIP files and such.
+ *
+ * \warning Not all binaries are created equal! PhysicsFS can be built with
+ *          or without support for various archives. You can check with
+ *          PHYSFS_supportedArchiveTypes() to see if your archive type is
+ *          supported.
+ *
+ * \sa PHYSFS_supportedArchiveTypes
+ */
+typedef struct PHYSFS_ArchiveInfo
+{
+    const char *extension;   /**< Archive file extension: "ZIP", for example. */
+    const char *description; /**< Human-readable archive description. */
+    const char *author;      /**< Person who did support for this archive. */
+    const char *url;         /**< URL related to this archive */
+} PHYSFS_ArchiveInfo;
+
+
+/**
+ * \struct PHYSFS_Version
+ * \brief Information the version of PhysicsFS in use.
+ *
+ * Represents the library's version as three levels: major revision
+ *  (increments with massive changes, additions, and enhancements),
+ *  minor revision (increments with backwards-compatible changes to the
+ *  major revision), and patchlevel (increments with fixes to the minor
+ *  revision).
+ *
+ * \sa PHYSFS_VERSION
+ * \sa PHYSFS_getLinkedVersion
+ */
+typedef struct PHYSFS_Version
+{
+    PHYSFS_uint8 major; /**< major revision */
+    PHYSFS_uint8 minor; /**< minor revision */
+    PHYSFS_uint8 patch; /**< patchlevel */
+} PHYSFS_Version;
+
+
+#ifndef SWIG  /* not available from scripting languages. */
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+#define PHYSFS_VER_MAJOR 2
+#define PHYSFS_VER_MINOR 1
+#define PHYSFS_VER_PATCH 0
+#endif  /* DOXYGEN_SHOULD_IGNORE_THIS */
+
+
+/* PhysicsFS state stuff ... */
+
+/**
+ * \def PHYSFS_VERSION(x)
+ * \brief Macro to determine PhysicsFS version program was compiled against.
+ *
+ * This macro fills in a PHYSFS_Version structure with the version of the
+ *  library you compiled against. This is determined by what header the
+ *  compiler uses. Note that if you dynamically linked the library, you might
+ *  have a slightly newer or older version at runtime. That version can be
+ *  determined with PHYSFS_getLinkedVersion(), which, unlike PHYSFS_VERSION,
+ *  is not a macro.
+ *
+ * \param x A pointer to a PHYSFS_Version struct to initialize.
+ *
+ * \sa PHYSFS_Version
+ * \sa PHYSFS_getLinkedVersion
+ */
+#define PHYSFS_VERSION(x) \
+{ \
+    (x)->major = PHYSFS_VER_MAJOR; \
+    (x)->minor = PHYSFS_VER_MINOR; \
+    (x)->patch = PHYSFS_VER_PATCH; \
+}
+
+#endif  /* SWIG */
+
+
+/**
+ * \fn void PHYSFS_getLinkedVersion(PHYSFS_Version *ver)
+ * \brief Get the version of PhysicsFS that is linked against your program.
+ *
+ * If you are using a shared library (DLL) version of PhysFS, then it is
+ *  possible that it will be different than the version you compiled against.
+ *
+ * This is a real function; the macro PHYSFS_VERSION tells you what version
+ *  of PhysFS you compiled against:
+ *
+ * \code
+ * PHYSFS_Version compiled;
+ * PHYSFS_Version linked;
+ *
+ * PHYSFS_VERSION(&compiled);
+ * PHYSFS_getLinkedVersion(&linked);
+ * printf("We compiled against PhysFS version %d.%d.%d ...\n",
+ *           compiled.major, compiled.minor, compiled.patch);
+ * printf("But we linked against PhysFS version %d.%d.%d.\n",
+ *           linked.major, linked.minor, linked.patch);
+ * \endcode
+ *
+ * This function may be called safely at any time, even before PHYSFS_init().
+ *
+ * \sa PHYSFS_VERSION
+ */
+PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver);
+
+
+/**
+ * \fn int PHYSFS_init(const char *argv0)
+ * \brief Initialize the PhysicsFS library.
+ *
+ * This must be called before any other PhysicsFS function.
+ *
+ * This should be called prior to any attempts to change your process's
+ *  current working directory.
+ *
+ *   \param argv0 the argv[0] string passed to your program's mainline.
+ *          This may be NULL on most platforms (such as ones without a
+ *          standard main() function), but you should always try to pass
+ *          something in here. Unix-like systems such as Linux _need_ to
+ *          pass argv[0] from main() in here.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_deinit
+ * \sa PHYSFS_isInit
+ */
+PHYSFS_DECL int PHYSFS_init(const char *argv0);
+
+
+/**
+ * \fn int PHYSFS_deinit(void)
+ * \brief Deinitialize the PhysicsFS library.
+ *
+ * This closes any files opened via PhysicsFS, blanks the search/write paths,
+ *  frees memory, and invalidates all of your file handles.
+ *
+ * Note that this call can FAIL if there's a file open for writing that
+ *  refuses to close (for example, the underlying operating system was
+ *  buffering writes to network filesystem, and the fileserver has crashed,
+ *  or a hard drive has failed, etc). It is usually best to close all write
+ *  handles yourself before calling this function, so that you can gracefully
+ *  handle a specific failure.
+ *
+ * Once successfully deinitialized, PHYSFS_init() can be called again to
+ *  restart the subsystem. All default API states are restored at this
+ *  point, with the exception of any custom allocator you might have
+ *  specified, which survives between initializations.
+ *
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is
+ *          undefined, and probably badly screwed up.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_isInit
+ */
+PHYSFS_DECL int PHYSFS_deinit(void);
+
+
+/**
+ * \fn const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void)
+ * \brief Get a list of supported archive types.
+ *
+ * Get a list of archive types supported by this implementation of PhysicFS.
+ *  These are the file formats usable for search path entries. This is for
+ *  informational purposes only. Note that the extension listed is merely
+ *  convention: if we list "ZIP", you can open a PkZip-compatible archive
+ *  with an extension of "XYZ", if you like.
+ *
+ * The returned value is an array of pointers to PHYSFS_ArchiveInfo structures,
+ *  with a NULL entry to signify the end of the list:
+ *
+ * \code
+ * PHYSFS_ArchiveInfo **i;
+ *
+ * for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++)
+ * {
+ *     printf("Supported archive: [%s], which is [%s].\n",
+ *              (*i)->extension, (*i)->description);
+ * }
+ * \endcode
+ *
+ * The return values are pointers to internal memory, and should
+ *  be considered READ ONLY, and never freed. The returned values are
+ *  valid until the next call to PHYSFS_deinit().
+ *
+ *   \return READ ONLY Null-terminated array of READ ONLY structures.
+ */
+PHYSFS_DECL const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void);
+
+
+/**
+ * \fn void PHYSFS_freeList(void *listVar)
+ * \brief Deallocate resources of lists returned by PhysicsFS.
+ *
+ * Certain PhysicsFS functions return lists of information that are
+ *  dynamically allocated. Use this function to free those resources.
+ *
+ * It is safe to pass a NULL here, but doing so will cause a crash in versions
+ *  before PhysicsFS 2.1.0.
+ *
+ *   \param listVar List of information specified as freeable by this function.
+ *                  Passing NULL is safe; it is a valid no-op.
+ *
+ * \sa PHYSFS_getCdRomDirs
+ * \sa PHYSFS_enumerateFiles
+ * \sa PHYSFS_getSearchPath
+ */
+PHYSFS_DECL void PHYSFS_freeList(void *listVar);
+
+
+/**
+ * \fn const char *PHYSFS_getLastError(void)
+ * \brief Get human-readable error information.
+ *
+ * \warning As of PhysicsFS 2.1, this function has been nerfed.
+ *          Before PhysicsFS 2.1, this function was the only way to get
+ *          error details beyond a given function's basic return value.
+ *          This was meant to be a human-readable string in one of several
+ *          languages, and was not useful for application parsing. This was
+ *          a problem, because the developer and not the user chose the
+ *          language at compile time, and the PhysicsFS maintainers had
+ *          to (poorly) maintain a significant amount of localization work.
+ *          The app couldn't parse the strings, even if they counted on a
+ *          specific language, since some were dynamically generated.
+ *          In 2.1 and later, this always returns a static string in
+ *          English; you may use it as a key string for your own
+ *          localizations if you like, as we'll promise not to change
+ *          existing error strings. Also, if your application wants to
+ *          look at specific errors, we now offer a better option:
+ *          use PHYSFS_getLastErrorCode() instead.
+ *
+ * Get the last PhysicsFS error message as a human-readable, null-terminated
+ *  string. This will return NULL if there's been no error since the last call
+ *  to this function. The pointer returned by this call points to an internal
+ *  buffer. Each thread has a unique error state associated with it, but each
+ *  time a new error message is set, it will overwrite the previous one
+ *  associated with that thread. It is safe to call this function at anytime,
+ *  even before PHYSFS_init().
+ *
+ * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same
+ *  thread-specific error state. Calling one will wipe out the other's
+ *  data. If you need both, call PHYSFS_getLastErrorCode(), then pass that
+ *  value to PHYSFS_getErrorByCode().
+ *
+ * As of PhysicsFS 2.1, this function only presents text in the English
+ *  language, but the strings are static, so you can use them as keys into
+ *  your own localization dictionary. These strings are meant to be passed on
+ *  directly to the user.
+ *
+ * Generally, applications should only concern themselves with whether a
+ *  given function failed; however, if your code require more specifics, you
+ *  should use PHYSFS_getLastErrorCode() instead of this function.
+ *
+ *   \return READ ONLY string of last error message.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ * \sa PHYSFS_getErrorByCode
+ */
+PHYSFS_DECL const char *PHYSFS_getLastError(void);
+
+
+/**
+ * \fn const char *PHYSFS_getDirSeparator(void)
+ * \brief Get platform-dependent dir separator string.
+ *
+ * This returns "\\" on win32, "/" on Unix, and ":" on MacOS. It may be more
+ *  than one character, depending on the platform, and your code should take
+ *  that into account. Note that this is only useful for setting up the
+ *  search/write paths, since access into those dirs always use '/'
+ *  (platform-independent notation) to separate directories. This is also
+ *  handy for getting platform-independent access when using stdio calls.
+ *
+ *   \return READ ONLY null-terminated string of platform's dir separator.
+ */
+PHYSFS_DECL const char *PHYSFS_getDirSeparator(void);
+
+
+/**
+ * \fn void PHYSFS_permitSymbolicLinks(int allow)
+ * \brief Enable or disable following of symbolic links.
+ *
+ * Some physical filesystems and archives contain files that are just pointers
+ *  to other files. On the physical filesystem, opening such a link will
+ *  (transparently) open the file that is pointed to.
+ *
+ * By default, PhysicsFS will check if a file is really a symlink during open
+ *  calls and fail if it is. Otherwise, the link could take you outside the
+ *  write and search paths, and compromise security.
+ *
+ * If you want to take that risk, call this function with a non-zero parameter.
+ *  Note that this is more for sandboxing a program's scripting language, in
+ *  case untrusted scripts try to compromise the system. Generally speaking,
+ *  a user could very well have a legitimate reason to set up a symlink, so
+ *  unless you feel there's a specific danger in allowing them, you should
+ *  permit them.
+ *
+ * Symlinks are only explicitly checked when dealing with filenames
+ *  in platform-independent notation. That is, when setting up your
+ *  search and write paths, etc, symlinks are never checked for.
+ *
+ * Please note that PHYSFS_stat() will always check the path specified; if
+ *  that path is a symlink, it will not be followed in any case. If symlinks
+ *  aren't permitted through this function, PHYSFS_stat() ignores them, and
+ *  would treat the query as if the path didn't exist at all.
+ *
+ * Symbolic link permission can be enabled or disabled at any time after
+ *  you've called PHYSFS_init(), and is disabled by default.
+ *
+ *   \param allow nonzero to permit symlinks, zero to deny linking.
+ *
+ * \sa PHYSFS_symbolicLinksPermitted
+ */
+PHYSFS_DECL void PHYSFS_permitSymbolicLinks(int allow);
+
+
+/* !!! FIXME: const this? */
+/**
+ * \fn char **PHYSFS_getCdRomDirs(void)
+ * \brief Get an array of paths to available CD-ROM drives.
+ *
+ * The dirs returned are platform-dependent ("D:\" on Win32, "/cdrom" or
+ *  whatnot on Unix). Dirs are only returned if there is a disc ready and
+ *  accessible in the drive. So if you've got two drives (D: and E:), and only
+ *  E: has a disc in it, then that's all you get. If the user inserts a disc
+ *  in D: and you call this function again, you get both drives. If, on a
+ *  Unix box, the user unmounts a disc and remounts it elsewhere, the next
+ *  call to this function will reflect that change.
+ *
+ * This function refers to "CD-ROM" media, but it really means "inserted disc
+ *  media," such as DVD-ROM, HD-DVD, CDRW, and Blu-Ray discs. It looks for
+ *  filesystems, and as such won't report an audio CD, unless there's a
+ *  mounted filesystem track on it.
+ *
+ * The returned value is an array of strings, with a NULL entry to signify the
+ *  end of the list:
+ *
+ * \code
+ * char **cds = PHYSFS_getCdRomDirs();
+ * char **i;
+ *
+ * for (i = cds; *i != NULL; i++)
+ *     printf("cdrom dir [%s] is available.\n", *i);
+ *
+ * PHYSFS_freeList(cds);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ * When you are done with the returned information, you may dispose of the
+ *  resources by calling PHYSFS_freeList() with the returned pointer.
+ *
+ *   \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ */
+PHYSFS_DECL char **PHYSFS_getCdRomDirs(void);
+
+
+/**
+ * \fn const char *PHYSFS_getBaseDir(void)
+ * \brief Get the path where the application resides.
+ *
+ * Helper function.
+ *
+ * Get the "base dir". This is the directory where the application was run
+ *  from, which is probably the installation directory, and may or may not
+ *  be the process's current working directory.
+ *
+ * You should probably use the base dir in your search path.
+ *
+ *  \return READ ONLY string of base dir in platform-dependent notation.
+ *
+ * \sa PHYSFS_getPrefDir
+ */
+PHYSFS_DECL const char *PHYSFS_getBaseDir(void);
+
+
+/**
+ * \fn const char *PHYSFS_getUserDir(void)
+ * \brief Get the path where user's home directory resides.
+ *
+ * \deprecated As of PhysicsFS 2.1, you probably want PHYSFS_getPrefDir().
+ *
+ * Helper function.
+ *
+ * Get the "user dir". This is meant to be a suggestion of where a specific
+ *  user of the system can store files. On Unix, this is her home directory.
+ *  On systems with no concept of multiple home directories (MacOS, win95),
+ *  this will default to something like "C:\mybasedir\users\username"
+ *  where "username" will either be the login name, or "default" if the
+ *  platform doesn't support multiple users, either.
+ *
+ *  \return READ ONLY string of user dir in platform-dependent notation.
+ *
+ * \sa PHYSFS_getBaseDir
+ * \sa PHYSFS_getPrefDir
+ */
+PHYSFS_DECL const char *PHYSFS_getUserDir(void) PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn const char *PHYSFS_getWriteDir(void)
+ * \brief Get path where PhysicsFS will allow file writing.
+ *
+ * Get the current write dir. The default write dir is NULL.
+ *
+ *  \return READ ONLY string of write dir in platform-dependent notation,
+ *           OR NULL IF NO WRITE PATH IS CURRENTLY SET.
+ *
+ * \sa PHYSFS_setWriteDir
+ */
+PHYSFS_DECL const char *PHYSFS_getWriteDir(void);
+
+
+/**
+ * \fn int PHYSFS_setWriteDir(const char *newDir)
+ * \brief Tell PhysicsFS where it may write files.
+ *
+ * Set a new write dir. This will override the previous setting.
+ *
+ * This call will fail (and fail to change the write dir) if the current
+ *  write dir still has files open in it.
+ *
+ *   \param newDir The new directory to be the root of the write dir,
+ *                   specified in platform-dependent notation. Setting to NULL
+ *                   disables the write dir, so no files can be opened for
+ *                   writing via PhysicsFS.
+ *  \return non-zero on success, zero on failure. All attempts to open a file
+ *           for writing via PhysicsFS will fail until this call succeeds.
+ *           Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_getWriteDir
+ */
+PHYSFS_DECL int PHYSFS_setWriteDir(const char *newDir);
+
+
+/**
+ * \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * \deprecated As of PhysicsFS 2.0, use PHYSFS_mount() instead. This
+ *             function just wraps it anyhow.
+ *
+ * This function is equivalent to:
+ *
+ * \code
+ *  PHYSFS_mount(newDir, NULL, appendToPath);
+ * \endcode
+ *
+ * You must use this and not PHYSFS_mount if binary compatibility with
+ *  PhysicsFS 1.0 is important (which it may not be for many people).
+ *
+ * \sa PHYSFS_mount
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ */
+PHYSFS_DECL int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
+                                        PHYSFS_DEPRECATED;
+
+/**
+ * \fn int PHYSFS_removeFromSearchPath(const char *oldDir)
+ * \brief Remove a directory or archive from the search path.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_unmount() instead. This
+ *             function just wraps it anyhow. There's no functional difference
+ *             except the vocabulary changed from "adding to the search path"
+ *             to "mounting" when that functionality was extended, and thus
+ *             the preferred way to accomplish this function's work is now
+ *             called "unmounting."
+ *
+ * This function is equivalent to:
+ *
+ * \code
+ *  PHYSFS_unmount(oldDir);
+ * \endcode
+ *
+ * You must use this and not PHYSFS_unmount if binary compatibility with
+ *  PhysicsFS 1.0 is important (which it may not be for many people).
+ *
+ * \sa PHYSFS_addToSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_unmount
+ */
+PHYSFS_DECL int PHYSFS_removeFromSearchPath(const char *oldDir)
+                                            PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn char **PHYSFS_getSearchPath(void)
+ * \brief Get the current search path.
+ *
+ * The default search path is an empty list.
+ *
+ * The returned value is an array of strings, with a NULL entry to signify the
+ *  end of the list:
+ *
+ * \code
+ * char **i;
+ *
+ * for (i = PHYSFS_getSearchPath(); *i != NULL; i++)
+ *     printf("[%s] is in the search path.\n", *i);
+ * \endcode
+ *
+ * When you are done with the returned information, you may dispose of the
+ *  resources by calling PHYSFS_freeList() with the returned pointer.
+ *
+ *   \return Null-terminated array of null-terminated strings. NULL if there
+ *            was a problem (read: OUT OF MEMORY).
+ *
+ * \sa PHYSFS_getSearchPathCallback
+ * \sa PHYSFS_addToSearchPath
+ * \sa PHYSFS_removeFromSearchPath
+ */
+PHYSFS_DECL char **PHYSFS_getSearchPath(void);
+
+
+/**
+ * \fn int PHYSFS_setSaneConfig(const char *organization, const char *appName, const char *archiveExt, int includeCdRoms, int archivesFirst)
+ * \brief Set up sane, default paths.
+ *
+ * Helper function.
+ *
+ * The write dir will be set to the pref dir returned by
+ *  \code PHYSFS_getPrefDir(organization, appName) \endcode, which is
+ *  created if it doesn't exist.
+ *
+ * The above is sufficient to make sure your program's configuration directory
+ *  is separated from other clutter, and platform-independent.
+ *
+ *  The search path will be:
+ *
+ *    - The Write Dir (created if it doesn't exist)
+ *    - The Base Dir (PHYSFS_getBaseDir())
+ *    - All found CD-ROM dirs (optionally)
+ *
+ * These directories are then searched for files ending with the extension
+ *  (archiveExt), which, if they are valid and supported archives, will also
+ *  be added to the search path. If you specified "PKG" for (archiveExt), and
+ *  there's a file named data.PKG in the base dir, it'll be checked. Archives
+ *  can either be appended or prepended to the search path in alphabetical
+ *  order, regardless of which directories they were found in. All archives
+ *  are mounted in the root of the virtual file system ("/").
+ *
+ * All of this can be accomplished from the application, but this just does it
+ *  all for you. Feel free to add more to the search path manually, too.
+ *
+ *    \param organization Name of your company/group/etc to be used as a
+ *                         dirname, so keep it small, and no-frills.
+ *
+ *    \param appName Program-specific name of your program, to separate it
+ *                   from other programs using PhysicsFS.
+ *
+ *    \param archiveExt File extension used by your program to specify an
+ *                      archive. For example, Quake 3 uses "pk3", even though
+ *                      they are just zipfiles. Specify NULL to not dig out
+ *                      archives automatically. Do not specify the '.' char;
+ *                      If you want to look for ZIP files, specify "ZIP" and
+ *                      not ".ZIP" ... the archive search is case-insensitive.
+ *
+ *    \param includeCdRoms Non-zero to include CD-ROMs in the search path, and
+ *                         (if (archiveExt) != NULL) search them for archives.
+ *                         This may cause a significant amount of blocking
+ *                         while discs are accessed, and if there are no discs
+ *                         in the drive (or even not mounted on Unix systems),
+ *                         then they may not be made available anyhow. You may
+ *                         want to specify zero and handle the disc setup
+ *                         yourself.
+ *
+ *    \param archivesFirst Non-zero to prepend the archives to the search path.
+ *                          Zero to append them. Ignored if !(archiveExt).
+ *
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_setSaneConfig(const char *organization,
+                                     const char *appName,
+                                     const char *archiveExt,
+                                     int includeCdRoms,
+                                     int archivesFirst);
+
+
+/* Directory management stuff ... */
+
+/**
+ * \fn int PHYSFS_mkdir(const char *dirName)
+ * \brief Create a directory.
+ *
+ * This is specified in platform-independent notation in relation to the
+ *  write dir. All missing parent directories are also created if they
+ *  don't exist.
+ *
+ * So if you've got the write dir set to "C:\mygame\writedir" and call
+ *  PHYSFS_mkdir("downloads/maps") then the directories
+ *  "C:\mygame\writedir\downloads" and "C:\mygame\writedir\downloads\maps"
+ *  will be created if possible. If the creation of "maps" fails after we
+ *  have successfully created "downloads", then the function leaves the
+ *  created directory behind and reports failure.
+ *
+ *   \param dirName New dir to create.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_delete
+ */
+PHYSFS_DECL int PHYSFS_mkdir(const char *dirName);
+
+
+/**
+ * \fn int PHYSFS_delete(const char *filename)
+ * \brief Delete a file or directory.
+ *
+ * (filename) is specified in platform-independent notation in relation to the
+ *  write dir.
+ *
+ * A directory must be empty before this call can delete it.
+ *
+ * Deleting a symlink will remove the link, not what it points to, regardless
+ *  of whether you "permitSymLinks" or not.
+ *
+ * So if you've got the write dir set to "C:\mygame\writedir" and call
+ *  PHYSFS_delete("downloads/maps/level1.map") then the file
+ *  "C:\mygame\writedir\downloads\maps\level1.map" is removed from the
+ *  physical filesystem, if it exists and the operating system permits the
+ *  deletion.
+ *
+ * Note that on Unix systems, deleting a file may be successful, but the
+ *  actual file won't be removed until all processes that have an open
+ *  filehandle to it (including your program) close their handles.
+ *
+ * Chances are, the bits that make up the file still exist, they are just
+ *  made available to be written over at a later point. Don't consider this
+ *  a security method or anything.  :)
+ *
+ *   \param filename Filename to delete.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_delete(const char *filename);
+
+
+/**
+ * \fn const char *PHYSFS_getRealDir(const char *filename)
+ * \brief Figure out where in the search path a file resides.
+ *
+ * The file is specified in platform-independent notation. The returned
+ *  filename will be the element of the search path where the file was found,
+ *  which may be a directory, or an archive. Even if there are multiple
+ *  matches in different parts of the search path, only the first one found
+ *  is used, just like when opening a file.
+ *
+ * So, if you look for "maps/level1.map", and C:\\mygame is in your search
+ *  path and C:\\mygame\\maps\\level1.map exists, then "C:\mygame" is returned.
+ *
+ * If a any part of a match is a symbolic link, and you've not explicitly
+ *  permitted symlinks, then it will be ignored, and the search for a match
+ *  will continue.
+ *
+ * If you specify a fake directory that only exists as a mount point, it'll
+ *  be associated with the first archive mounted there, even though that
+ *  directory isn't necessarily contained in a real archive.
+ *
+ * \warning This will return NULL if there is no real directory associated
+ *          with (filename). Specifically, PHYSFS_mountIo(),
+ *          PHYSFS_mountMemory(), and PHYSFS_mountHandle() will return NULL
+ *          even if the filename is found in the search path. Plan accordingly.
+ *
+ *     \param filename file to look for.
+ *    \return READ ONLY string of element of search path containing the
+ *             the file in question. NULL if not found.
+ */
+PHYSFS_DECL const char *PHYSFS_getRealDir(const char *filename);
+
+
+/**
+ * \fn char **PHYSFS_enumerateFiles(const char *dir)
+ * \brief Get a file listing of a search path's directory.
+ *
+ * Matching directories are interpolated. That is, if "C:\mydir" is in the
+ *  search path and contains a directory "savegames" that contains "x.sav",
+ *  "y.sav", and "z.sav", and there is also a "C:\userdir" in the search path
+ *  that has a "savegames" subdirectory with "w.sav", then the following code:
+ *
+ * \code
+ * char **rc = PHYSFS_enumerateFiles("savegames");
+ * char **i;
+ *
+ * for (i = rc; *i != NULL; i++)
+ *     printf(" * We've got [%s].\n", *i);
+ *
+ * PHYSFS_freeList(rc);
+ * \endcode
+ *
+ *  \...will print:
+ *
+ * \verbatim
+ * We've got [x.sav].
+ * We've got [y.sav].
+ * We've got [z.sav].
+ * We've got [w.sav].\endverbatim
+ *
+ * Feel free to sort the list however you like. We only promise there will
+ *  be no duplicates, but not what order the final list will come back in.
+ *
+ * Don't forget to call PHYSFS_freeList() with the return value from this
+ *  function when you are done with it.
+ *
+ *    \param dir directory in platform-independent notation to enumerate.
+ *   \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+PHYSFS_DECL char **PHYSFS_enumerateFiles(const char *dir);
+
+
+/**
+ * \fn int PHYSFS_exists(const char *fname)
+ * \brief Determine if a file exists in the search path.
+ *
+ * Reports true if there is an entry anywhere in the search path by the
+ *  name of (fname).
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
+ *  might end up further down in the search path than expected.
+ *
+ *    \param fname filename in platform-independent notation.
+ *   \return non-zero if filename exists. zero otherwise.
+ */
+PHYSFS_DECL int PHYSFS_exists(const char *fname);
+
+
+/**
+ * \fn int PHYSFS_isDirectory(const char *fname)
+ * \brief Determine if a file in the search path is really a directory.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ *             function just wraps it anyhow.
+ *
+ * Determine if the first occurence of (fname) in the search path is
+ *  really a directory entry.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, so you
+ *  might end up further down in the search path than expected.
+ *
+ *    \param fname filename in platform-independent notation.
+ *   \return non-zero if filename exists and is a directory.  zero otherwise.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_exists
+ */
+PHYSFS_DECL int PHYSFS_isDirectory(const char *fname) PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn int PHYSFS_isSymbolicLink(const char *fname)
+ * \brief Determine if a file in the search path is really a symbolic link.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ *             function just wraps it anyhow.
+ *
+ * Determine if the first occurence of (fname) in the search path is
+ *  really a symbolic link.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and as such,
+ *  this function will always return 0 in that case.
+ *
+ *    \param fname filename in platform-independent notation.
+ *   \return non-zero if filename exists and is a symlink.  zero otherwise.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_exists
+ */
+PHYSFS_DECL int PHYSFS_isSymbolicLink(const char *fname) PHYSFS_DEPRECATED;
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
+ * \brief Get the last modification time of a file.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ *             function just wraps it anyhow.
+ *
+ * The modtime is returned as a number of seconds since the Unix epoch
+ *  (midnight, Jan 1, 1970). The exact derivation and accuracy of this time
+ *  depends on the particular archiver. If there is no reasonable way to
+ *  obtain this information for a particular archiver, or there was some sort
+ *  of error, this function returns (-1).
+ *
+ * You must use this and not PHYSFS_stat() if binary compatibility with
+ *  PhysicsFS 2.0 is important (which it may not be for many people).
+ *
+ *   \param filename filename to check, in platform-independent notation.
+ *  \return last modified time of the file. -1 if it can't be determined.
+ *
+ * \sa PHYSFS_stat
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
+                                                PHYSFS_DEPRECATED;
+
+
+/* i/o stuff... */
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openWrite(const char *filename)
+ * \brief Open a file for writing.
+ *
+ * Open a file for writing, in platform-independent notation and in relation
+ *  to the write dir as the root of the writable filesystem. The specified
+ *  file is created if it doesn't exist. If it does exist, it is truncated to
+ *  zero bytes, and the writing offset is set to the start.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL PHYSFS_File *PHYSFS_openWrite(const char *filename);
+
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openAppend(const char *filename)
+ * \brief Open a file for appending.
+ *
+ * Open a file for writing, in platform-independent notation and in relation
+ *  to the write dir as the root of the writable filesystem. The specified
+ *  file is created if it doesn't exist. If it does exist, the writing offset
+ *  is set to the end of the file, so the first write will be the byte after
+ *  the end.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL PHYSFS_File *PHYSFS_openAppend(const char *filename);
+
+
+/**
+ * \fn PHYSFS_File *PHYSFS_openRead(const char *filename)
+ * \brief Open a file for reading.
+ *
+ * Open a file for reading, in platform-independent notation. The search path
+ *  is checked one at a time until a matching file is found, in which case an
+ *  abstract filehandle is associated with it, and reading may be done.
+ *  The reading offset is set to the first byte of the file.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_read
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL PHYSFS_File *PHYSFS_openRead(const char *filename);
+
+
+/**
+ * \fn int PHYSFS_close(PHYSFS_File *handle)
+ * \brief Close a PhysicsFS filehandle.
+ *
+ * This call is capable of failing if the operating system was buffering
+ *  writes to the physical media, and, now forced to write those changes to
+ *  physical media, can not store the data for some reason. In such a case,
+ *  the filehandle stays open. A well-written program should ALWAYS check the
+ *  return value from the close call in addition to every writing call!
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ */
+PHYSFS_DECL int PHYSFS_close(PHYSFS_File *handle);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+ * \brief Read data from a PhysicsFS filehandle
+ *
+ * The file must be opened for reading.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_readBytes() instead. This
+ *             function just wraps it anyhow. This function never clarified
+ *             what would happen if you managed to read a partial object, so
+ *             working at the byte level makes this cleaner for everyone,
+ *             especially now that PHYSFS_Io interfaces can be supplied by the
+ *             application.
+ *
+ *   \param handle handle returned from PHYSFS_openRead().
+ *   \param buffer buffer to store read data into.
+ *   \param objSize size in bytes of objects being read from (handle).
+ *   \param objCount number of (objSize) objects to read from (handle).
+ *  \return number of objects read. PHYSFS_getLastError() can shed light on
+ *           the reason this might be < (objCount), as can PHYSFS_eof().
+ *            -1 if complete failure.
+ *
+ * \sa PHYSFS_readBytes
+ * \sa PHYSFS_eof
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle,
+                                      void *buffer,
+                                      PHYSFS_uint32 objSize,
+                                      PHYSFS_uint32 objCount)
+                                        PHYSFS_DEPRECATED;
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
+ * \brief Write data to a PhysicsFS filehandle
+ *
+ * The file must be opened for writing.
+ *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_writeBytes() instead. This
+ *             function just wraps it anyhow. This function never clarified
+ *             what would happen if you managed to write a partial object, so
+ *             working at the byte level makes this cleaner for everyone,
+ *             especially now that PHYSFS_Io interfaces can be supplied by the
+ *             application.
+ *
+ *   \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
+ *   \param buffer buffer of bytes to write to (handle).
+ *   \param objSize size in bytes of objects being written to (handle).
+ *   \param objCount number of (objSize) objects to write to (handle).
+ *  \return number of objects written. PHYSFS_getLastError() can shed light on
+ *           the reason this might be < (objCount). -1 if complete failure.
+ *
+ * \sa PHYSFS_writeBytes
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle,
+                                       const void *buffer,
+                                       PHYSFS_uint32 objSize,
+                                       PHYSFS_uint32 objCount)
+                                        PHYSFS_DEPRECATED;
+
+
+/* File position stuff... */
+
+/**
+ * \fn int PHYSFS_eof(PHYSFS_File *handle)
+ * \brief Check for end-of-file state on a PhysicsFS filehandle.
+ *
+ * Determine if the end of file has been reached in a PhysicsFS filehandle.
+ *
+ *   \param handle handle returned from PHYSFS_openRead().
+ *  \return nonzero if EOF, zero if not.
+ *
+ * \sa PHYSFS_read
+ * \sa PHYSFS_tell
+ */
+PHYSFS_DECL int PHYSFS_eof(PHYSFS_File *handle);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle)
+ * \brief Determine current position within a PhysicsFS filehandle.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return offset in bytes from start of file. -1 if error occurred.
+ *           Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_seek
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle);
+
+
+/**
+ * \fn int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos)
+ * \brief Seek to a new position within a PhysicsFS filehandle.
+ *
+ * The next read or write will occur at that place. Seeking past the
+ *  beginning or end of the file is not allowed, and causes an error.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *   \param pos number of bytes from start of file to seek to.
+ *  \return nonzero on success, zero on error. Specifics of the error can be
+ *          gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_tell
+ */
+PHYSFS_DECL int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle)
+ * \brief Get total length of a file in bytes.
+ *
+ * Note that if another process/thread is writing to this file at the same
+ *  time, then the information this function supplies could be incorrect
+ *  before you get it. Use with caution, or better yet, don't use at all.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return size in bytes of the file. -1 if can't be determined.
+ *
+ * \sa PHYSFS_tell
+ * \sa PHYSFS_seek
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle);
+
+
+/* Buffering stuff... */
+
+/**
+ * \fn int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize)
+ * \brief Set up buffering for a PhysicsFS file handle.
+ *
+ * Define an i/o buffer for a file handle. A memory block of (bufsize) bytes
+ *  will be allocated and associated with (handle).
+ *
+ * For files opened for reading, up to (bufsize) bytes are read from (handle)
+ *  and stored in the internal buffer. Calls to PHYSFS_read() will pull
+ *  from this buffer until it is empty, and then refill it for more reading.
+ *  Note that compressed files, like ZIP archives, will decompress while
+ *  buffering, so this can be handy for offsetting CPU-intensive operations.
+ *  The buffer isn't filled until you do your next read.
+ *
+ * For files opened for writing, data will be buffered to memory until the
+ *  buffer is full or the buffer is flushed. Closing a handle implicitly
+ *  causes a flush...check your return values!
+ *
+ * Seeking, etc transparently accounts for buffering.
+ *
+ * You can resize an existing buffer by calling this function more than once
+ *  on the same file. Setting the buffer size to zero will free an existing
+ *  buffer.
+ *
+ * PhysicsFS file handles are unbuffered by default.
+ *
+ * Please check the return value of this function! Failures can include
+ *  not being able to seek backwards in a read-only file when removing the
+ *  buffer, not being able to allocate the buffer, and not being able to
+ *  flush the buffer to disk, among other unexpected problems.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *   \param bufsize size, in bytes, of buffer to allocate.
+ *  \return nonzero if successful, zero on error.
+ *
+ * \sa PHYSFS_flush
+ * \sa PHYSFS_read
+ * \sa PHYSFS_write
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize);
+
+
+/**
+ * \fn int PHYSFS_flush(PHYSFS_File *handle)
+ * \brief Flush a buffered PhysicsFS file handle.
+ *
+ * For buffered files opened for writing, this will put the current contents
+ *  of the buffer to disk and flag the buffer as empty if possible.
+ *
+ * For buffered files opened for reading or unbuffered files, this is a safe
+ *  no-op, and will report success.
+ *
+ *   \param handle handle returned from PHYSFS_open*().
+ *  \return nonzero if successful, zero on error.
+ *
+ * \sa PHYSFS_setBuffer
+ * \sa PHYSFS_close
+ */
+PHYSFS_DECL int PHYSFS_flush(PHYSFS_File *handle);
+
+
+/* Byteorder stuff... */
+
+#ifndef SWIG  /* not available from scripting languages. */
+
+/**
+ * \fn PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val)
+ * \brief Swap littleendian signed 16 to platform's native byte order.
+ *
+ * Take a 16-bit signed value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val);
+
+
+/**
+ * \fn PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val)
+ * \brief Swap littleendian unsigned 16 to platform's native byte order.
+ *
+ * Take a 16-bit unsigned value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val);
+
+/**
+ * \fn PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val)
+ * \brief Swap littleendian signed 32 to platform's native byte order.
+ *
+ * Take a 32-bit signed value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val);
+
+
+/**
+ * \fn PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val)
+ * \brief Swap littleendian unsigned 32 to platform's native byte order.
+ *
+ * Take a 32-bit unsigned value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val);
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val)
+ * \brief Swap littleendian signed 64 to platform's native byte order.
+ *
+ * Take a 64-bit signed value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val);
+
+
+/**
+ * \fn PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val)
+ * \brief Swap littleendian unsigned 64 to platform's native byte order.
+ *
+ * Take a 64-bit unsigned value in littleendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val);
+
+
+/**
+ * \fn PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val)
+ * \brief Swap bigendian signed 16 to platform's native byte order.
+ *
+ * Take a 16-bit signed value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val);
+
+
+/**
+ * \fn PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val)
+ * \brief Swap bigendian unsigned 16 to platform's native byte order.
+ *
+ * Take a 16-bit unsigned value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val);
+
+/**
+ * \fn PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val)
+ * \brief Swap bigendian signed 32 to platform's native byte order.
+ *
+ * Take a 32-bit signed value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val);
+
+
+/**
+ * \fn PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val)
+ * \brief Swap bigendian unsigned 32 to platform's native byte order.
+ *
+ * Take a 32-bit unsigned value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ */
+PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val);
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val)
+ * \brief Swap bigendian signed 64 to platform's native byte order.
+ *
+ * Take a 64-bit signed value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val);
+
+
+/**
+ * \fn PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val)
+ * \brief Swap bigendian unsigned 64 to platform's native byte order.
+ *
+ * Take a 64-bit unsigned value in bigendian format and convert it to
+ *  the platform's native byte order.
+ *
+ *    \param val value to convert
+ *   \return converted value.
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val);
+
+#endif  /* SWIG */
+
+
+/**
+ * \fn int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+ * \brief Read and convert a signed 16-bit littleendian value.
+ *
+ * Convenience function. Read a signed 16-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+ * \brief Read and convert an unsigned 16-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 16-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val)
+ * \brief Read and convert a signed 16-bit bigendian value.
+ *
+ * Convenience function. Read a signed 16-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val)
+ * \brief Read and convert an unsigned 16-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 16-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val);
+
+
+/**
+ * \fn int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+ * \brief Read and convert a signed 32-bit littleendian value.
+ *
+ * Convenience function. Read a signed 32-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+ * \brief Read and convert an unsigned 32-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 32-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val)
+ * \brief Read and convert a signed 32-bit bigendian value.
+ *
+ * Convenience function. Read a signed 32-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val)
+ * \brief Read and convert an unsigned 32-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 32-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ */
+PHYSFS_DECL int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val);
+
+
+/**
+ * \fn int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+ * \brief Read and convert a signed 64-bit littleendian value.
+ *
+ * Convenience function. Read a signed 64-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+ * \brief Read and convert an unsigned 64-bit littleendian value.
+ *
+ * Convenience function. Read an unsigned 64-bit littleendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val)
+ * \brief Read and convert a signed 64-bit bigendian value.
+ *
+ * Convenience function. Read a signed 64-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val);
+
+
+/**
+ * \fn int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val)
+ * \brief Read and convert an unsigned 64-bit bigendian value.
+ *
+ * Convenience function. Read an unsigned 64-bit bigendian value from a
+ *  file and convert it to the platform's native byte order.
+ *
+ *    \param file PhysicsFS file handle from which to read.
+ *    \param val pointer to where value should be stored.
+ *   \return zero on failure, non-zero on success. If successful, (*val) will
+ *           store the result. On failure, you can find out what went wrong
+ *           from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val)
+ * \brief Convert and write a signed 16-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 16-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val)
+ * \brief Convert and write an unsigned 16-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 16-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val)
+ * \brief Convert and write a signed 16-bit bigendian value.
+ *
+ * Convenience function. Convert a signed 16-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val)
+ * \brief Convert and write an unsigned 16-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 16-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val)
+ * \brief Convert and write a signed 32-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 32-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val)
+ * \brief Convert and write an unsigned 32-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 32-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val)
+ * \brief Convert and write a signed 32-bit bigendian value.
+ *
+ * Convenience function. Convert a signed 32-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val)
+ * \brief Convert and write an unsigned 32-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 32-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ */
+PHYSFS_DECL int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val);
+
+
+/**
+ * \fn int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val)
+ * \brief Convert and write a signed 64-bit littleendian value.
+ *
+ * Convenience function. Convert a signed 64-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val)
+ * \brief Convert and write an unsigned 64-bit littleendian value.
+ *
+ * Convenience function. Convert an unsigned 64-bit value from the platform's
+ *  native byte order to littleendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val)
+ * \brief Convert and write a signed 64-bit bigending value.
+ *
+ * Convenience function. Convert a signed 64-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val);
+
+
+/**
+ * \fn int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val)
+ * \brief Convert and write an unsigned 64-bit bigendian value.
+ *
+ * Convenience function. Convert an unsigned 64-bit value from the platform's
+ *  native byte order to bigendian and write it to a file.
+ *
+ *    \param file PhysicsFS file handle to which to write.
+ *    \param val Value to convert and write.
+ *   \return zero on failure, non-zero on success. On failure, you can
+ *           find out what went wrong from PHYSFS_getLastError().
+ *
+ * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without
+ *          any sort of 64-bit support.
+ */
+PHYSFS_DECL int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val);
+
+
+/* Everything above this line is part of the PhysicsFS 1.0 API. */
+
+/**
+ * \fn int PHYSFS_isInit(void)
+ * \brief Determine if the PhysicsFS library is initialized.
+ *
+ * Once PHYSFS_init() returns successfully, this will return non-zero.
+ *  Before a successful PHYSFS_init() and after PHYSFS_deinit() returns
+ *  successfully, this will return zero. This function is safe to call at
+ *  any time.
+ *
+ *  \return non-zero if library is initialized, zero if library is not.
+ *
+ * \sa PHYSFS_init
+ * \sa PHYSFS_deinit
+ */
+PHYSFS_DECL int PHYSFS_isInit(void);
+
+
+/**
+ * \fn int PHYSFS_symbolicLinksPermitted(void)
+ * \brief Determine if the symbolic links are permitted.
+ *
+ * This reports the setting from the last call to PHYSFS_permitSymbolicLinks().
+ *  If PHYSFS_permitSymbolicLinks() hasn't been called since the library was
+ *  last initialized, symbolic links are implicitly disabled.
+ *
+ *  \return non-zero if symlinks are permitted, zero if not.
+ *
+ * \sa PHYSFS_permitSymbolicLinks
+ */
+PHYSFS_DECL int PHYSFS_symbolicLinksPermitted(void);
+
+
+#ifndef SWIG  /* not available from scripting languages. */
+
+/**
+ * \struct PHYSFS_Allocator
+ * \brief PhysicsFS allocation function pointers.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * You create one of these structures for use with PHYSFS_setAllocator.
+ *  Allocators are assumed to be reentrant by the caller; please mutex
+ *  accordingly.
+ *
+ * Allocations are always discussed in 64-bits, for future expansion...we're
+ *  on the cusp of a 64-bit transition, and we'll probably be allocating 6
+ *  gigabytes like it's nothing sooner or later, and I don't want to change
+ *  this again at that point. If you're on a 32-bit platform and have to
+ *  downcast, it's okay to return NULL if the allocation is greater than
+ *  4 gigabytes, since you'd have to do so anyhow.
+ *
+ * \sa PHYSFS_setAllocator
+ */
+typedef struct PHYSFS_Allocator
+{
+    int (*Init)(void);   /**< Initialize. Can be NULL. Zero on failure. */
+    void (*Deinit)(void);  /**< Deinitialize your allocator. Can be NULL. */
+    void *(*Malloc)(PHYSFS_uint64);  /**< Allocate like malloc(). */
+    void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */
+    void (*Free)(void *); /**< Free memory from Malloc or Realloc. */
+} PHYSFS_Allocator;
+
+
+/**
+ * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator)
+ * \brief Hook your own allocation routines into PhysicsFS.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * By default, PhysicsFS will use whatever is reasonable for a platform
+ *  to manage dynamic memory (usually ANSI C malloc/realloc/free, but
+ *  some platforms might use something else), but in some uncommon cases, the
+ *  app might want more control over the library's memory management. This
+ *  lets you redirect PhysicsFS to use your own allocation routines instead.
+ *  You can only call this function before PHYSFS_init(); if the library is
+ *  initialized, it'll reject your efforts to change the allocator mid-stream.
+ *  You may call this function after PHYSFS_deinit() if you are willing to
+ *  shut down the library and restart it with a new allocator; this is a safe
+ *  and supported operation. The allocator remains intact between deinit/init
+ *  calls. If you want to return to the platform's default allocator, pass a
+ *  NULL in here.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ *  safely ignore it altogether.
+ *
+ *    \param allocator Structure containing your allocator's entry points.
+ *   \return zero on failure, non-zero on success. This call only fails
+ *           when used between PHYSFS_init() and PHYSFS_deinit() calls.
+ */
+PHYSFS_DECL int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
+
+#endif  /* SWIG */
+
+
+/**
+ * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
+ * \brief Add an archive or directory to the search path.
+ *
+ * If this is a duplicate, the entry is not added again, even though the
+ *  function succeeds. You may not add the same archive to two different
+ *  mountpoints: duplicate checking is done against the archive and not the
+ *  mountpoint.
+ *
+ * When you mount an archive, it is added to a virtual file system...all files
+ *  in all of the archives are interpolated into a single hierachical file
+ *  tree. Two archives mounted at the same place (or an archive with files
+ *  overlapping another mountpoint) may have overlapping files: in such a case,
+ *  the file earliest in the search path is selected, and the other files are
+ *  inaccessible to the application. This allows archives to be used to
+ *  override previous revisions; you can use the mounting mechanism to place
+ *  archives at a specific point in the file tree and prevent overlap; this
+ *  is useful for downloadable mods that might trample over application data
+ *  or each other, for example.
+ *
+ * The mountpoint does not need to exist prior to mounting, which is different
+ *  than those familiar with the Unix concept of "mounting" may not expect.
+ *  As well, more than one archive can be mounted to the same mountpoint, or
+ *  mountpoints and archive contents can overlap...the interpolation mechanism
+ *  still functions as usual.
+ *
+ *   \param newDir directory or archive to add to the path, in
+ *                   platform-dependent notation.
+ *   \param mountPoint Location in the interpolated tree that this archive
+ *                     will be "mounted", in platform-independent notation.
+ *                     NULL or "" is equivalent to "/".
+ *   \param appendToPath nonzero to append to search path, zero to prepend.
+ *  \return nonzero if added to path, zero on failure (bogus archive, dir
+ *                   missing, etc). Specifics of the error can be
+ *                   gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ * \sa PHYSFS_mountIo
+ */
+PHYSFS_DECL int PHYSFS_mount(const char *newDir,
+                             const char *mountPoint,
+                             int appendToPath);
+
+/**
+ * \fn int PHYSFS_getMountPoint(const char *dir)
+ * \brief Determine a mounted archive's mountpoint.
+ *
+ * You give this function the name of an archive or dir you successfully
+ *  added to the search path, and it reports the location in the interpolated
+ *  tree where it is mounted. Files mounted with a NULL mountpoint or through
+ *  PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY
+ *  and valid until the archive is removed from the search path.
+ *
+ *   \param dir directory or archive previously added to the path, in
+ *              platform-dependent notation. This must match the string
+ *              used when adding, even if your string would also reference
+ *              the same file with a different string of characters.
+ *  \return READ-ONLY string of mount point if added to path, NULL on failure
+ *          (bogus archive, etc) Specifics of the error can be gleaned from
+ *          PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_removeFromSearchPath
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL const char *PHYSFS_getMountPoint(const char *dir);
+
+
+#ifndef SWIG  /* not available from scripting languages. */
+
+/**
+ * \typedef PHYSFS_StringCallback
+ * \brief Function signature for callbacks that report strings.
+ *
+ * These are used to report a list of strings to an original caller, one
+ *  string per callback. All strings are UTF-8 encoded. Functions should not
+ *  try to modify or free the string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ *  functions that would return lists that need to be cleaned up with
+ *  PHYSFS_freeList(). The callback means that the library doesn't need to
+ *  allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ *  necessarily so in the callback versions. Check the documentation on
+ *  specific APIs, but strings may not be sorted as you expect.
+ *
+ *    \param data User-defined data pointer, passed through from the API
+ *                that eventually called the callback.
+ *    \param str The string data about which the callback is meant to inform.
+ *
+ * \sa PHYSFS_getCdRomDirsCallback
+ * \sa PHYSFS_getSearchPathCallback
+ */
+typedef void (*PHYSFS_StringCallback)(void *data, const char *str);
+
+
+/**
+ * \typedef PHYSFS_EnumFilesCallback
+ * \brief Function signature for callbacks that enumerate files.
+ *
+ * These are used to report a list of directory entries to an original caller,
+ *  one file/dir/symlink per callback. All strings are UTF-8 encoded.
+ *  Functions should not try to modify or free any string's memory.
+ *
+ * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to
+ *  functions that would return lists that need to be cleaned up with
+ *  PHYSFS_freeList(). The callback means that the library doesn't need to
+ *  allocate an entire list and all the strings up front.
+ *
+ * Be aware that promises data ordering in the list versions are not
+ *  necessarily so in the callback versions. Check the documentation on
+ *  specific APIs, but strings may not be sorted as you expect.
+ *
+ *    \param data User-defined data pointer, passed through from the API
+ *                that eventually called the callback.
+ *    \param origdir A string containing the full path, in platform-independent
+ *                   notation, of the directory containing this file. In most
+ *                   cases, this is the directory on which you requested
+ *                   enumeration, passed in the callback for your convenience.
+ *    \param fname The filename that is being enumerated. It may not be in
+ *                 alphabetical order compared to other callbacks that have
+ *                 fired, and it will not contain the full path. You can
+ *                 recreate the fullpath with $origdir/$fname ... The file
+ *                 can be a subdirectory, a file, a symlink, etc.
+ *
+ * \sa PHYSFS_enumerateFilesCallback
+ */
+typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir,
+                                         const char *fname);
+
+
+/**
+ * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate CD-ROM directories, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getCdRomDirs(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  detected disc:
+ *
+ * \code
+ *
+ * static void foundDisc(void *data, const char *cddir)
+ * {
+ *     printf("cdrom dir [%s] is available.\n", cddir);
+ * }
+ *
+ * // ...
+ * PHYSFS_getCdRomDirsCallback(foundDisc, NULL);
+ * \endcode
+ *
+ * This call may block while drives spin up. Be forewarned.
+ *
+ *    \param c Callback function to notify about detected drives.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getCdRomDirs
+ */
+PHYSFS_DECL void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d)
+ * \brief Enumerate the search path, using an application-defined callback.
+ *
+ * Internally, PHYSFS_getSearchPath() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_getSearchPath(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  element of the search path:
+ *
+ * \code
+ *
+ * static void printSearchPath(void *data, const char *pathItem)
+ * {
+ *     printf("[%s] is in the search path.\n", pathItem);
+ * }
+ *
+ * // ...
+ * PHYSFS_getSearchPathCallback(printSearchPath, NULL);
+ * \endcode
+ *
+ * Elements of the search path are reported in order search priority, so the
+ *  first archive/dir that would be examined when looking for a file is the
+ *  first element passed through the callback.
+ *
+ *    \param c Callback function to notify about search path elements.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_StringCallback
+ * \sa PHYSFS_getSearchPath
+ */
+PHYSFS_DECL void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d);
+
+
+/**
+ * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d)
+ * \brief Get a file listing of a search path's directory, using an application-defined callback.
+ *
+ * Internally, PHYSFS_enumerateFiles() just calls this function and then builds
+ *  a list before returning to the application, so functionality is identical
+ *  except for how the information is represented to the application.
+ *
+ * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
+ *  Rather, it calls a function specified by the application once per
+ *  element of the search path:
+ *
+ * \code
+ *
+ * static void printDir(void *data, const char *origdir, const char *fname)
+ * {
+ *     printf(" * We've got [%s] in [%s].\n", fname, origdir);
+ * }
+ *
+ * // ...
+ * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL);
+ * \endcode
+ *
+ * !!! FIXME: enumerateFiles() does not promise alphabetical sorting by
+ * !!! FIXME:  case-sensitivity in the code, and doesn't promise sorting at
+ * !!! FIXME:  all in the above docs.
+ *
+ * Items sent to the callback are not guaranteed to be in any order whatsoever.
+ *  There is no sorting done at this level, and if you need that, you should
+ *  probably use PHYSFS_enumerateFiles() instead, which guarantees
+ *  alphabetical sorting. This form reports whatever is discovered in each
+ *  archive before moving on to the next. Even within one archive, we can't
+ *  guarantee what order it will discover data. <em>Any sorting you find in
+ *  these callbacks is just pure luck. Do not rely on it.</em> As this walks
+ *  the entire list of archives, you may receive duplicate filenames.
+ *
+ *    \param dir Directory, in platform-independent notation, to enumerate.
+ *    \param c Callback function to notify about search path elements.
+ *    \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_EnumFilesCallback
+ * \sa PHYSFS_enumerateFiles
+ */
+PHYSFS_DECL void PHYSFS_enumerateFilesCallback(const char *dir,
+                                               PHYSFS_EnumFilesCallback c,
+                                               void *d);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-4 string to a UTF-8 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is the same size as the source buffer. UTF-8
+ *  never uses more than 32-bits per character, so while it may shrink a UCS-4
+ *  string, it will never expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UCS-4 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst,
+                                     PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UCS-4 string.
+ *
+ * UCS-4 strings are 32-bits per character: \c wchar_t on Unix.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is four times the size of the source buffer.
+ *  UTF-8 uses from one to four bytes per character, but UCS-4 always uses
+ *  four, so an entirely low-ASCII string will quadruple in size!
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UCS-4
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UTF-8 format.
+ *   \param dst Buffer to store converted UCS-4 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst,
+                                   PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UCS-2 string to a UTF-8 string.
+ *
+ * \warning you almost certainly should use PHYSFS_utf8FromUtf16(), which
+ *  became available in PhysicsFS 2.1, unless you know what you're doing.
+ *
+ * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
+ *  with Unicode support. Please note that modern versions of Windows use
+ *  UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You
+ *  almost certainly want PHYSFS_utf8FromUtf16() instead.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 never uses more than 32-bits per character, so while it may shrink
+ *  a UCS-2 string, it may also expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UCS-2 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ *
+ * \sa PHYSFS_utf8FromUtf16
+ */
+PHYSFS_DECL void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst,
+                                     PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UCS-2 string.
+ *
+ * \warning you almost certainly should use PHYSFS_utf8ToUtf16(), which
+ *  became available in PhysicsFS 2.1, unless you know what you're doing.
+ *
+ * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building
+ *  with Unicode support. Please note that modern versions of Windows use
+ *  UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You
+ *  almost certainly want PHYSFS_utf8ToUtf16() instead, but you need to
+ *  understand how that changes things, too.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 uses from one to four bytes per character, but UCS-2 always uses
+ *  two, so an entirely low-ASCII string will double in size!
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UCS-2
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UTF-8 format.
+ *   \param dst Buffer to store converted UCS-2 string.
+ *   \param len Size, in bytes, of destination buffer.
+ *
+ * \sa PHYSFS_utf8ToUtf16
+ */
+PHYSFS_DECL void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst,
+                                   PHYSFS_uint64 len);
+
+/**
+ * \fn void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a Latin1 string.
+ *
+ * Latin1 strings are 8-bits per character: a popular "high ASCII" encoding.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 expands latin1 codepoints over 127 from 1 to 2 bytes, so the string
+ *  may grow in some cases.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1
+ *  can't express most Unicode codepoints. It's a legacy encoding; you should
+ *  be converting away from it at all times.
+ *
+ *   \param src Null-terminated source string in Latin1 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8FromLatin1(const char *src, char *dst,
+                                       PHYSFS_uint64 len);
+
+/* Everything above this line is part of the PhysicsFS 2.0 API. */
+
+/**
+ * \fn int PHYSFS_unmount(const char *oldDir)
+ * \brief Remove a directory or archive from the search path.
+ *
+ * This is functionally equivalent to PHYSFS_removeFromSearchPath(), but that
+ *  function is deprecated to keep the vocabulary paired with PHYSFS_mount().
+ *
+ * This must be a (case-sensitive) match to a dir or archive already in the
+ *  search path, specified in platform-dependent notation.
+ *
+ * This call will fail (and fail to remove from the path) if the element still
+ *  has files open in it.
+ *
+ *    \param oldDir dir/archive to remove.
+ *   \return nonzero on success, zero on failure.
+ *            Specifics of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_mount
+ */
+PHYSFS_DECL int PHYSFS_unmount(const char *oldDir);
+
+/**
+ * \fn const PHYSFS_Allocator *PHYSFS_getAllocator(void)
+ * \brief Discover the current allocator.
+ *
+ * (This is for limited, hardcore use. If you don't immediately see a need
+ *  for it, you can probably ignore this forever.)
+ *
+ * This function exposes the function pointers that make up the currently used
+ *  allocator. This can be useful for apps that want to access PhysicsFS's
+ *  internal, default allocation routines, as well as for external code that
+ *  wants to share the same allocator, even if the application specified their
+ *  own.
+ *
+ * This call is only valid between PHYSFS_init() and PHYSFS_deinit() calls;
+ *  it will return NULL if the library isn't initialized. As we can't
+ *  guarantee the state of the internal allocators unless the library is
+ *  initialized, you shouldn't use any allocator returned here after a call
+ *  to PHYSFS_deinit().
+ *
+ * Do not call the returned allocator's Init() or Deinit() methods under any
+ *  circumstances.
+ *
+ * If you aren't immediately sure what to do with this function, you can
+ *  safely ignore it altogether.
+ *
+ *  \return Current allocator, as set by PHYSFS_setAllocator(), or PhysicsFS's
+ *          internal, default allocator if no application defined allocator
+ *          is currently set. Will return NULL if the library is not
+ *          initialized.
+ *
+ * \sa PHYSFS_Allocator
+ * \sa PHYSFS_setAllocator
+ */
+PHYSFS_DECL const PHYSFS_Allocator *PHYSFS_getAllocator(void);
+
+#endif  /* SWIG */
+
+/**
+ * \enum PHYSFS_FileType
+ * \brief Type of a File
+ *
+ * Possible types of a file.
+ *
+ * \sa PHYSFS_stat
+ */
+typedef enum PHYSFS_FileType
+{
+	PHYSFS_FILETYPE_REGULAR, /**< a normal file */
+	PHYSFS_FILETYPE_DIRECTORY, /**< a directory */
+	PHYSFS_FILETYPE_SYMLINK, /**< a symlink */
+	PHYSFS_FILETYPE_OTHER /**< something completely different like a device */
+} PHYSFS_FileType;
+
+/**
+ * \struct PHYSFS_Stat
+ * \brief Meta data for a file or directory
+ *
+ * Container for various meta data about a file in the virtual file system.
+ *  PHYSFS_stat() uses this structure for returning the information. The time
+ *  data will be either the number of seconds since the Unix epoch (midnight,
+ *  Jan 1, 1970), or -1 if the information isn't available or applicable.
+ *  The (filesize) field is measured in bytes.
+ *  The (readonly) field tells you whether when you open a file for writing you
+ *  are writing to the same file as if you were opening it, given you have
+ *  enough filesystem rights to do that.  !!! FIXME: this might change.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_FileType
+ */
+typedef struct PHYSFS_Stat
+{
+	PHYSFS_sint64 filesize; /**< size in bytes, -1 for non-files and unknown */
+	PHYSFS_sint64 modtime;  /**< last modification time */
+	PHYSFS_sint64 createtime; /**< like modtime, but for file creation time */
+	PHYSFS_sint64 accesstime; /**< like modtime, but for file access time */
+	PHYSFS_FileType filetype; /**< File? Directory? Symlink? */
+	int readonly; /**< non-zero if read only, zero if writable. */
+} PHYSFS_Stat;
+
+/**
+ * \fn int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat)
+ * \brief Get various information about a directory or a file.
+ *
+ * Obtain various information about a file or directory from the meta data.
+ *
+ * This function will never follow symbolic links. If you haven't enabled
+ *  symlinks with PHYSFS_permitSymbolicLinks(), stat'ing a symlink will be
+ *  treated like stat'ing a non-existant file. If symlinks are enabled,
+ *  stat'ing a symlink will give you information on the link itself and not
+ *  what it points to.
+ *
+ *    \param fname filename to check, in platform-indepedent notation.
+ *    \param stat pointer to structure to fill in with data about (fname).
+ *   \return non-zero on success, zero on failure. On failure, (stat)'s
+ *           contents are undefined.
+ *
+ * \sa PHYSFS_Stat
+ */
+PHYSFS_DECL int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat);
+
+
+#ifndef SWIG  /* not available from scripting languages. */
+
+/**
+ * \fn void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-16 string to a UTF-8 string.
+ *
+ * UTF-16 strings are 16-bits per character (except some chars, which are
+ *  32-bits): \c TCHAR on Windows, when building with Unicode support. Modern
+ *  Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but
+ *  only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that
+ *  are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you
+ *  aren't sure, you should be using UTF-16 at this point on Windows.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 never uses more than 32-bits per character, so while it may shrink
+ *  a UTF-16 string, it may also expand it.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-8
+ *  sequence at the end. If the buffer length is 0, this function does nothing.
+ *
+ *   \param src Null-terminated source string in UTF-16 format.
+ *   \param dst Buffer to store converted UTF-8 string.
+ *   \param len Size, in bytes, of destination buffer.
+ */
+PHYSFS_DECL void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst,
+                                      PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+ * \brief Convert a UTF-8 string to a UTF-16 string.
+ *
+ * UTF-16 strings are 16-bits per character (except some chars, which are
+ *  32-bits): \c TCHAR on Windows, when building with Unicode support. Modern
+ *  Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but
+ *  only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that
+ *  are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you
+ *  aren't sure, you should be using UTF-16 at this point on Windows.
+ *
+ * To ensure that the destination buffer is large enough for the conversion,
+ *  please allocate a buffer that is double the size of the source buffer.
+ *  UTF-8 uses from one to four bytes per character, but UTF-16 always uses
+ *  two to four, so an entirely low-ASCII string will double in size! The
+ *  UTF-16 characters that would take four bytes also take four bytes in UTF-8,
+ *  so you don't need to allocate 4x the space just in case: double will do.
+ *
+ * Strings that don't fit in the destination buffer will be truncated, but
+ *  will always be null-terminated and never have an incomplete UTF-16
+ *  surrogate pair at the end. If the buffer length is 0, this function does
+ *  nothing.
+ *
+ *   \param src Null-terminated source string in UTF-8 format.
+ *   \param dst Buffer to store converted UTF-16 string.
+ *   \param len Size, in bytes, of destination buffer.
+ *
+ * \sa PHYSFS_utf8ToUtf16
+ */
+PHYSFS_DECL void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst,
+                                    PHYSFS_uint64 len);
+
+#endif  /* SWIG */
+
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer, PHYSFS_uint64 len)
+ * \brief Read bytes from a PhysicsFS filehandle
+ *
+ * The file must be opened for reading.
+ *
+ *   \param handle handle returned from PHYSFS_openRead().
+ *   \param buffer buffer of at least (len) bytes to store read data into.
+ *   \param len number of bytes being read from (handle).
+ *  \return number of bytes read. This may be less than (len); this does not
+ *          signify an error, necessarily (a short read may mean EOF).
+ *          PHYSFS_getLastError() can shed light on the reason this might
+ *          be < (len), as can PHYSFS_eof(). -1 if complete failure.
+ *
+ * \sa PHYSFS_eof
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer,
+                                           PHYSFS_uint64 len);
+
+/**
+ * \fn PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer, PHYSFS_uint64 len)
+ * \brief Write data to a PhysicsFS filehandle
+ *
+ * The file must be opened for writing.
+ *
+ * Please note that while (len) is an unsigned 64-bit integer, you are limited
+ *  to 63 bits (9223372036854775807 bytes), so we can return a negative value
+ *  on error. If length is greater than 0x7FFFFFFFFFFFFFFF, this function will
+ *  immediately fail. For systems without a 64-bit datatype, you are limited
+ *  to 31 bits (0x7FFFFFFF, or 2147483647 bytes). We trust most things won't
+ *  need to do multiple gigabytes of i/o in one call anyhow, but why limit
+ *  things?
+ *
+ *   \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
+ *   \param buffer buffer of (len) bytes to write to (handle).
+ *   \param len number of bytes being written to (handle).
+ *  \return number of bytes written. This may be less than (len); in the case
+ *          of an error, the system may try to write as many bytes as possible,
+ *          so an incomplete write might occur. PHYSFS_getLastError() can shed
+ *          light on the reason this might be < (len). -1 if complete failure.
+ */
+PHYSFS_DECL PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle,
+                                            const void *buffer,
+                                            PHYSFS_uint64 len);
+
+
+#ifndef SWIG  /* not available from scripting languages. */
+
+/**
+ * \struct PHYSFS_Io
+ * \brief An abstract i/o interface.
+ *
+ * \warning This is advanced, hardcore stuff. You don't need this unless you
+ *          really know what you're doing. Most apps will not need this.
+ *
+ * Historically, PhysicsFS provided access to the physical filesystem and
+ *  archives within that filesystem. However, sometimes you need more power
+ *  than this. Perhaps you need to provide an archive that is entirely
+ *  contained in RAM, or you need to bridge some other file i/o API to
+ *  PhysicsFS, or you need to translate the bits (perhaps you have a
+ *  a standard .zip file that's encrypted, and you need to decrypt on the fly
+ *  for the unsuspecting zip archiver).
+ *
+ * A PHYSFS_Io is the interface that Archivers use to get archive data.
+ *  Historically, this has mapped to file i/o to the physical filesystem, but
+ *  as of PhysicsFS 2.1, applications can provide their own i/o implementations
+ *  at runtime.
+ *
+ * This interface isn't necessarily a good universal fit for i/o. There are a
+ *  few requirements of note:
+ *
+ *  - They only do blocking i/o (at least, for now).
+ *  - They need to be able to duplicate. If you have a file handle from
+ *    fopen(), you need to be able to create a unique clone of it (so we
+ *    have two handles to the same file that can both seek/read/etc without
+ *    stepping on each other).
+ *  - They need to know the size of their entire data set.
+ *  - They need to be able to seek and rewind on demand.
+ *
+ * ...in short, you're probably not going to write an HTTP implementation.
+ *
+ * Thread safety: TO BE DECIDED.  !!! FIXME
+ *
+ * \sa PHYSFS_mountIo
+ */
+typedef struct PHYSFS_Io
+{
+    /**
+     * \brief Binary compatibility information.
+     *
+     * This must be set to zero at this time. Future versions of this
+     *  struct will increment this field, so we know what a given
+     *  implementation supports. We'll presumably keep supporting older
+     *  versions as we offer new features, though.
+     */
+    PHYSFS_uint32 version;
+
+    /**
+     * \brief Instance data for this struct.
+     *
+     * Each instance has a pointer associated with it that can be used to
+     *  store anything it likes. This pointer is per-instance of the stream,
+     *  so presumably it will change when calling duplicate(). This can be
+     *  deallocated during the destroy() method.
+     */
+    void *opaque;
+
+    /**
+     * \brief Read more data.
+     *
+     * Read (len) bytes from the interface, at the current i/o position, and
+     *  store them in (buffer). The current i/o position should move ahead
+     *  by the number of bytes successfully read.
+     *
+     * You don't have to implement this; set it to NULL if not implemented.
+     *  This will only be used if the file is opened for reading. If set to
+     *  NULL, a default implementation that immediately reports failure will
+     *  be used.
+     *
+     *   \param io The i/o instance to read from.
+     *   \param buf The buffer to store data into. It must be at least
+     *                 (len) bytes long and can't be NULL.
+     *   \param len The number of bytes to read from the interface.
+     *  \return number of bytes read from file, 0 on EOF, -1 if complete
+     *          failure.
+     */
+    PHYSFS_sint64 (*read)(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len);
+
+    /**
+     * \brief Write more data.
+     *
+     * Write (len) bytes from (buffer) to the interface at the current i/o
+     *  position. The current i/o position should move ahead by the number of
+     *  bytes successfully written.
+     *
+     * You don't have to implement this; set it to NULL if not implemented.
+     *  This will only be used if the file is opened for writing. If set to
+     *  NULL, a default implementation that immediately reports failure will
+     *  be used.
+     *
+     * You are allowed to buffer; a write can succeed here and then later
+     *  fail when flushing. Note that PHYSFS_setBuffer() may be operating a
+     *  level above your i/o, so you should usually not implement your
+     *  own buffering routines.
+     *
+     *   \param io The i/o instance to write to.
+     *   \param buffer The buffer to read data from. It must be at least
+     *                 (len) bytes long and can't be NULL.
+     *   \param len The number of bytes to read from (buffer).
+     *  \return number of bytes written to file, -1 if complete failure.
+     */
+    PHYSFS_sint64 (*write)(struct PHYSFS_Io *io, const void *buffer,
+                           PHYSFS_uint64 len);
+
+    /**
+     * \brief Move i/o position to a given byte offset from start.
+     *
+     * This method moves the i/o position, so the next read/write will
+     *  be of the byte at (offset) offset. Seeks past the end of file should
+     *  be treated as an error condition.
+     *
+     *   \param io The i/o instance to seek.
+     *   \param offset The new byte offset for the i/o position.
+     *  \return non-zero on success, zero on error.
+     */
+    int (*seek)(struct PHYSFS_Io *io, PHYSFS_uint64 offset);
+
+    /**
+     * \brief Report current i/o position.
+     *
+     * Return bytes offset, or -1 if you aren't able to determine. A failure
+     *  will almost certainly be fatal to further use of this stream, so you
+     *  may not leave this unimplemented.
+     *
+     *   \param io The i/o instance to query.
+     *  \return The current byte offset for the i/o position, -1 if unknown.
+     */
+    PHYSFS_sint64 (*tell)(struct PHYSFS_Io *io);
+
+    /**
+     * \brief Determine size of the i/o instance's dataset.
+     *
+     * Return number of bytes available in the file, or -1 if you
+     *  aren't able to determine. A failure will almost certainly be fatal
+     *  to further use of this stream, so you may not leave this unimplemented.
+     *
+     *   \param io The i/o instance to query.
+     *  \return Total size, in bytes, of the dataset.
+     */
+    PHYSFS_sint64 (*length)(struct PHYSFS_Io *io);
+
+    /**
+     * \brief Duplicate this i/o instance.
+     *
+     *  // !!! FIXME: write me.
+     *
+     *   \param io The i/o instance to duplicate.
+     *  \return A new value for a stream's (opaque) field, or NULL on error.
+     */
+    struct PHYSFS_Io *(*duplicate)(struct PHYSFS_Io *io);
+
+    /**
+     * \brief Flush resources to media, or wherever.
+     *
+     * This is the chance to report failure for writes that had claimed
+     *  success earlier, but still had a chance to actually fail. This method
+     *  can be NULL if flushing isn't necessary.
+     *
+     * This function may be called before destroy(), as it can report failure
+     *  and destroy() can not. It may be called at other times, too.
+     *
+     *   \param io The i/o instance to flush.
+     *  \return Zero on error, non-zero on success.
+     */
+    int (*flush)(struct PHYSFS_Io *io);
+
+    /**
+     * \brief Cleanup and deallocate i/o instance.
+     *
+     * Free associated resources, including (opaque) if applicable.
+     *
+     * This function must always succeed: as such, it returns void. The
+     *  system may call your flush() method before this. You may report
+     *  failure there if necessary. This method may still be called if
+     *  flush() fails, in which case you'll have to abandon unflushed data
+     *  and other failing conditions and clean up.
+     *
+     * Once this method is called for a given instance, the system will assume
+     *  it is unsafe to touch that instance again and will discard any
+     *  references to it.
+     *
+     *   \param s The i/o instance to destroy.
+     */
+    void (*destroy)(struct PHYSFS_Io *io);
+} PHYSFS_Io;
+
+
+/**
+ * \fn int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, const char *mountPoint, int appendToPath)
+ * \brief Add an archive, built on a PHYSFS_Io, to the search path.
+ *
+ * \warning Unless you have some special, low-level need, you should be using
+ *          PHYSFS_mount() instead of this.
+ *
+ * This function operates just like PHYSFS_mount(), but takes a PHYSFS_Io
+ *  instead of a pathname. Behind the scenes, PHYSFS_mount() calls this
+ *  function with a physical-filesystem-based PHYSFS_Io.
+ *
+ * (filename) is only used here to optimize archiver selection (if you name it
+ *  XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
+ *  need to refer to a real file at all, and can even be NULL. If the filename
+ *  isn't helpful, the system will try every archiver until one works or none
+ *  of them do.
+ *
+ * (io) must remain until the archive is unmounted. When the archive is
+ *  unmounted, the system will call (io)->destroy(io), which will give you
+ *  a chance to free your resources.
+ *
+ * If this function fails, (io)->destroy(io) is not called.
+ *
+ *   \param io i/o instance for archive to add to the path.
+ *   \param fname Filename that can represent this stream. Can be NULL.
+ *   \param mountPoint Location in the interpolated tree that this archive
+ *                     will be "mounted", in platform-independent notation.
+ *                     NULL or "" is equivalent to "/".
+ *   \param appendToPath nonzero to append to search path, zero to prepend.
+ *  \return nonzero if added to path, zero on failure (bogus archive, stream
+ *                   i/o issue, etc). Specifics of the error can be
+ *                   gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_unmount
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
+                               const char *mountPoint, int appendToPath);
+
+#endif  /* SWIG */
+
+/**
+ * \fn int PHYSFS_mountMemory(const void *ptr, PHYSFS_uint64 len, void (*del)(void *), const char *fname, const char *mountPoint, int appendToPath)
+ * \brief Add an archive, contained in a memory buffer, to the search path.
+ *
+ * \warning Unless you have some special, low-level need, you should be using
+ *          PHYSFS_mount() instead of this.
+ *
+ * This function operates just like PHYSFS_mount(), but takes a memory buffer
+ *  instead of a pathname. This buffer contains all the data of the archive,
+ *  and is used instead of a real file in the physical filesystem.
+ *
+ * (filename) is only used here to optimize archiver selection (if you name it
+ *  XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
+ *  need to refer to a real file at all, and can even be NULL. If the filename
+ *  isn't helpful, the system will try every archiver until one works or none
+ *  of them do.
+ *
+ * (ptr) must remain until the archive is unmounted. When the archive is
+ *  unmounted, the system will call (del)(ptr), which will notify you that
+ *  the system is done with the buffer, and give you a chance to free your
+ *  resources. (del) can be NULL, in which case the system will make no
+ *  attempt to free the buffer.
+ *
+ * If this function fails, (del) is not called.
+ *
+ *   \param ptr Address of the memory buffer containing the archive data.
+ *   \param len Size of memory buffer, in bytes.
+ *   \param del A callback that triggers upon unmount. Can be NULL.
+ *   \param fname Filename that can represent this stream. Can be NULL.
+ *   \param mountPoint Location in the interpolated tree that this archive
+ *                     will be "mounted", in platform-independent notation.
+ *                     NULL or "" is equivalent to "/".
+ *   \param appendToPath nonzero to append to search path, zero to prepend.
+ *  \return nonzero if added to path, zero on failure (bogus archive, etc).
+ *                  Specifics of the error can be gleaned from
+ *                  PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_unmount
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
+                                   void (*del)(void *), const char *fname,
+                                   const char *mountPoint, int appendToPath);
+
+
+/**
+ * \fn int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, const char *mountPoint, int appendToPath)
+ * \brief Add an archive, contained in a PHYSFS_File handle, to the search path.
+ *
+ * \warning Unless you have some special, low-level need, you should be using
+ *          PHYSFS_mount() instead of this.
+ *
+ * \warning Archives-in-archives may be very slow! While a PHYSFS_File can
+ *          seek even when the data is compressed, it may do so by rewinding
+ *          to the start and decompressing everything before the seek point.
+ *          Normal archive usage may do a lot of seeking behind the scenes.
+ *          As such, you might find normal archive usage extremely painful
+ *          if mounted this way. Plan accordingly: if you, say, have a
+ *          self-extracting .zip file, and want to mount something in it,
+ *          compress the contents of the inner archive and make sure the outer
+ *          .zip file doesn't compress the inner archive too.
+ *
+ * This function operates just like PHYSFS_mount(), but takes a PHYSFS_File
+ *  handle instead of a pathname. This handle contains all the data of the
+ *  archive, and is used instead of a real file in the physical filesystem.
+ *  The PHYSFS_File may be backed by a real file in the physical filesystem,
+ *  but isn't necessarily. The most popular use for this is likely to mount
+ *  archives stored inside other archives.
+ *
+ * (filename) is only used here to optimize archiver selection (if you name it
+ *  XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
+ *  need to refer to a real file at all, and can even be NULL. If the filename
+ *  isn't helpful, the system will try every archiver until one works or none
+ *  of them do.
+ *
+ * (file) must remain until the archive is unmounted. When the archive is
+ *  unmounted, the system will call PHYSFS_close(file). If you need this
+ *  handle to survive, you will have to wrap this in a PHYSFS_Io and use
+ *  PHYSFS_mountIo() instead.
+ *
+ * If this function fails, PHYSFS_close(file) is not called.
+ *
+ *   \param file The PHYSFS_File handle containing archive data.
+ *   \param fname Filename that can represent this stream. Can be NULL.
+ *   \param mountPoint Location in the interpolated tree that this archive
+ *                     will be "mounted", in platform-independent notation.
+ *                     NULL or "" is equivalent to "/".
+ *   \param appendToPath nonzero to append to search path, zero to prepend.
+ *  \return nonzero if added to path, zero on failure (bogus archive, etc).
+ *                  Specifics of the error can be gleaned from
+ *                  PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_unmount
+ * \sa PHYSFS_getSearchPath
+ * \sa PHYSFS_getMountPoint
+ */
+PHYSFS_DECL int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
+                                   const char *mountPoint, int appendToPath);
+
+
+/**
+ * \enum PHYSFS_ErrorCode
+ * \brief Values that represent specific causes of failure.
+ *
+ * Most of the time, you should only concern yourself with whether a given
+ *  operation failed or not, but there may be occasions where you plan to
+ *  handle a specific failure case gracefully, so we provide specific error
+ *  codes.
+ *
+ * Most of these errors are a little vague, and most aren't things you can
+ *  fix...if there's a permission error, for example, all you can really do
+ *  is pass that information on to the user and let them figure out how to
+ *  handle it. In most these cases, your program should only care that it
+ *  failed to accomplish its goals, and not care specifically why.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ * \sa PHYSFS_getErrorByCode
+ */
+typedef enum PHYSFS_ErrorCode
+{
+    PHYSFS_ERR_OK,               /**< Success; no error.                    */
+    PHYSFS_ERR_OTHER_ERROR,      /**< Error not otherwise covered here.     */
+    PHYSFS_ERR_OUT_OF_MEMORY,    /**< Memory allocation failed.             */
+    PHYSFS_ERR_NOT_INITIALIZED,  /**< PhysicsFS is not initialized.         */
+    PHYSFS_ERR_IS_INITIALIZED,   /**< PhysicsFS is already initialized.     */
+    PHYSFS_ERR_ARGV0_IS_NULL,    /**< Needed argv[0], but it is NULL.       */
+    PHYSFS_ERR_UNSUPPORTED,      /**< Operation or feature unsupported.     */
+    PHYSFS_ERR_PAST_EOF,         /**< Attempted to access past end of file. */
+    PHYSFS_ERR_FILES_STILL_OPEN, /**< Files still open.                     */
+    PHYSFS_ERR_INVALID_ARGUMENT, /**< Bad parameter passed to an function.  */
+    PHYSFS_ERR_NOT_MOUNTED,      /**< Requested archive/dir not mounted.    */
+    PHYSFS_ERR_NO_SUCH_PATH,     /**< No such file, directory, or parent.   */
+    PHYSFS_ERR_SYMLINK_FORBIDDEN,/**< Symlink seen when not permitted.      */
+    PHYSFS_ERR_NO_WRITE_DIR,     /**< No write dir has been specified.      */
+    PHYSFS_ERR_OPEN_FOR_READING, /**< Wrote to a file opened for reading.   */
+    PHYSFS_ERR_OPEN_FOR_WRITING, /**< Read from a file opened for writing.  */
+    PHYSFS_ERR_NOT_A_FILE,       /**< Needed a file, got a directory (etc). */
+    PHYSFS_ERR_READ_ONLY,        /**< Wrote to a read-only filesystem.      */
+    PHYSFS_ERR_CORRUPT,          /**< Corrupted data encountered.           */
+    PHYSFS_ERR_SYMLINK_LOOP,     /**< Infinite symbolic link loop.          */
+    PHYSFS_ERR_IO,               /**< i/o error (hardware failure, etc).    */
+    PHYSFS_ERR_PERMISSION,       /**< Permission denied.                    */
+    PHYSFS_ERR_NO_SPACE,         /**< No space (disk full, over quota, etc) */
+    PHYSFS_ERR_BAD_FILENAME,     /**< Filename is bogus/insecure.           */
+    PHYSFS_ERR_BUSY,             /**< Tried to modify a file the OS needs.  */
+    PHYSFS_ERR_DIR_NOT_EMPTY,    /**< Tried to delete dir with files in it. */
+    PHYSFS_ERR_OS_ERROR          /**< Unspecified OS-level error.           */
+} PHYSFS_ErrorCode;
+
+
+/**
+ * \fn PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void)
+ * \brief Get machine-readable error information.
+ *
+ * Get the last PhysicsFS error message as an integer value. This will return
+ *  PHYSFS_ERR_OK if there's been no error since the last call to this
+ *  function. Each thread has a unique error state associated with it, but
+ *  each time a new error message is set, it will overwrite the previous one
+ *  associated with that thread. It is safe to call this function at anytime,
+ *  even before PHYSFS_init().
+ *
+ * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same
+ *  thread-specific error state. Calling one will wipe out the other's
+ *  data. If you need both, call PHYSFS_getLastErrorCode(), then pass that
+ *  value to PHYSFS_getErrorByCode().
+ *
+ * Generally, applications should only concern themselves with whether a
+ *  given function failed; however, if you require more specifics, you can
+ *  try this function to glean information, if there's some specific problem
+ *  you're expecting and plan to handle. But with most things that involve
+ *  file systems, the best course of action is usually to give up, report the
+ *  problem to the user, and let them figure out what should be done about it.
+ *  For that, you might prefer PHYSFS_getLastError() instead.
+ *
+ *   \return Enumeration value that represents last reported error.
+ *
+ * \sa PHYSFS_getErrorByCode
+ */
+PHYSFS_DECL PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void);
+
+
+/**
+ * \fn const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code)
+ * \brief Get human-readable description string for a given error code.
+ *
+ * Get a static string, in UTF-8 format, that represents an English
+ *  description of a given error code.
+ *
+ * This string is guaranteed to never change (although we may add new strings
+ *  for new error codes in later versions of PhysicsFS), so you can use it
+ *  for keying a localization dictionary.
+ *
+ * It is safe to call this function at anytime, even before PHYSFS_init().
+ *
+ * These strings are meant to be passed on directly to the user.
+ *  Generally, applications should only concern themselves with whether a
+ *  given function failed, but not care about the specifics much.
+ *
+ * Do not attempt to free the returned strings; they are read-only and you
+ *  don't own their memory pages.
+ *
+ *   \param code Error code to convert to a string.
+ *   \return READ ONLY string of requested error message, NULL if this
+ *           is not a valid PhysicsFS error code. Always check for NULL if
+ *           you might be looking up an error code that didn't exist in an
+ *           earlier version of PhysicsFS.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ */
+PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code);
+
+/**
+ * \fn void PHYSFS_setErrorCode(PHYSFS_ErrorCode code)
+ * \brief Set the current thread's error code.
+ *
+ * This lets you set the value that will be returned by the next call to
+ *  PHYSFS_getLastErrorCode(). This will replace any existing error code,
+ *  whether set by your application or internally by PhysicsFS.
+ *
+ * Error codes are stored per-thread; what you set here will not be
+ *  accessible to another thread.
+ *
+ * Any call into PhysicsFS may change the current error code, so any code you
+ *  set here is somewhat fragile, and thus you shouldn't build any serious
+ *  error reporting framework on this function. The primary goal of this
+ *  function is to allow PHYSFS_Io implementations to set the error state,
+ *  which generally will be passed back to your application when PhysicsFS
+ *  makes a PHYSFS_Io call that fails internally.
+ *
+ * This function doesn't care if the error code is a value known to PhysicsFS
+ *  or not (but PHYSFS_getErrorByCode() will return NULL for unknown values).
+ *  The value will be reported unmolested by PHYSFS_getLastErrorCode().
+ *
+ *   \param code Error code to become the current thread's new error state.
+ *
+ * \sa PHYSFS_getLastErrorCode
+ * \sa PHYSFS_getErrorByCode
+ */
+PHYSFS_DECL void PHYSFS_setErrorCode(PHYSFS_ErrorCode code);
+
+
+/**
+ * \fn const char *PHYSFS_getPrefDir(const char *org, const char *app)
+ * \brief Get the user-and-app-specific path where files can be written.
+ *
+ * Helper function.
+ *
+ * Get the "pref dir". This is meant to be where users can write personal
+ *  files (preferences and save games, etc) that are specific to your
+ *  application. This directory is unique per user, per application.
+ *
+ * This function will decide the appropriate location in the native filesystem,
+ *  create the directory if necessary, and return a string in
+ *  platform-dependent notation, suitable for passing to PHYSFS_setWriteDir().
+ *
+ * On Windows, this might look like:
+ *  "C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name"
+ *
+ * On Linux, this might look like:
+ *  "/home/bob/.local/share/My Program Name"
+ *
+ * On Mac OS X, this might look like:
+ *  "/Users/bob/Library/Application Support/My Program Name"
+ *
+ * (etc.)
+ *
+ * You should probably use the pref dir for your write dir, and also put it
+ *  near the beginning of your search path. Older versions of PhysicsFS
+ *  offered only PHYSFS_getUserDir() and left you to figure out where the
+ *  files should go under that tree. This finds the correct location
+ *  for whatever platform, which not only changes between operating systems,
+ *  but also versions of the same operating system.
+ *
+ * You specify the name of your organization (if it's not a real organization,
+ *  your name or an Internet domain you own might do) and the name of your
+ *  application. These should be proper names.
+ *
+ * Both the (org) and (app) strings may become part of a directory name, so
+ *  please follow these rules:
+ *
+ *    - Try to use the same org string (including case-sensitivity) for
+ *      all your applications that use this function.
+ *    - Always use a unique app string for each one, and make sure it never
+ *      changes for an app once you've decided on it.
+ *    - Unicode characters are legal, as long as it's UTF-8 encoded, but...
+ *    - ...only use letters, numbers, and spaces. Avoid punctuation like
+ *      "Game Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
+ *
+ * The pointer returned by this function remains valid until you call this
+ *  function again, or call PHYSFS_deinit(). This is not necessarily a fast
+ *  call, though, so you should call this once at startup and copy the string
+ *  if you need it.
+ *
+ * You should assume the path returned by this function is the only safe
+ *  place to write files (and that PHYSFS_getUserDir() and PHYSFS_getBaseDir(),
+ *  while they might be writable, or even parents of the returned path, aren't
+ *  where you should be writing things).
+ *
+ *   \param org The name of your organization.
+ *   \param app The name of your application.
+ *  \return READ ONLY string of user dir in platform-dependent notation. NULL
+ *          if there's a problem (creating directory failed, etc).
+ *
+ * \sa PHYSFS_getBaseDir
+ * \sa PHYSFS_getUserDir
+ */
+PHYSFS_DECL const char *PHYSFS_getPrefDir(const char *org, const char *app);
+
+
+/* Everything above this line is part of the PhysicsFS 2.1 API. */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* !defined _INCLUDE_PHYSFS_H_ */
+
+/* end of physfs.h ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs_byteorder.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,137 @@
+/**
+ * PhysicsFS; a portable, flexible file i/o abstraction.
+ *
+ * Documentation is in physfs.h. It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+#ifndef PHYSFS_Swap16
+static inline PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D)
+{
+    return ((D<<8)|(D>>8));
+}
+#endif
+#ifndef PHYSFS_Swap32
+static inline PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D)
+{
+    return ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
+}
+#endif
+#ifndef PHYSFS_NO_64BIT_SUPPORT
+#ifndef PHYSFS_Swap64
+static inline PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) {
+    PHYSFS_uint32 hi, lo;
+
+    /* Separate into high and low 32-bit values and swap them */
+    lo = (PHYSFS_uint32)(val&0xFFFFFFFF);
+    val >>= 32;
+    hi = (PHYSFS_uint32)(val&0xFFFFFFFF);
+    val = PHYSFS_Swap32(lo);
+    val <<= 32;
+    val |= PHYSFS_Swap32(hi);
+    return val;
+}
+#endif
+#else
+#ifndef PHYSFS_Swap64
+/* This is mainly to keep compilers from complaining in PHYSFS code.
+   If there is no real 64-bit datatype, then compilers will complain about
+   the fake 64-bit datatype that PHYSFS provides when it compiles user code.
+*/
+#define PHYSFS_Swap64(X)    (X)
+#endif
+#endif /* PHYSFS_NO_64BIT_SUPPORT */
+
+
+/* Byteswap item from the specified endianness to the native endianness */
+#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN
+PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return x; }
+PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return x; }
+PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return x; }
+PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return x; }
+PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return x; }
+PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return x; }
+
+PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
+PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
+#else
+PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); }
+PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); }
+PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); }
+PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); }
+
+PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return x; }
+PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return x; }
+PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return x; }
+PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return x; }
+PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return x; }
+PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return x; }
+#endif
+
+static inline int readAll(PHYSFS_File *file, void *val, const size_t len)
+{
+    return (PHYSFS_readBytes(file, val, len) == len);
+} /* readAll */
+
+#define PHYSFS_BYTEORDER_READ(datatype, swaptype) \
+    int PHYSFS_read##swaptype(PHYSFS_File *file, PHYSFS_##datatype *val) { \
+        PHYSFS_##datatype in; \
+        BAIL_IF_MACRO(val == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); \
+        BAIL_IF_MACRO(!readAll(file, &in, sizeof (in)), ERRPASS, 0); \
+        *val = PHYSFS_swap##swaptype(in); \
+        return 1; \
+    }
+
+PHYSFS_BYTEORDER_READ(sint16, SLE16)
+PHYSFS_BYTEORDER_READ(uint16, ULE16)
+PHYSFS_BYTEORDER_READ(sint16, SBE16)
+PHYSFS_BYTEORDER_READ(uint16, UBE16)
+PHYSFS_BYTEORDER_READ(sint32, SLE32)
+PHYSFS_BYTEORDER_READ(uint32, ULE32)
+PHYSFS_BYTEORDER_READ(sint32, SBE32)
+PHYSFS_BYTEORDER_READ(uint32, UBE32)
+PHYSFS_BYTEORDER_READ(sint64, SLE64)
+PHYSFS_BYTEORDER_READ(uint64, ULE64)
+PHYSFS_BYTEORDER_READ(sint64, SBE64)
+PHYSFS_BYTEORDER_READ(uint64, UBE64)
+
+
+static inline int writeAll(PHYSFS_File *f, const void *val, const size_t len)
+{
+    return (PHYSFS_writeBytes(f, val, len) == len);
+} /* writeAll */
+
+#define PHYSFS_BYTEORDER_WRITE(datatype, swaptype) \
+    int PHYSFS_write##swaptype(PHYSFS_File *file, PHYSFS_##datatype val) { \
+        const PHYSFS_##datatype out = PHYSFS_swap##swaptype(val); \
+        BAIL_IF_MACRO(!writeAll(file, &out, sizeof (out)), ERRPASS, 0); \
+        return 1; \
+    }
+
+PHYSFS_BYTEORDER_WRITE(sint16, SLE16)
+PHYSFS_BYTEORDER_WRITE(uint16, ULE16)
+PHYSFS_BYTEORDER_WRITE(sint16, SBE16)
+PHYSFS_BYTEORDER_WRITE(uint16, UBE16)
+PHYSFS_BYTEORDER_WRITE(sint32, SLE32)
+PHYSFS_BYTEORDER_WRITE(uint32, ULE32)
+PHYSFS_BYTEORDER_WRITE(sint32, SBE32)
+PHYSFS_BYTEORDER_WRITE(uint32, UBE32)
+PHYSFS_BYTEORDER_WRITE(sint64, SLE64)
+PHYSFS_BYTEORDER_WRITE(uint64, ULE64)
+PHYSFS_BYTEORDER_WRITE(sint64, SBE64)
+PHYSFS_BYTEORDER_WRITE(uint64, UBE64)
+
+/* end of physfs_byteorder.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs_casefolding.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2013 @@
+/*
+ * This file is part of PhysicsFS (http://icculus.org/physfs/)
+ *
+ * This data generated by physfs/extras/makecasefoldhashtable.pl ...
+ * Do not manually edit this file!
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ */
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+static const CaseFoldMapping case_fold_000[] = {
+    { 0x0202, 0x0203, 0x0000, 0x0000 },
+    { 0x0404, 0x0454, 0x0000, 0x0000 },
+    { 0x1E1E, 0x1E1F, 0x0000, 0x0000 },
+    { 0x2C2C, 0x2C5C, 0x0000, 0x0000 },
+    { 0x10404, 0x1042C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_001[] = {
+    { 0x0100, 0x0101, 0x0000, 0x0000 },
+    { 0x0405, 0x0455, 0x0000, 0x0000 },
+    { 0x0504, 0x0505, 0x0000, 0x0000 },
+    { 0x2C2D, 0x2C5D, 0x0000, 0x0000 },
+    { 0x10405, 0x1042D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_002[] = {
+    { 0x0200, 0x0201, 0x0000, 0x0000 },
+    { 0x0406, 0x0456, 0x0000, 0x0000 },
+    { 0x1E1C, 0x1E1D, 0x0000, 0x0000 },
+    { 0x1F1D, 0x1F15, 0x0000, 0x0000 },
+    { 0x2C2E, 0x2C5E, 0x0000, 0x0000 },
+    { 0x10406, 0x1042E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_003[] = {
+    { 0x0102, 0x0103, 0x0000, 0x0000 },
+    { 0x0407, 0x0457, 0x0000, 0x0000 },
+    { 0x0506, 0x0507, 0x0000, 0x0000 },
+    { 0x1F1C, 0x1F14, 0x0000, 0x0000 },
+    { 0x10407, 0x1042F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_004[] = {
+    { 0x0206, 0x0207, 0x0000, 0x0000 },
+    { 0x0400, 0x0450, 0x0000, 0x0000 },
+    { 0x1E1A, 0x1E1B, 0x0000, 0x0000 },
+    { 0x1F1B, 0x1F13, 0x0000, 0x0000 },
+    { 0x2C28, 0x2C58, 0x0000, 0x0000 },
+    { 0x10400, 0x10428, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_005[] = {
+    { 0x0104, 0x0105, 0x0000, 0x0000 },
+    { 0x0401, 0x0451, 0x0000, 0x0000 },
+    { 0x0500, 0x0501, 0x0000, 0x0000 },
+    { 0x1F1A, 0x1F12, 0x0000, 0x0000 },
+    { 0x2C29, 0x2C59, 0x0000, 0x0000 },
+    { 0x10401, 0x10429, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_006[] = {
+    { 0x0204, 0x0205, 0x0000, 0x0000 },
+    { 0x0402, 0x0452, 0x0000, 0x0000 },
+    { 0x1E18, 0x1E19, 0x0000, 0x0000 },
+    { 0x1F19, 0x1F11, 0x0000, 0x0000 },
+    { 0x2C2A, 0x2C5A, 0x0000, 0x0000 },
+    { 0x10402, 0x1042A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_007[] = {
+    { 0x0106, 0x0107, 0x0000, 0x0000 },
+    { 0x0403, 0x0453, 0x0000, 0x0000 },
+    { 0x0502, 0x0503, 0x0000, 0x0000 },
+    { 0x1F18, 0x1F10, 0x0000, 0x0000 },
+    { 0x2126, 0x03C9, 0x0000, 0x0000 },
+    { 0x2C2B, 0x2C5B, 0x0000, 0x0000 },
+    { 0x10403, 0x1042B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_008[] = {
+    { 0x020A, 0x020B, 0x0000, 0x0000 },
+    { 0x040C, 0x045C, 0x0000, 0x0000 },
+    { 0x1E16, 0x1E17, 0x0000, 0x0000 },
+    { 0x2C24, 0x2C54, 0x0000, 0x0000 },
+    { 0x1040C, 0x10434, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_009[] = {
+    { 0x0108, 0x0109, 0x0000, 0x0000 },
+    { 0x040D, 0x045D, 0x0000, 0x0000 },
+    { 0x050C, 0x050D, 0x0000, 0x0000 },
+    { 0x2C25, 0x2C55, 0x0000, 0x0000 },
+    { 0x1040D, 0x10435, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_010[] = {
+    { 0x0208, 0x0209, 0x0000, 0x0000 },
+    { 0x040E, 0x045E, 0x0000, 0x0000 },
+    { 0x1E14, 0x1E15, 0x0000, 0x0000 },
+    { 0x212B, 0x00E5, 0x0000, 0x0000 },
+    { 0x2C26, 0x2C56, 0x0000, 0x0000 },
+    { 0x1040E, 0x10436, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_011[] = {
+    { 0x010A, 0x010B, 0x0000, 0x0000 },
+    { 0x040F, 0x045F, 0x0000, 0x0000 },
+    { 0x050E, 0x050F, 0x0000, 0x0000 },
+    { 0x212A, 0x006B, 0x0000, 0x0000 },
+    { 0x2C27, 0x2C57, 0x0000, 0x0000 },
+    { 0x1040F, 0x10437, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_012[] = {
+    { 0x020E, 0x020F, 0x0000, 0x0000 },
+    { 0x0408, 0x0458, 0x0000, 0x0000 },
+    { 0x1E12, 0x1E13, 0x0000, 0x0000 },
+    { 0x2C20, 0x2C50, 0x0000, 0x0000 },
+    { 0x10408, 0x10430, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_013[] = {
+    { 0x010C, 0x010D, 0x0000, 0x0000 },
+    { 0x0409, 0x0459, 0x0000, 0x0000 },
+    { 0x0508, 0x0509, 0x0000, 0x0000 },
+    { 0x2C21, 0x2C51, 0x0000, 0x0000 },
+    { 0x10409, 0x10431, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_014[] = {
+    { 0x020C, 0x020D, 0x0000, 0x0000 },
+    { 0x040A, 0x045A, 0x0000, 0x0000 },
+    { 0x1E10, 0x1E11, 0x0000, 0x0000 },
+    { 0x2C22, 0x2C52, 0x0000, 0x0000 },
+    { 0x1040A, 0x10432, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_015[] = {
+    { 0x010E, 0x010F, 0x0000, 0x0000 },
+    { 0x040B, 0x045B, 0x0000, 0x0000 },
+    { 0x050A, 0x050B, 0x0000, 0x0000 },
+    { 0x2C23, 0x2C53, 0x0000, 0x0000 },
+    { 0x1040B, 0x10433, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_016[] = {
+    { 0x0212, 0x0213, 0x0000, 0x0000 },
+    { 0x0414, 0x0434, 0x0000, 0x0000 },
+    { 0x1E0E, 0x1E0F, 0x0000, 0x0000 },
+    { 0x1F0F, 0x1F07, 0x0000, 0x0000 },
+    { 0x10414, 0x1043C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_017[] = {
+    { 0x0110, 0x0111, 0x0000, 0x0000 },
+    { 0x0415, 0x0435, 0x0000, 0x0000 },
+    { 0x1F0E, 0x1F06, 0x0000, 0x0000 },
+    { 0x10415, 0x1043D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_018[] = {
+    { 0x0210, 0x0211, 0x0000, 0x0000 },
+    { 0x0416, 0x0436, 0x0000, 0x0000 },
+    { 0x1E0C, 0x1E0D, 0x0000, 0x0000 },
+    { 0x1F0D, 0x1F05, 0x0000, 0x0000 },
+    { 0x10416, 0x1043E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_019[] = {
+    { 0x0112, 0x0113, 0x0000, 0x0000 },
+    { 0x0417, 0x0437, 0x0000, 0x0000 },
+    { 0x1F0C, 0x1F04, 0x0000, 0x0000 },
+    { 0x10417, 0x1043F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_020[] = {
+    { 0x0216, 0x0217, 0x0000, 0x0000 },
+    { 0x0410, 0x0430, 0x0000, 0x0000 },
+    { 0x1E0A, 0x1E0B, 0x0000, 0x0000 },
+    { 0x1F0B, 0x1F03, 0x0000, 0x0000 },
+    { 0x10410, 0x10438, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_021[] = {
+    { 0x0114, 0x0115, 0x0000, 0x0000 },
+    { 0x0411, 0x0431, 0x0000, 0x0000 },
+    { 0x1F0A, 0x1F02, 0x0000, 0x0000 },
+    { 0x10411, 0x10439, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_022[] = {
+    { 0x0214, 0x0215, 0x0000, 0x0000 },
+    { 0x0412, 0x0432, 0x0000, 0x0000 },
+    { 0x1E08, 0x1E09, 0x0000, 0x0000 },
+    { 0x1F09, 0x1F01, 0x0000, 0x0000 },
+    { 0x10412, 0x1043A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_023[] = {
+    { 0x0116, 0x0117, 0x0000, 0x0000 },
+    { 0x0413, 0x0433, 0x0000, 0x0000 },
+    { 0x1F08, 0x1F00, 0x0000, 0x0000 },
+    { 0x10413, 0x1043B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_024[] = {
+    { 0x021A, 0x021B, 0x0000, 0x0000 },
+    { 0x041C, 0x043C, 0x0000, 0x0000 },
+    { 0x1E06, 0x1E07, 0x0000, 0x0000 },
+    { 0x1041C, 0x10444, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_025[] = {
+    { 0x0118, 0x0119, 0x0000, 0x0000 },
+    { 0x041D, 0x043D, 0x0000, 0x0000 },
+    { 0x1041D, 0x10445, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_026[] = {
+    { 0x0218, 0x0219, 0x0000, 0x0000 },
+    { 0x041E, 0x043E, 0x0000, 0x0000 },
+    { 0x1E04, 0x1E05, 0x0000, 0x0000 },
+    { 0x1041E, 0x10446, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_027[] = {
+    { 0x011A, 0x011B, 0x0000, 0x0000 },
+    { 0x041F, 0x043F, 0x0000, 0x0000 },
+    { 0x1041F, 0x10447, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_028[] = {
+    { 0x021E, 0x021F, 0x0000, 0x0000 },
+    { 0x0418, 0x0438, 0x0000, 0x0000 },
+    { 0x1E02, 0x1E03, 0x0000, 0x0000 },
+    { 0x10418, 0x10440, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_029[] = {
+    { 0x011C, 0x011D, 0x0000, 0x0000 },
+    { 0x0419, 0x0439, 0x0000, 0x0000 },
+    { 0x10419, 0x10441, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_030[] = {
+    { 0x021C, 0x021D, 0x0000, 0x0000 },
+    { 0x041A, 0x043A, 0x0000, 0x0000 },
+    { 0x1E00, 0x1E01, 0x0000, 0x0000 },
+    { 0x1041A, 0x10442, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_031[] = {
+    { 0x011E, 0x011F, 0x0000, 0x0000 },
+    { 0x041B, 0x043B, 0x0000, 0x0000 },
+    { 0x1041B, 0x10443, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_032[] = {
+    { 0x0222, 0x0223, 0x0000, 0x0000 },
+    { 0x0424, 0x0444, 0x0000, 0x0000 },
+    { 0x1E3E, 0x1E3F, 0x0000, 0x0000 },
+    { 0x1F3F, 0x1F37, 0x0000, 0x0000 },
+    { 0x2C0C, 0x2C3C, 0x0000, 0x0000 },
+    { 0x10424, 0x1044C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_033[] = {
+    { 0x0120, 0x0121, 0x0000, 0x0000 },
+    { 0x0425, 0x0445, 0x0000, 0x0000 },
+    { 0x1F3E, 0x1F36, 0x0000, 0x0000 },
+    { 0x2C0D, 0x2C3D, 0x0000, 0x0000 },
+    { 0x10425, 0x1044D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_034[] = {
+    { 0x0220, 0x019E, 0x0000, 0x0000 },
+    { 0x0426, 0x0446, 0x0000, 0x0000 },
+    { 0x1E3C, 0x1E3D, 0x0000, 0x0000 },
+    { 0x1F3D, 0x1F35, 0x0000, 0x0000 },
+    { 0x2C0E, 0x2C3E, 0x0000, 0x0000 },
+    { 0x10426, 0x1044E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_035[] = {
+    { 0x0122, 0x0123, 0x0000, 0x0000 },
+    { 0x0427, 0x0447, 0x0000, 0x0000 },
+    { 0x1F3C, 0x1F34, 0x0000, 0x0000 },
+    { 0x2C0F, 0x2C3F, 0x0000, 0x0000 },
+    { 0x10427, 0x1044F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_036[] = {
+    { 0x0226, 0x0227, 0x0000, 0x0000 },
+    { 0x0420, 0x0440, 0x0000, 0x0000 },
+    { 0x1E3A, 0x1E3B, 0x0000, 0x0000 },
+    { 0x1F3B, 0x1F33, 0x0000, 0x0000 },
+    { 0x2C08, 0x2C38, 0x0000, 0x0000 },
+    { 0x10420, 0x10448, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_037[] = {
+    { 0x0124, 0x0125, 0x0000, 0x0000 },
+    { 0x0421, 0x0441, 0x0000, 0x0000 },
+    { 0x1F3A, 0x1F32, 0x0000, 0x0000 },
+    { 0x2C09, 0x2C39, 0x0000, 0x0000 },
+    { 0x10421, 0x10449, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_038[] = {
+    { 0x0224, 0x0225, 0x0000, 0x0000 },
+    { 0x0422, 0x0442, 0x0000, 0x0000 },
+    { 0x1E38, 0x1E39, 0x0000, 0x0000 },
+    { 0x1F39, 0x1F31, 0x0000, 0x0000 },
+    { 0x2C0A, 0x2C3A, 0x0000, 0x0000 },
+    { 0x10422, 0x1044A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_039[] = {
+    { 0x0126, 0x0127, 0x0000, 0x0000 },
+    { 0x0423, 0x0443, 0x0000, 0x0000 },
+    { 0x1F38, 0x1F30, 0x0000, 0x0000 },
+    { 0x2C0B, 0x2C3B, 0x0000, 0x0000 },
+    { 0x10423, 0x1044B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_040[] = {
+    { 0x022A, 0x022B, 0x0000, 0x0000 },
+    { 0x042C, 0x044C, 0x0000, 0x0000 },
+    { 0x1E36, 0x1E37, 0x0000, 0x0000 },
+    { 0x2C04, 0x2C34, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_041[] = {
+    { 0x0128, 0x0129, 0x0000, 0x0000 },
+    { 0x042D, 0x044D, 0x0000, 0x0000 },
+    { 0x2C05, 0x2C35, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_042[] = {
+    { 0x0228, 0x0229, 0x0000, 0x0000 },
+    { 0x042E, 0x044E, 0x0000, 0x0000 },
+    { 0x1E34, 0x1E35, 0x0000, 0x0000 },
+    { 0x2C06, 0x2C36, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_043[] = {
+    { 0x012A, 0x012B, 0x0000, 0x0000 },
+    { 0x042F, 0x044F, 0x0000, 0x0000 },
+    { 0x2C07, 0x2C37, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_044[] = {
+    { 0x022E, 0x022F, 0x0000, 0x0000 },
+    { 0x0428, 0x0448, 0x0000, 0x0000 },
+    { 0x1E32, 0x1E33, 0x0000, 0x0000 },
+    { 0x2C00, 0x2C30, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_045[] = {
+    { 0x012C, 0x012D, 0x0000, 0x0000 },
+    { 0x0429, 0x0449, 0x0000, 0x0000 },
+    { 0x2C01, 0x2C31, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_046[] = {
+    { 0x022C, 0x022D, 0x0000, 0x0000 },
+    { 0x042A, 0x044A, 0x0000, 0x0000 },
+    { 0x1E30, 0x1E31, 0x0000, 0x0000 },
+    { 0x2C02, 0x2C32, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_047[] = {
+    { 0x012E, 0x012F, 0x0000, 0x0000 },
+    { 0x042B, 0x044B, 0x0000, 0x0000 },
+    { 0x2C03, 0x2C33, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_048[] = {
+    { 0x0232, 0x0233, 0x0000, 0x0000 },
+    { 0x0535, 0x0565, 0x0000, 0x0000 },
+    { 0x1E2E, 0x1E2F, 0x0000, 0x0000 },
+    { 0x1F2F, 0x1F27, 0x0000, 0x0000 },
+    { 0x2C1C, 0x2C4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_049[] = {
+    { 0x0130, 0x0069, 0x0307, 0x0000 },
+    { 0x0534, 0x0564, 0x0000, 0x0000 },
+    { 0x1F2E, 0x1F26, 0x0000, 0x0000 },
+    { 0x2C1D, 0x2C4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_050[] = {
+    { 0x0230, 0x0231, 0x0000, 0x0000 },
+    { 0x0537, 0x0567, 0x0000, 0x0000 },
+    { 0x1E2C, 0x1E2D, 0x0000, 0x0000 },
+    { 0x1F2D, 0x1F25, 0x0000, 0x0000 },
+    { 0x2C1E, 0x2C4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_051[] = {
+    { 0x0132, 0x0133, 0x0000, 0x0000 },
+    { 0x0536, 0x0566, 0x0000, 0x0000 },
+    { 0x1F2C, 0x1F24, 0x0000, 0x0000 },
+    { 0x2C1F, 0x2C4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_052[] = {
+    { 0x0531, 0x0561, 0x0000, 0x0000 },
+    { 0x1E2A, 0x1E2B, 0x0000, 0x0000 },
+    { 0x1F2B, 0x1F23, 0x0000, 0x0000 },
+    { 0x2C18, 0x2C48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_053[] = {
+    { 0x0134, 0x0135, 0x0000, 0x0000 },
+    { 0x1F2A, 0x1F22, 0x0000, 0x0000 },
+    { 0x2C19, 0x2C49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_054[] = {
+    { 0x0533, 0x0563, 0x0000, 0x0000 },
+    { 0x1E28, 0x1E29, 0x0000, 0x0000 },
+    { 0x1F29, 0x1F21, 0x0000, 0x0000 },
+    { 0x2C1A, 0x2C4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_055[] = {
+    { 0x0136, 0x0137, 0x0000, 0x0000 },
+    { 0x0532, 0x0562, 0x0000, 0x0000 },
+    { 0x1F28, 0x1F20, 0x0000, 0x0000 },
+    { 0x2C1B, 0x2C4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_056[] = {
+    { 0x0139, 0x013A, 0x0000, 0x0000 },
+    { 0x053D, 0x056D, 0x0000, 0x0000 },
+    { 0x1E26, 0x1E27, 0x0000, 0x0000 },
+    { 0x2C14, 0x2C44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_057[] = {
+    { 0x023B, 0x023C, 0x0000, 0x0000 },
+    { 0x053C, 0x056C, 0x0000, 0x0000 },
+    { 0x2C15, 0x2C45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_058[] = {
+    { 0x013B, 0x013C, 0x0000, 0x0000 },
+    { 0x053F, 0x056F, 0x0000, 0x0000 },
+    { 0x1E24, 0x1E25, 0x0000, 0x0000 },
+    { 0x2C16, 0x2C46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_059[] = {
+    { 0x053E, 0x056E, 0x0000, 0x0000 },
+    { 0x2C17, 0x2C47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_060[] = {
+    { 0x013D, 0x013E, 0x0000, 0x0000 },
+    { 0x0539, 0x0569, 0x0000, 0x0000 },
+    { 0x1E22, 0x1E23, 0x0000, 0x0000 },
+    { 0x2C10, 0x2C40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_061[] = {
+    { 0x0538, 0x0568, 0x0000, 0x0000 },
+    { 0x2C11, 0x2C41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_062[] = {
+    { 0x013F, 0x0140, 0x0000, 0x0000 },
+    { 0x053B, 0x056B, 0x0000, 0x0000 },
+    { 0x1E20, 0x1E21, 0x0000, 0x0000 },
+    { 0x2C12, 0x2C42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_063[] = {
+    { 0x023D, 0x019A, 0x0000, 0x0000 },
+    { 0x053A, 0x056A, 0x0000, 0x0000 },
+    { 0x2C13, 0x2C43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_064[] = {
+    { 0x0141, 0x0142, 0x0000, 0x0000 },
+    { 0x0545, 0x0575, 0x0000, 0x0000 },
+    { 0x1E5E, 0x1E5F, 0x0000, 0x0000 },
+    { 0x1F5F, 0x1F57, 0x0000, 0x0000 },
+    { 0x2161, 0x2171, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_065[] = {
+    { 0x0041, 0x0061, 0x0000, 0x0000 },
+    { 0x0544, 0x0574, 0x0000, 0x0000 },
+    { 0x2160, 0x2170, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_066[] = {
+    { 0x0042, 0x0062, 0x0000, 0x0000 },
+    { 0x0143, 0x0144, 0x0000, 0x0000 },
+    { 0x0547, 0x0577, 0x0000, 0x0000 },
+    { 0x1E5C, 0x1E5D, 0x0000, 0x0000 },
+    { 0x1F5D, 0x1F55, 0x0000, 0x0000 },
+    { 0x2163, 0x2173, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_067[] = {
+    { 0x0043, 0x0063, 0x0000, 0x0000 },
+    { 0x0241, 0x0294, 0x0000, 0x0000 },
+    { 0x0546, 0x0576, 0x0000, 0x0000 },
+    { 0x2162, 0x2172, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_068[] = {
+    { 0x0044, 0x0064, 0x0000, 0x0000 },
+    { 0x0145, 0x0146, 0x0000, 0x0000 },
+    { 0x0541, 0x0571, 0x0000, 0x0000 },
+    { 0x1E5A, 0x1E5B, 0x0000, 0x0000 },
+    { 0x1F5B, 0x1F53, 0x0000, 0x0000 },
+    { 0x2165, 0x2175, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_069[] = {
+    { 0x0045, 0x0065, 0x0000, 0x0000 },
+    { 0x0540, 0x0570, 0x0000, 0x0000 },
+    { 0x2164, 0x2174, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_070[] = {
+    { 0x0046, 0x0066, 0x0000, 0x0000 },
+    { 0x0147, 0x0148, 0x0000, 0x0000 },
+    { 0x0345, 0x03B9, 0x0000, 0x0000 },
+    { 0x0543, 0x0573, 0x0000, 0x0000 },
+    { 0x1E58, 0x1E59, 0x0000, 0x0000 },
+    { 0x1F59, 0x1F51, 0x0000, 0x0000 },
+    { 0x2167, 0x2177, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_071[] = {
+    { 0x0047, 0x0067, 0x0000, 0x0000 },
+    { 0x0542, 0x0572, 0x0000, 0x0000 },
+    { 0x2166, 0x2176, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_072[] = {
+    { 0x0048, 0x0068, 0x0000, 0x0000 },
+    { 0x0149, 0x02BC, 0x006E, 0x0000 },
+    { 0x054D, 0x057D, 0x0000, 0x0000 },
+    { 0x1E56, 0x1E57, 0x0000, 0x0000 },
+    { 0x2169, 0x2179, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_073[] = {
+    { 0x0049, 0x0069, 0x0000, 0x0000 },
+    { 0x054C, 0x057C, 0x0000, 0x0000 },
+    { 0x1F56, 0x03C5, 0x0313, 0x0342 },
+    { 0x2168, 0x2178, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_074[] = {
+    { 0x004A, 0x006A, 0x0000, 0x0000 },
+    { 0x054F, 0x057F, 0x0000, 0x0000 },
+    { 0x1E54, 0x1E55, 0x0000, 0x0000 },
+    { 0x216B, 0x217B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_075[] = {
+    { 0x004B, 0x006B, 0x0000, 0x0000 },
+    { 0x014A, 0x014B, 0x0000, 0x0000 },
+    { 0x054E, 0x057E, 0x0000, 0x0000 },
+    { 0x1F54, 0x03C5, 0x0313, 0x0301 },
+    { 0x216A, 0x217A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_076[] = {
+    { 0x004C, 0x006C, 0x0000, 0x0000 },
+    { 0x0549, 0x0579, 0x0000, 0x0000 },
+    { 0x1E52, 0x1E53, 0x0000, 0x0000 },
+    { 0x216D, 0x217D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_077[] = {
+    { 0x004D, 0x006D, 0x0000, 0x0000 },
+    { 0x014C, 0x014D, 0x0000, 0x0000 },
+    { 0x0548, 0x0578, 0x0000, 0x0000 },
+    { 0x1F52, 0x03C5, 0x0313, 0x0300 },
+    { 0x216C, 0x217C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_078[] = {
+    { 0x004E, 0x006E, 0x0000, 0x0000 },
+    { 0x054B, 0x057B, 0x0000, 0x0000 },
+    { 0x1E50, 0x1E51, 0x0000, 0x0000 },
+    { 0x216F, 0x217F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_079[] = {
+    { 0x004F, 0x006F, 0x0000, 0x0000 },
+    { 0x014E, 0x014F, 0x0000, 0x0000 },
+    { 0x054A, 0x057A, 0x0000, 0x0000 },
+    { 0x1F50, 0x03C5, 0x0313, 0x0000 },
+    { 0x216E, 0x217E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_080[] = {
+    { 0x0050, 0x0070, 0x0000, 0x0000 },
+    { 0x0555, 0x0585, 0x0000, 0x0000 },
+    { 0x1E4E, 0x1E4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_081[] = {
+    { 0x0051, 0x0071, 0x0000, 0x0000 },
+    { 0x0150, 0x0151, 0x0000, 0x0000 },
+    { 0x0554, 0x0584, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_082[] = {
+    { 0x0052, 0x0072, 0x0000, 0x0000 },
+    { 0x1E4C, 0x1E4D, 0x0000, 0x0000 },
+    { 0x1F4D, 0x1F45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_083[] = {
+    { 0x0053, 0x0073, 0x0000, 0x0000 },
+    { 0x0152, 0x0153, 0x0000, 0x0000 },
+    { 0x0556, 0x0586, 0x0000, 0x0000 },
+    { 0x1F4C, 0x1F44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_084[] = {
+    { 0x0054, 0x0074, 0x0000, 0x0000 },
+    { 0x0551, 0x0581, 0x0000, 0x0000 },
+    { 0x1E4A, 0x1E4B, 0x0000, 0x0000 },
+    { 0x1F4B, 0x1F43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_085[] = {
+    { 0x0055, 0x0075, 0x0000, 0x0000 },
+    { 0x0154, 0x0155, 0x0000, 0x0000 },
+    { 0x0550, 0x0580, 0x0000, 0x0000 },
+    { 0x1F4A, 0x1F42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_086[] = {
+    { 0x0056, 0x0076, 0x0000, 0x0000 },
+    { 0x0553, 0x0583, 0x0000, 0x0000 },
+    { 0x1E48, 0x1E49, 0x0000, 0x0000 },
+    { 0x1F49, 0x1F41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_087[] = {
+    { 0x0057, 0x0077, 0x0000, 0x0000 },
+    { 0x0156, 0x0157, 0x0000, 0x0000 },
+    { 0x0552, 0x0582, 0x0000, 0x0000 },
+    { 0x1F48, 0x1F40, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_088[] = {
+    { 0x0058, 0x0078, 0x0000, 0x0000 },
+    { 0x1E46, 0x1E47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_089[] = {
+    { 0x0059, 0x0079, 0x0000, 0x0000 },
+    { 0x0158, 0x0159, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_090[] = {
+    { 0x005A, 0x007A, 0x0000, 0x0000 },
+    { 0x1E44, 0x1E45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_091[] = {
+    { 0x015A, 0x015B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_092[] = {
+    { 0x1E42, 0x1E43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_093[] = {
+    { 0x015C, 0x015D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_094[] = {
+    { 0x1E40, 0x1E41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_095[] = {
+    { 0x015E, 0x015F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_096[] = {
+    { 0x0464, 0x0465, 0x0000, 0x0000 },
+    { 0x1E7E, 0x1E7F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_097[] = {
+    { 0x0160, 0x0161, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_098[] = {
+    { 0x0466, 0x0467, 0x0000, 0x0000 },
+    { 0x1E7C, 0x1E7D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_099[] = {
+    { 0x0162, 0x0163, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_100[] = {
+    { 0x0460, 0x0461, 0x0000, 0x0000 },
+    { 0x1E7A, 0x1E7B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_101[] = {
+    { 0x0164, 0x0165, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_102[] = {
+    { 0x0462, 0x0463, 0x0000, 0x0000 },
+    { 0x1E78, 0x1E79, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_103[] = {
+    { 0x0166, 0x0167, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_104[] = {
+    { 0x046C, 0x046D, 0x0000, 0x0000 },
+    { 0x1E76, 0x1E77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_105[] = {
+    { 0x0168, 0x0169, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_106[] = {
+    { 0x046E, 0x046F, 0x0000, 0x0000 },
+    { 0x1E74, 0x1E75, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_107[] = {
+    { 0x016A, 0x016B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_108[] = {
+    { 0x0468, 0x0469, 0x0000, 0x0000 },
+    { 0x1E72, 0x1E73, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_109[] = {
+    { 0x016C, 0x016D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_110[] = {
+    { 0x046A, 0x046B, 0x0000, 0x0000 },
+    { 0x1E70, 0x1E71, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_111[] = {
+    { 0x016E, 0x016F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_112[] = {
+    { 0x0474, 0x0475, 0x0000, 0x0000 },
+    { 0x1E6E, 0x1E6F, 0x0000, 0x0000 },
+    { 0x1F6F, 0x1F67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_113[] = {
+    { 0x0170, 0x0171, 0x0000, 0x0000 },
+    { 0x1F6E, 0x1F66, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_114[] = {
+    { 0x0476, 0x0477, 0x0000, 0x0000 },
+    { 0x1E6C, 0x1E6D, 0x0000, 0x0000 },
+    { 0x1F6D, 0x1F65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_115[] = {
+    { 0x0172, 0x0173, 0x0000, 0x0000 },
+    { 0x1F6C, 0x1F64, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_116[] = {
+    { 0x0470, 0x0471, 0x0000, 0x0000 },
+    { 0x1E6A, 0x1E6B, 0x0000, 0x0000 },
+    { 0x1F6B, 0x1F63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_117[] = {
+    { 0x0174, 0x0175, 0x0000, 0x0000 },
+    { 0x1F6A, 0x1F62, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_118[] = {
+    { 0x0472, 0x0473, 0x0000, 0x0000 },
+    { 0x1E68, 0x1E69, 0x0000, 0x0000 },
+    { 0x1F69, 0x1F61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_119[] = {
+    { 0x0176, 0x0177, 0x0000, 0x0000 },
+    { 0x1F68, 0x1F60, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_120[] = {
+    { 0x0179, 0x017A, 0x0000, 0x0000 },
+    { 0x047C, 0x047D, 0x0000, 0x0000 },
+    { 0x1E66, 0x1E67, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_121[] = {
+    { 0x0178, 0x00FF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_122[] = {
+    { 0x017B, 0x017C, 0x0000, 0x0000 },
+    { 0x047E, 0x047F, 0x0000, 0x0000 },
+    { 0x1E64, 0x1E65, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_124[] = {
+    { 0x017D, 0x017E, 0x0000, 0x0000 },
+    { 0x0478, 0x0479, 0x0000, 0x0000 },
+    { 0x1E62, 0x1E63, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_126[] = {
+    { 0x017F, 0x0073, 0x0000, 0x0000 },
+    { 0x047A, 0x047B, 0x0000, 0x0000 },
+    { 0x1E60, 0x1E61, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_128[] = {
+    { 0x0181, 0x0253, 0x0000, 0x0000 },
+    { 0x1F9F, 0x1F27, 0x03B9, 0x0000 },
+    { 0x2CAC, 0x2CAD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_129[] = {
+    { 0x1F9E, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_130[] = {
+    { 0x0587, 0x0565, 0x0582, 0x0000 },
+    { 0x1F9D, 0x1F25, 0x03B9, 0x0000 },
+    { 0x2CAE, 0x2CAF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_131[] = {
+    { 0x0182, 0x0183, 0x0000, 0x0000 },
+    { 0x1F9C, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_132[] = {
+    { 0x0480, 0x0481, 0x0000, 0x0000 },
+    { 0x1E9A, 0x0061, 0x02BE, 0x0000 },
+    { 0x1F9B, 0x1F23, 0x03B9, 0x0000 },
+    { 0x2CA8, 0x2CA9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_133[] = {
+    { 0x0184, 0x0185, 0x0000, 0x0000 },
+    { 0x0386, 0x03AC, 0x0000, 0x0000 },
+    { 0x1E9B, 0x1E61, 0x0000, 0x0000 },
+    { 0x1F9A, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_134[] = {
+    { 0x0187, 0x0188, 0x0000, 0x0000 },
+    { 0x1E98, 0x0077, 0x030A, 0x0000 },
+    { 0x1F99, 0x1F21, 0x03B9, 0x0000 },
+    { 0x2CAA, 0x2CAB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_135[] = {
+    { 0x0186, 0x0254, 0x0000, 0x0000 },
+    { 0x1E99, 0x0079, 0x030A, 0x0000 },
+    { 0x1F98, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_136[] = {
+    { 0x0189, 0x0256, 0x0000, 0x0000 },
+    { 0x048C, 0x048D, 0x0000, 0x0000 },
+    { 0x1E96, 0x0068, 0x0331, 0x0000 },
+    { 0x1F97, 0x1F27, 0x03B9, 0x0000 },
+    { 0x2CA4, 0x2CA5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_137[] = {
+    { 0x038A, 0x03AF, 0x0000, 0x0000 },
+    { 0x1E97, 0x0074, 0x0308, 0x0000 },
+    { 0x1F96, 0x1F26, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_138[] = {
+    { 0x018B, 0x018C, 0x0000, 0x0000 },
+    { 0x0389, 0x03AE, 0x0000, 0x0000 },
+    { 0x048E, 0x048F, 0x0000, 0x0000 },
+    { 0x1E94, 0x1E95, 0x0000, 0x0000 },
+    { 0x1F95, 0x1F25, 0x03B9, 0x0000 },
+    { 0x2CA6, 0x2CA7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_139[] = {
+    { 0x018A, 0x0257, 0x0000, 0x0000 },
+    { 0x0388, 0x03AD, 0x0000, 0x0000 },
+    { 0x1F94, 0x1F24, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_140[] = {
+    { 0x038F, 0x03CE, 0x0000, 0x0000 },
+    { 0x1E92, 0x1E93, 0x0000, 0x0000 },
+    { 0x1F93, 0x1F23, 0x03B9, 0x0000 },
+    { 0x2CA0, 0x2CA1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_141[] = {
+    { 0x038E, 0x03CD, 0x0000, 0x0000 },
+    { 0x1F92, 0x1F22, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_142[] = {
+    { 0x018F, 0x0259, 0x0000, 0x0000 },
+    { 0x048A, 0x048B, 0x0000, 0x0000 },
+    { 0x1E90, 0x1E91, 0x0000, 0x0000 },
+    { 0x1F91, 0x1F21, 0x03B9, 0x0000 },
+    { 0x2CA2, 0x2CA3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_143[] = {
+    { 0x018E, 0x01DD, 0x0000, 0x0000 },
+    { 0x038C, 0x03CC, 0x0000, 0x0000 },
+    { 0x1F90, 0x1F20, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_144[] = {
+    { 0x0191, 0x0192, 0x0000, 0x0000 },
+    { 0x0393, 0x03B3, 0x0000, 0x0000 },
+    { 0x0494, 0x0495, 0x0000, 0x0000 },
+    { 0x1E8E, 0x1E8F, 0x0000, 0x0000 },
+    { 0x1F8F, 0x1F07, 0x03B9, 0x0000 },
+    { 0x2CBC, 0x2CBD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_145[] = {
+    { 0x0190, 0x025B, 0x0000, 0x0000 },
+    { 0x0392, 0x03B2, 0x0000, 0x0000 },
+    { 0x1F8E, 0x1F06, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_146[] = {
+    { 0x0193, 0x0260, 0x0000, 0x0000 },
+    { 0x0391, 0x03B1, 0x0000, 0x0000 },
+    { 0x0496, 0x0497, 0x0000, 0x0000 },
+    { 0x1E8C, 0x1E8D, 0x0000, 0x0000 },
+    { 0x1F8D, 0x1F05, 0x03B9, 0x0000 },
+    { 0x24B6, 0x24D0, 0x0000, 0x0000 },
+    { 0x2CBE, 0x2CBF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_147[] = {
+    { 0x0390, 0x03B9, 0x0308, 0x0301 },
+    { 0x1F8C, 0x1F04, 0x03B9, 0x0000 },
+    { 0x24B7, 0x24D1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_148[] = {
+    { 0x0397, 0x03B7, 0x0000, 0x0000 },
+    { 0x0490, 0x0491, 0x0000, 0x0000 },
+    { 0x1E8A, 0x1E8B, 0x0000, 0x0000 },
+    { 0x1F8B, 0x1F03, 0x03B9, 0x0000 },
+    { 0x2CB8, 0x2CB9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_149[] = {
+    { 0x0194, 0x0263, 0x0000, 0x0000 },
+    { 0x0396, 0x03B6, 0x0000, 0x0000 },
+    { 0x1F8A, 0x1F02, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_150[] = {
+    { 0x0197, 0x0268, 0x0000, 0x0000 },
+    { 0x0395, 0x03B5, 0x0000, 0x0000 },
+    { 0x0492, 0x0493, 0x0000, 0x0000 },
+    { 0x1E88, 0x1E89, 0x0000, 0x0000 },
+    { 0x1F89, 0x1F01, 0x03B9, 0x0000 },
+    { 0x2CBA, 0x2CBB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_151[] = {
+    { 0x0196, 0x0269, 0x0000, 0x0000 },
+    { 0x0394, 0x03B4, 0x0000, 0x0000 },
+    { 0x1F88, 0x1F00, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_152[] = {
+    { 0x039B, 0x03BB, 0x0000, 0x0000 },
+    { 0x049C, 0x049D, 0x0000, 0x0000 },
+    { 0x1E86, 0x1E87, 0x0000, 0x0000 },
+    { 0x1F87, 0x1F07, 0x03B9, 0x0000 },
+    { 0x24BC, 0x24D6, 0x0000, 0x0000 },
+    { 0x2CB4, 0x2CB5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_153[] = {
+    { 0x0198, 0x0199, 0x0000, 0x0000 },
+    { 0x039A, 0x03BA, 0x0000, 0x0000 },
+    { 0x1F86, 0x1F06, 0x03B9, 0x0000 },
+    { 0x24BD, 0x24D7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_154[] = {
+    { 0x0399, 0x03B9, 0x0000, 0x0000 },
+    { 0x049E, 0x049F, 0x0000, 0x0000 },
+    { 0x1E84, 0x1E85, 0x0000, 0x0000 },
+    { 0x1F85, 0x1F05, 0x03B9, 0x0000 },
+    { 0x24BE, 0x24D8, 0x0000, 0x0000 },
+    { 0x2CB6, 0x2CB7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_155[] = {
+    { 0x0398, 0x03B8, 0x0000, 0x0000 },
+    { 0x1F84, 0x1F04, 0x03B9, 0x0000 },
+    { 0x24BF, 0x24D9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_156[] = {
+    { 0x019D, 0x0272, 0x0000, 0x0000 },
+    { 0x039F, 0x03BF, 0x0000, 0x0000 },
+    { 0x0498, 0x0499, 0x0000, 0x0000 },
+    { 0x1E82, 0x1E83, 0x0000, 0x0000 },
+    { 0x1F83, 0x1F03, 0x03B9, 0x0000 },
+    { 0x24B8, 0x24D2, 0x0000, 0x0000 },
+    { 0x2CB0, 0x2CB1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_157[] = {
+    { 0x019C, 0x026F, 0x0000, 0x0000 },
+    { 0x039E, 0x03BE, 0x0000, 0x0000 },
+    { 0x1F82, 0x1F02, 0x03B9, 0x0000 },
+    { 0x24B9, 0x24D3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_158[] = {
+    { 0x019F, 0x0275, 0x0000, 0x0000 },
+    { 0x039D, 0x03BD, 0x0000, 0x0000 },
+    { 0x049A, 0x049B, 0x0000, 0x0000 },
+    { 0x1E80, 0x1E81, 0x0000, 0x0000 },
+    { 0x1F81, 0x1F01, 0x03B9, 0x0000 },
+    { 0x24BA, 0x24D4, 0x0000, 0x0000 },
+    { 0x2CB2, 0x2CB3, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_159[] = {
+    { 0x039C, 0x03BC, 0x0000, 0x0000 },
+    { 0x1F80, 0x1F00, 0x03B9, 0x0000 },
+    { 0x24BB, 0x24D5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_160[] = {
+    { 0x03A3, 0x03C3, 0x0000, 0x0000 },
+    { 0x04A4, 0x04A5, 0x0000, 0x0000 },
+    { 0x10B0, 0x2D10, 0x0000, 0x0000 },
+    { 0x1EBE, 0x1EBF, 0x0000, 0x0000 },
+    { 0x2C8C, 0x2C8D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_161[] = {
+    { 0x01A0, 0x01A1, 0x0000, 0x0000 },
+    { 0x10B1, 0x2D11, 0x0000, 0x0000 },
+    { 0x1FBE, 0x03B9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_162[] = {
+    { 0x03A1, 0x03C1, 0x0000, 0x0000 },
+    { 0x04A6, 0x04A7, 0x0000, 0x0000 },
+    { 0x10B2, 0x2D12, 0x0000, 0x0000 },
+    { 0x1EBC, 0x1EBD, 0x0000, 0x0000 },
+    { 0x2C8E, 0x2C8F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_163[] = {
+    { 0x01A2, 0x01A3, 0x0000, 0x0000 },
+    { 0x03A0, 0x03C0, 0x0000, 0x0000 },
+    { 0x10B3, 0x2D13, 0x0000, 0x0000 },
+    { 0x1FBC, 0x03B1, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_164[] = {
+    { 0x03A7, 0x03C7, 0x0000, 0x0000 },
+    { 0x04A0, 0x04A1, 0x0000, 0x0000 },
+    { 0x10B4, 0x2D14, 0x0000, 0x0000 },
+    { 0x1EBA, 0x1EBB, 0x0000, 0x0000 },
+    { 0x1FBB, 0x1F71, 0x0000, 0x0000 },
+    { 0x2C88, 0x2C89, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_165[] = {
+    { 0x01A4, 0x01A5, 0x0000, 0x0000 },
+    { 0x03A6, 0x03C6, 0x0000, 0x0000 },
+    { 0x10B5, 0x2D15, 0x0000, 0x0000 },
+    { 0x1FBA, 0x1F70, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_166[] = {
+    { 0x01A7, 0x01A8, 0x0000, 0x0000 },
+    { 0x03A5, 0x03C5, 0x0000, 0x0000 },
+    { 0x04A2, 0x04A3, 0x0000, 0x0000 },
+    { 0x10B6, 0x2D16, 0x0000, 0x0000 },
+    { 0x1EB8, 0x1EB9, 0x0000, 0x0000 },
+    { 0x1FB9, 0x1FB1, 0x0000, 0x0000 },
+    { 0x2C8A, 0x2C8B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_167[] = {
+    { 0x01A6, 0x0280, 0x0000, 0x0000 },
+    { 0x03A4, 0x03C4, 0x0000, 0x0000 },
+    { 0x10B7, 0x2D17, 0x0000, 0x0000 },
+    { 0x1FB8, 0x1FB0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_168[] = {
+    { 0x01A9, 0x0283, 0x0000, 0x0000 },
+    { 0x03AB, 0x03CB, 0x0000, 0x0000 },
+    { 0x04AC, 0x04AD, 0x0000, 0x0000 },
+    { 0x10B8, 0x2D18, 0x0000, 0x0000 },
+    { 0x1EB6, 0x1EB7, 0x0000, 0x0000 },
+    { 0x1FB7, 0x03B1, 0x0342, 0x03B9 },
+    { 0x2C84, 0x2C85, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_169[] = {
+    { 0x03AA, 0x03CA, 0x0000, 0x0000 },
+    { 0x10B9, 0x2D19, 0x0000, 0x0000 },
+    { 0x1FB6, 0x03B1, 0x0342, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_170[] = {
+    { 0x03A9, 0x03C9, 0x0000, 0x0000 },
+    { 0x04AE, 0x04AF, 0x0000, 0x0000 },
+    { 0x10BA, 0x2D1A, 0x0000, 0x0000 },
+    { 0x1EB4, 0x1EB5, 0x0000, 0x0000 },
+    { 0x2C86, 0x2C87, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_171[] = {
+    { 0x03A8, 0x03C8, 0x0000, 0x0000 },
+    { 0x10BB, 0x2D1B, 0x0000, 0x0000 },
+    { 0x1FB4, 0x03AC, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_172[] = {
+    { 0x04A8, 0x04A9, 0x0000, 0x0000 },
+    { 0x10BC, 0x2D1C, 0x0000, 0x0000 },
+    { 0x1EB2, 0x1EB3, 0x0000, 0x0000 },
+    { 0x1FB3, 0x03B1, 0x03B9, 0x0000 },
+    { 0x2C80, 0x2C81, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_173[] = {
+    { 0x01AC, 0x01AD, 0x0000, 0x0000 },
+    { 0x10BD, 0x2D1D, 0x0000, 0x0000 },
+    { 0x1FB2, 0x1F70, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_174[] = {
+    { 0x01AF, 0x01B0, 0x0000, 0x0000 },
+    { 0x04AA, 0x04AB, 0x0000, 0x0000 },
+    { 0x10BE, 0x2D1E, 0x0000, 0x0000 },
+    { 0x1EB0, 0x1EB1, 0x0000, 0x0000 },
+    { 0x2C82, 0x2C83, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_175[] = {
+    { 0x01AE, 0x0288, 0x0000, 0x0000 },
+    { 0x10BF, 0x2D1F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_176[] = {
+    { 0x01B1, 0x028A, 0x0000, 0x0000 },
+    { 0x04B4, 0x04B5, 0x0000, 0x0000 },
+    { 0x10A0, 0x2D00, 0x0000, 0x0000 },
+    { 0x1EAE, 0x1EAF, 0x0000, 0x0000 },
+    { 0x1FAF, 0x1F67, 0x03B9, 0x0000 },
+    { 0x2C9C, 0x2C9D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_177[] = {
+    { 0x10A1, 0x2D01, 0x0000, 0x0000 },
+    { 0x1FAE, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_178[] = {
+    { 0x01B3, 0x01B4, 0x0000, 0x0000 },
+    { 0x04B6, 0x04B7, 0x0000, 0x0000 },
+    { 0x10A2, 0x2D02, 0x0000, 0x0000 },
+    { 0x1EAC, 0x1EAD, 0x0000, 0x0000 },
+    { 0x1FAD, 0x1F65, 0x03B9, 0x0000 },
+    { 0x2C9E, 0x2C9F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_179[] = {
+    { 0x01B2, 0x028B, 0x0000, 0x0000 },
+    { 0x03B0, 0x03C5, 0x0308, 0x0301 },
+    { 0x10A3, 0x2D03, 0x0000, 0x0000 },
+    { 0x1FAC, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_180[] = {
+    { 0x01B5, 0x01B6, 0x0000, 0x0000 },
+    { 0x04B0, 0x04B1, 0x0000, 0x0000 },
+    { 0x10A4, 0x2D04, 0x0000, 0x0000 },
+    { 0x1EAA, 0x1EAB, 0x0000, 0x0000 },
+    { 0x1FAB, 0x1F63, 0x03B9, 0x0000 },
+    { 0x2C98, 0x2C99, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_181[] = {
+    { 0x00B5, 0x03BC, 0x0000, 0x0000 },
+    { 0x10A5, 0x2D05, 0x0000, 0x0000 },
+    { 0x1FAA, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_182[] = {
+    { 0x01B7, 0x0292, 0x0000, 0x0000 },
+    { 0x04B2, 0x04B3, 0x0000, 0x0000 },
+    { 0x10A6, 0x2D06, 0x0000, 0x0000 },
+    { 0x1EA8, 0x1EA9, 0x0000, 0x0000 },
+    { 0x1FA9, 0x1F61, 0x03B9, 0x0000 },
+    { 0x2C9A, 0x2C9B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_183[] = {
+    { 0x10A7, 0x2D07, 0x0000, 0x0000 },
+    { 0x1FA8, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_184[] = {
+    { 0x04BC, 0x04BD, 0x0000, 0x0000 },
+    { 0x10A8, 0x2D08, 0x0000, 0x0000 },
+    { 0x1EA6, 0x1EA7, 0x0000, 0x0000 },
+    { 0x1FA7, 0x1F67, 0x03B9, 0x0000 },
+    { 0x2C94, 0x2C95, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_185[] = {
+    { 0x01B8, 0x01B9, 0x0000, 0x0000 },
+    { 0x10A9, 0x2D09, 0x0000, 0x0000 },
+    { 0x1FA6, 0x1F66, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_186[] = {
+    { 0x04BE, 0x04BF, 0x0000, 0x0000 },
+    { 0x10AA, 0x2D0A, 0x0000, 0x0000 },
+    { 0x1EA4, 0x1EA5, 0x0000, 0x0000 },
+    { 0x1FA5, 0x1F65, 0x03B9, 0x0000 },
+    { 0x2C96, 0x2C97, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_187[] = {
+    { 0x10AB, 0x2D0B, 0x0000, 0x0000 },
+    { 0x1FA4, 0x1F64, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_188[] = {
+    { 0x04B8, 0x04B9, 0x0000, 0x0000 },
+    { 0x10AC, 0x2D0C, 0x0000, 0x0000 },
+    { 0x1EA2, 0x1EA3, 0x0000, 0x0000 },
+    { 0x1FA3, 0x1F63, 0x03B9, 0x0000 },
+    { 0x2C90, 0x2C91, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_189[] = {
+    { 0x01BC, 0x01BD, 0x0000, 0x0000 },
+    { 0x10AD, 0x2D0D, 0x0000, 0x0000 },
+    { 0x1FA2, 0x1F62, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_190[] = {
+    { 0x04BA, 0x04BB, 0x0000, 0x0000 },
+    { 0x10AE, 0x2D0E, 0x0000, 0x0000 },
+    { 0x1EA0, 0x1EA1, 0x0000, 0x0000 },
+    { 0x1FA1, 0x1F61, 0x03B9, 0x0000 },
+    { 0x2C92, 0x2C93, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_191[] = {
+    { 0x10AF, 0x2D0F, 0x0000, 0x0000 },
+    { 0x1FA0, 0x1F60, 0x03B9, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_192[] = {
+    { 0x00C0, 0x00E0, 0x0000, 0x0000 },
+    { 0x1EDE, 0x1EDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_193[] = {
+    { 0x00C1, 0x00E1, 0x0000, 0x0000 },
+    { 0x03C2, 0x03C3, 0x0000, 0x0000 },
+    { 0x04C5, 0x04C6, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_194[] = {
+    { 0x00C2, 0x00E2, 0x0000, 0x0000 },
+    { 0x1EDC, 0x1EDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_195[] = {
+    { 0x00C3, 0x00E3, 0x0000, 0x0000 },
+    { 0x04C7, 0x04C8, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_196[] = {
+    { 0x00C4, 0x00E4, 0x0000, 0x0000 },
+    { 0x01C5, 0x01C6, 0x0000, 0x0000 },
+    { 0x1EDA, 0x1EDB, 0x0000, 0x0000 },
+    { 0x1FDB, 0x1F77, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_197[] = {
+    { 0x00C5, 0x00E5, 0x0000, 0x0000 },
+    { 0x01C4, 0x01C6, 0x0000, 0x0000 },
+    { 0x04C1, 0x04C2, 0x0000, 0x0000 },
+    { 0x1FDA, 0x1F76, 0x0000, 0x0000 },
+    { 0xFF3A, 0xFF5A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_198[] = {
+    { 0x00C6, 0x00E6, 0x0000, 0x0000 },
+    { 0x01C7, 0x01C9, 0x0000, 0x0000 },
+    { 0x1ED8, 0x1ED9, 0x0000, 0x0000 },
+    { 0x1FD9, 0x1FD1, 0x0000, 0x0000 },
+    { 0xFF39, 0xFF59, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_199[] = {
+    { 0x00C7, 0x00E7, 0x0000, 0x0000 },
+    { 0x04C3, 0x04C4, 0x0000, 0x0000 },
+    { 0x1FD8, 0x1FD0, 0x0000, 0x0000 },
+    { 0xFF38, 0xFF58, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_200[] = {
+    { 0x00C8, 0x00E8, 0x0000, 0x0000 },
+    { 0x1ED6, 0x1ED7, 0x0000, 0x0000 },
+    { 0x1FD7, 0x03B9, 0x0308, 0x0342 },
+    { 0xFF37, 0xFF57, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_201[] = {
+    { 0x00C9, 0x00E9, 0x0000, 0x0000 },
+    { 0x01C8, 0x01C9, 0x0000, 0x0000 },
+    { 0x04CD, 0x04CE, 0x0000, 0x0000 },
+    { 0x1FD6, 0x03B9, 0x0342, 0x0000 },
+    { 0xFF36, 0xFF56, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_202[] = {
+    { 0x00CA, 0x00EA, 0x0000, 0x0000 },
+    { 0x01CB, 0x01CC, 0x0000, 0x0000 },
+    { 0x1ED4, 0x1ED5, 0x0000, 0x0000 },
+    { 0xFF35, 0xFF55, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_203[] = {
+    { 0x00CB, 0x00EB, 0x0000, 0x0000 },
+    { 0x01CA, 0x01CC, 0x0000, 0x0000 },
+    { 0xFF34, 0xFF54, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_204[] = {
+    { 0x00CC, 0x00EC, 0x0000, 0x0000 },
+    { 0x01CD, 0x01CE, 0x0000, 0x0000 },
+    { 0x1ED2, 0x1ED3, 0x0000, 0x0000 },
+    { 0x1FD3, 0x03B9, 0x0308, 0x0301 },
+    { 0x2CE0, 0x2CE1, 0x0000, 0x0000 },
+    { 0xFF33, 0xFF53, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_205[] = {
+    { 0x00CD, 0x00ED, 0x0000, 0x0000 },
+    { 0x04C9, 0x04CA, 0x0000, 0x0000 },
+    { 0x1FD2, 0x03B9, 0x0308, 0x0300 },
+    { 0xFF32, 0xFF52, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_206[] = {
+    { 0x00CE, 0x00EE, 0x0000, 0x0000 },
+    { 0x01CF, 0x01D0, 0x0000, 0x0000 },
+    { 0x1ED0, 0x1ED1, 0x0000, 0x0000 },
+    { 0x2CE2, 0x2CE3, 0x0000, 0x0000 },
+    { 0xFF31, 0xFF51, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_207[] = {
+    { 0x00CF, 0x00EF, 0x0000, 0x0000 },
+    { 0x04CB, 0x04CC, 0x0000, 0x0000 },
+    { 0xFF30, 0xFF50, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_208[] = {
+    { 0x00D0, 0x00F0, 0x0000, 0x0000 },
+    { 0x01D1, 0x01D2, 0x0000, 0x0000 },
+    { 0x04D4, 0x04D5, 0x0000, 0x0000 },
+    { 0x10C0, 0x2D20, 0x0000, 0x0000 },
+    { 0x1ECE, 0x1ECF, 0x0000, 0x0000 },
+    { 0xFF2F, 0xFF4F, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_209[] = {
+    { 0x00D1, 0x00F1, 0x0000, 0x0000 },
+    { 0x10C1, 0x2D21, 0x0000, 0x0000 },
+    { 0xFF2E, 0xFF4E, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_210[] = {
+    { 0x00D2, 0x00F2, 0x0000, 0x0000 },
+    { 0x01D3, 0x01D4, 0x0000, 0x0000 },
+    { 0x03D1, 0x03B8, 0x0000, 0x0000 },
+    { 0x04D6, 0x04D7, 0x0000, 0x0000 },
+    { 0x10C2, 0x2D22, 0x0000, 0x0000 },
+    { 0x1ECC, 0x1ECD, 0x0000, 0x0000 },
+    { 0xFF2D, 0xFF4D, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_211[] = {
+    { 0x00D3, 0x00F3, 0x0000, 0x0000 },
+    { 0x03D0, 0x03B2, 0x0000, 0x0000 },
+    { 0x10C3, 0x2D23, 0x0000, 0x0000 },
+    { 0x1FCC, 0x03B7, 0x03B9, 0x0000 },
+    { 0xFF2C, 0xFF4C, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_212[] = {
+    { 0x00D4, 0x00F4, 0x0000, 0x0000 },
+    { 0x01D5, 0x01D6, 0x0000, 0x0000 },
+    { 0x04D0, 0x04D1, 0x0000, 0x0000 },
+    { 0x10C4, 0x2D24, 0x0000, 0x0000 },
+    { 0x1ECA, 0x1ECB, 0x0000, 0x0000 },
+    { 0x1FCB, 0x1F75, 0x0000, 0x0000 },
+    { 0xFF2B, 0xFF4B, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_213[] = {
+    { 0x00D5, 0x00F5, 0x0000, 0x0000 },
+    { 0x03D6, 0x03C0, 0x0000, 0x0000 },
+    { 0x10C5, 0x2D25, 0x0000, 0x0000 },
+    { 0x1FCA, 0x1F74, 0x0000, 0x0000 },
+    { 0xFF2A, 0xFF4A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_214[] = {
+    { 0x00D6, 0x00F6, 0x0000, 0x0000 },
+    { 0x01D7, 0x01D8, 0x0000, 0x0000 },
+    { 0x03D5, 0x03C6, 0x0000, 0x0000 },
+    { 0x04D2, 0x04D3, 0x0000, 0x0000 },
+    { 0x1EC8, 0x1EC9, 0x0000, 0x0000 },
+    { 0x1FC9, 0x1F73, 0x0000, 0x0000 },
+    { 0xFF29, 0xFF49, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_215[] = {
+    { 0x1FC8, 0x1F72, 0x0000, 0x0000 },
+    { 0xFF28, 0xFF48, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_216[] = {
+    { 0x00D8, 0x00F8, 0x0000, 0x0000 },
+    { 0x01D9, 0x01DA, 0x0000, 0x0000 },
+    { 0x04DC, 0x04DD, 0x0000, 0x0000 },
+    { 0x1EC6, 0x1EC7, 0x0000, 0x0000 },
+    { 0x1FC7, 0x03B7, 0x0342, 0x03B9 },
+    { 0xFF27, 0xFF47, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_217[] = {
+    { 0x00D9, 0x00F9, 0x0000, 0x0000 },
+    { 0x03DA, 0x03DB, 0x0000, 0x0000 },
+    { 0x1FC6, 0x03B7, 0x0342, 0x0000 },
+    { 0xFF26, 0xFF46, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_218[] = {
+    { 0x00DA, 0x00FA, 0x0000, 0x0000 },
+    { 0x01DB, 0x01DC, 0x0000, 0x0000 },
+    { 0x04DE, 0x04DF, 0x0000, 0x0000 },
+    { 0x1EC4, 0x1EC5, 0x0000, 0x0000 },
+    { 0xFF25, 0xFF45, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_219[] = {
+    { 0x00DB, 0x00FB, 0x0000, 0x0000 },
+    { 0x03D8, 0x03D9, 0x0000, 0x0000 },
+    { 0x1FC4, 0x03AE, 0x03B9, 0x0000 },
+    { 0xFF24, 0xFF44, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_220[] = {
+    { 0x00DC, 0x00FC, 0x0000, 0x0000 },
+    { 0x04D8, 0x04D9, 0x0000, 0x0000 },
+    { 0x1EC2, 0x1EC3, 0x0000, 0x0000 },
+    { 0x1FC3, 0x03B7, 0x03B9, 0x0000 },
+    { 0xFF23, 0xFF43, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_221[] = {
+    { 0x00DD, 0x00FD, 0x0000, 0x0000 },
+    { 0x03DE, 0x03DF, 0x0000, 0x0000 },
+    { 0x1FC2, 0x1F74, 0x03B9, 0x0000 },
+    { 0xFF22, 0xFF42, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_222[] = {
+    { 0x00DE, 0x00FE, 0x0000, 0x0000 },
+    { 0x04DA, 0x04DB, 0x0000, 0x0000 },
+    { 0x1EC0, 0x1EC1, 0x0000, 0x0000 },
+    { 0xFF21, 0xFF41, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_223[] = {
+    { 0x00DF, 0x0073, 0x0073, 0x0000 },
+    { 0x01DE, 0x01DF, 0x0000, 0x0000 },
+    { 0x03DC, 0x03DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_224[] = {
+    { 0x04E4, 0x04E5, 0x0000, 0x0000 },
+    { 0x24C4, 0x24DE, 0x0000, 0x0000 },
+    { 0x2CCC, 0x2CCD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_225[] = {
+    { 0x01E0, 0x01E1, 0x0000, 0x0000 },
+    { 0x03E2, 0x03E3, 0x0000, 0x0000 },
+    { 0x24C5, 0x24DF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_226[] = {
+    { 0x04E6, 0x04E7, 0x0000, 0x0000 },
+    { 0x24C6, 0x24E0, 0x0000, 0x0000 },
+    { 0x2CCE, 0x2CCF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_227[] = {
+    { 0x01E2, 0x01E3, 0x0000, 0x0000 },
+    { 0x03E0, 0x03E1, 0x0000, 0x0000 },
+    { 0x1FFC, 0x03C9, 0x03B9, 0x0000 },
+    { 0x24C7, 0x24E1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_228[] = {
+    { 0x04E0, 0x04E1, 0x0000, 0x0000 },
+    { 0x1FFB, 0x1F7D, 0x0000, 0x0000 },
+    { 0x24C0, 0x24DA, 0x0000, 0x0000 },
+    { 0x2CC8, 0x2CC9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_229[] = {
+    { 0x01E4, 0x01E5, 0x0000, 0x0000 },
+    { 0x03E6, 0x03E7, 0x0000, 0x0000 },
+    { 0x1FFA, 0x1F7C, 0x0000, 0x0000 },
+    { 0x24C1, 0x24DB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_230[] = {
+    { 0x04E2, 0x04E3, 0x0000, 0x0000 },
+    { 0x1EF8, 0x1EF9, 0x0000, 0x0000 },
+    { 0x1FF9, 0x1F79, 0x0000, 0x0000 },
+    { 0x24C2, 0x24DC, 0x0000, 0x0000 },
+    { 0x2CCA, 0x2CCB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_231[] = {
+    { 0x01E6, 0x01E7, 0x0000, 0x0000 },
+    { 0x03E4, 0x03E5, 0x0000, 0x0000 },
+    { 0x1FF8, 0x1F78, 0x0000, 0x0000 },
+    { 0x24C3, 0x24DD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_232[] = {
+    { 0x04EC, 0x04ED, 0x0000, 0x0000 },
+    { 0x1EF6, 0x1EF7, 0x0000, 0x0000 },
+    { 0x1FF7, 0x03C9, 0x0342, 0x03B9 },
+    { 0x24CC, 0x24E6, 0x0000, 0x0000 },
+    { 0x2CC4, 0x2CC5, 0x0000, 0x0000 },
+    { 0xFB13, 0x0574, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_233[] = {
+    { 0x01E8, 0x01E9, 0x0000, 0x0000 },
+    { 0x03EA, 0x03EB, 0x0000, 0x0000 },
+    { 0x1FF6, 0x03C9, 0x0342, 0x0000 },
+    { 0x24CD, 0x24E7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_234[] = {
+    { 0x04EE, 0x04EF, 0x0000, 0x0000 },
+    { 0x1EF4, 0x1EF5, 0x0000, 0x0000 },
+    { 0x24CE, 0x24E8, 0x0000, 0x0000 },
+    { 0x2CC6, 0x2CC7, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_235[] = {
+    { 0x01EA, 0x01EB, 0x0000, 0x0000 },
+    { 0x03E8, 0x03E9, 0x0000, 0x0000 },
+    { 0x1FF4, 0x03CE, 0x03B9, 0x0000 },
+    { 0x24CF, 0x24E9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_236[] = {
+    { 0x04E8, 0x04E9, 0x0000, 0x0000 },
+    { 0x1EF2, 0x1EF3, 0x0000, 0x0000 },
+    { 0x1FF3, 0x03C9, 0x03B9, 0x0000 },
+    { 0x24C8, 0x24E2, 0x0000, 0x0000 },
+    { 0x2CC0, 0x2CC1, 0x0000, 0x0000 },
+    { 0xFB17, 0x0574, 0x056D, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_237[] = {
+    { 0x01EC, 0x01ED, 0x0000, 0x0000 },
+    { 0x03EE, 0x03EF, 0x0000, 0x0000 },
+    { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 },
+    { 0x24C9, 0x24E3, 0x0000, 0x0000 },
+    { 0xFB16, 0x057E, 0x0576, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_238[] = {
+    { 0x04EA, 0x04EB, 0x0000, 0x0000 },
+    { 0x1EF0, 0x1EF1, 0x0000, 0x0000 },
+    { 0x24CA, 0x24E4, 0x0000, 0x0000 },
+    { 0x2CC2, 0x2CC3, 0x0000, 0x0000 },
+    { 0xFB15, 0x0574, 0x056B, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_239[] = {
+    { 0x01EE, 0x01EF, 0x0000, 0x0000 },
+    { 0x03EC, 0x03ED, 0x0000, 0x0000 },
+    { 0x24CB, 0x24E5, 0x0000, 0x0000 },
+    { 0xFB14, 0x0574, 0x0565, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_240[] = {
+    { 0x01F1, 0x01F3, 0x0000, 0x0000 },
+    { 0x04F4, 0x04F5, 0x0000, 0x0000 },
+    { 0x1EEE, 0x1EEF, 0x0000, 0x0000 },
+    { 0x2CDC, 0x2CDD, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_241[] = {
+    { 0x01F0, 0x006A, 0x030C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_242[] = {
+    { 0x03F1, 0x03C1, 0x0000, 0x0000 },
+    { 0x04F6, 0x04F7, 0x0000, 0x0000 },
+    { 0x1EEC, 0x1EED, 0x0000, 0x0000 },
+    { 0x2CDE, 0x2CDF, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_243[] = {
+    { 0x01F2, 0x01F3, 0x0000, 0x0000 },
+    { 0x03F0, 0x03BA, 0x0000, 0x0000 },
+    { 0x1FEC, 0x1FE5, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_244[] = {
+    { 0x03F7, 0x03F8, 0x0000, 0x0000 },
+    { 0x04F0, 0x04F1, 0x0000, 0x0000 },
+    { 0x1EEA, 0x1EEB, 0x0000, 0x0000 },
+    { 0x1FEB, 0x1F7B, 0x0000, 0x0000 },
+    { 0x2CD8, 0x2CD9, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_245[] = {
+    { 0x01F4, 0x01F5, 0x0000, 0x0000 },
+    { 0x1FEA, 0x1F7A, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_246[] = {
+    { 0x01F7, 0x01BF, 0x0000, 0x0000 },
+    { 0x03F5, 0x03B5, 0x0000, 0x0000 },
+    { 0x04F2, 0x04F3, 0x0000, 0x0000 },
+    { 0x1EE8, 0x1EE9, 0x0000, 0x0000 },
+    { 0x1FE9, 0x1FE1, 0x0000, 0x0000 },
+    { 0x2CDA, 0x2CDB, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_247[] = {
+    { 0x01F6, 0x0195, 0x0000, 0x0000 },
+    { 0x03F4, 0x03B8, 0x0000, 0x0000 },
+    { 0x1FE8, 0x1FE0, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_248[] = {
+    { 0x1EE6, 0x1EE7, 0x0000, 0x0000 },
+    { 0x1FE7, 0x03C5, 0x0308, 0x0342 },
+    { 0x2CD4, 0x2CD5, 0x0000, 0x0000 },
+    { 0xFB03, 0x0066, 0x0066, 0x0069 }
+};
+
+static const CaseFoldMapping case_fold_249[] = {
+    { 0x01F8, 0x01F9, 0x0000, 0x0000 },
+    { 0x03FA, 0x03FB, 0x0000, 0x0000 },
+    { 0x1FE6, 0x03C5, 0x0342, 0x0000 },
+    { 0xFB02, 0x0066, 0x006C, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_250[] = {
+    { 0x03F9, 0x03F2, 0x0000, 0x0000 },
+    { 0x1EE4, 0x1EE5, 0x0000, 0x0000 },
+    { 0x2CD6, 0x2CD7, 0x0000, 0x0000 },
+    { 0xFB01, 0x0066, 0x0069, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_251[] = {
+    { 0x01FA, 0x01FB, 0x0000, 0x0000 },
+    { 0x1FE4, 0x03C1, 0x0313, 0x0000 },
+    { 0xFB00, 0x0066, 0x0066, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_252[] = {
+    { 0x04F8, 0x04F9, 0x0000, 0x0000 },
+    { 0x1EE2, 0x1EE3, 0x0000, 0x0000 },
+    { 0x1FE3, 0x03C5, 0x0308, 0x0301 },
+    { 0x2CD0, 0x2CD1, 0x0000, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_253[] = {
+    { 0x01FC, 0x01FD, 0x0000, 0x0000 },
+    { 0x1FE2, 0x03C5, 0x0308, 0x0300 },
+    { 0xFB06, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_254[] = {
+    { 0x1EE0, 0x1EE1, 0x0000, 0x0000 },
+    { 0x2CD2, 0x2CD3, 0x0000, 0x0000 },
+    { 0xFB05, 0x0073, 0x0074, 0x0000 }
+};
+
+static const CaseFoldMapping case_fold_255[] = {
+    { 0x01FE, 0x01FF, 0x0000, 0x0000 },
+    { 0xFB04, 0x0066, 0x0066, 0x006C }
+};
+
+
+static const CaseFoldHashBucket case_fold_hash[256] = {
+    { __PHYSFS_ARRAYLEN(case_fold_000), case_fold_000 },
+    { __PHYSFS_ARRAYLEN(case_fold_001), case_fold_001 },
+    { __PHYSFS_ARRAYLEN(case_fold_002), case_fold_002 },
+    { __PHYSFS_ARRAYLEN(case_fold_003), case_fold_003 },
+    { __PHYSFS_ARRAYLEN(case_fold_004), case_fold_004 },
+    { __PHYSFS_ARRAYLEN(case_fold_005), case_fold_005 },
+    { __PHYSFS_ARRAYLEN(case_fold_006), case_fold_006 },
+    { __PHYSFS_ARRAYLEN(case_fold_007), case_fold_007 },
+    { __PHYSFS_ARRAYLEN(case_fold_008), case_fold_008 },
+    { __PHYSFS_ARRAYLEN(case_fold_009), case_fold_009 },
+    { __PHYSFS_ARRAYLEN(case_fold_010), case_fold_010 },
+    { __PHYSFS_ARRAYLEN(case_fold_011), case_fold_011 },
+    { __PHYSFS_ARRAYLEN(case_fold_012), case_fold_012 },
+    { __PHYSFS_ARRAYLEN(case_fold_013), case_fold_013 },
+    { __PHYSFS_ARRAYLEN(case_fold_014), case_fold_014 },
+    { __PHYSFS_ARRAYLEN(case_fold_015), case_fold_015 },
+    { __PHYSFS_ARRAYLEN(case_fold_016), case_fold_016 },
+    { __PHYSFS_ARRAYLEN(case_fold_017), case_fold_017 },
+    { __PHYSFS_ARRAYLEN(case_fold_018), case_fold_018 },
+    { __PHYSFS_ARRAYLEN(case_fold_019), case_fold_019 },
+    { __PHYSFS_ARRAYLEN(case_fold_020), case_fold_020 },
+    { __PHYSFS_ARRAYLEN(case_fold_021), case_fold_021 },
+    { __PHYSFS_ARRAYLEN(case_fold_022), case_fold_022 },
+    { __PHYSFS_ARRAYLEN(case_fold_023), case_fold_023 },
+    { __PHYSFS_ARRAYLEN(case_fold_024), case_fold_024 },
+    { __PHYSFS_ARRAYLEN(case_fold_025), case_fold_025 },
+    { __PHYSFS_ARRAYLEN(case_fold_026), case_fold_026 },
+    { __PHYSFS_ARRAYLEN(case_fold_027), case_fold_027 },
+    { __PHYSFS_ARRAYLEN(case_fold_028), case_fold_028 },
+    { __PHYSFS_ARRAYLEN(case_fold_029), case_fold_029 },
+    { __PHYSFS_ARRAYLEN(case_fold_030), case_fold_030 },
+    { __PHYSFS_ARRAYLEN(case_fold_031), case_fold_031 },
+    { __PHYSFS_ARRAYLEN(case_fold_032), case_fold_032 },
+    { __PHYSFS_ARRAYLEN(case_fold_033), case_fold_033 },
+    { __PHYSFS_ARRAYLEN(case_fold_034), case_fold_034 },
+    { __PHYSFS_ARRAYLEN(case_fold_035), case_fold_035 },
+    { __PHYSFS_ARRAYLEN(case_fold_036), case_fold_036 },
+    { __PHYSFS_ARRAYLEN(case_fold_037), case_fold_037 },
+    { __PHYSFS_ARRAYLEN(case_fold_038), case_fold_038 },
+    { __PHYSFS_ARRAYLEN(case_fold_039), case_fold_039 },
+    { __PHYSFS_ARRAYLEN(case_fold_040), case_fold_040 },
+    { __PHYSFS_ARRAYLEN(case_fold_041), case_fold_041 },
+    { __PHYSFS_ARRAYLEN(case_fold_042), case_fold_042 },
+    { __PHYSFS_ARRAYLEN(case_fold_043), case_fold_043 },
+    { __PHYSFS_ARRAYLEN(case_fold_044), case_fold_044 },
+    { __PHYSFS_ARRAYLEN(case_fold_045), case_fold_045 },
+    { __PHYSFS_ARRAYLEN(case_fold_046), case_fold_046 },
+    { __PHYSFS_ARRAYLEN(case_fold_047), case_fold_047 },
+    { __PHYSFS_ARRAYLEN(case_fold_048), case_fold_048 },
+    { __PHYSFS_ARRAYLEN(case_fold_049), case_fold_049 },
+    { __PHYSFS_ARRAYLEN(case_fold_050), case_fold_050 },
+    { __PHYSFS_ARRAYLEN(case_fold_051), case_fold_051 },
+    { __PHYSFS_ARRAYLEN(case_fold_052), case_fold_052 },
+    { __PHYSFS_ARRAYLEN(case_fold_053), case_fold_053 },
+    { __PHYSFS_ARRAYLEN(case_fold_054), case_fold_054 },
+    { __PHYSFS_ARRAYLEN(case_fold_055), case_fold_055 },
+    { __PHYSFS_ARRAYLEN(case_fold_056), case_fold_056 },
+    { __PHYSFS_ARRAYLEN(case_fold_057), case_fold_057 },
+    { __PHYSFS_ARRAYLEN(case_fold_058), case_fold_058 },
+    { __PHYSFS_ARRAYLEN(case_fold_059), case_fold_059 },
+    { __PHYSFS_ARRAYLEN(case_fold_060), case_fold_060 },
+    { __PHYSFS_ARRAYLEN(case_fold_061), case_fold_061 },
+    { __PHYSFS_ARRAYLEN(case_fold_062), case_fold_062 },
+    { __PHYSFS_ARRAYLEN(case_fold_063), case_fold_063 },
+    { __PHYSFS_ARRAYLEN(case_fold_064), case_fold_064 },
+    { __PHYSFS_ARRAYLEN(case_fold_065), case_fold_065 },
+    { __PHYSFS_ARRAYLEN(case_fold_066), case_fold_066 },
+    { __PHYSFS_ARRAYLEN(case_fold_067), case_fold_067 },
+    { __PHYSFS_ARRAYLEN(case_fold_068), case_fold_068 },
+    { __PHYSFS_ARRAYLEN(case_fold_069), case_fold_069 },
+    { __PHYSFS_ARRAYLEN(case_fold_070), case_fold_070 },
+    { __PHYSFS_ARRAYLEN(case_fold_071), case_fold_071 },
+    { __PHYSFS_ARRAYLEN(case_fold_072), case_fold_072 },
+    { __PHYSFS_ARRAYLEN(case_fold_073), case_fold_073 },
+    { __PHYSFS_ARRAYLEN(case_fold_074), case_fold_074 },
+    { __PHYSFS_ARRAYLEN(case_fold_075), case_fold_075 },
+    { __PHYSFS_ARRAYLEN(case_fold_076), case_fold_076 },
+    { __PHYSFS_ARRAYLEN(case_fold_077), case_fold_077 },
+    { __PHYSFS_ARRAYLEN(case_fold_078), case_fold_078 },
+    { __PHYSFS_ARRAYLEN(case_fold_079), case_fold_079 },
+    { __PHYSFS_ARRAYLEN(case_fold_080), case_fold_080 },
+    { __PHYSFS_ARRAYLEN(case_fold_081), case_fold_081 },
+    { __PHYSFS_ARRAYLEN(case_fold_082), case_fold_082 },
+    { __PHYSFS_ARRAYLEN(case_fold_083), case_fold_083 },
+    { __PHYSFS_ARRAYLEN(case_fold_084), case_fold_084 },
+    { __PHYSFS_ARRAYLEN(case_fold_085), case_fold_085 },
+    { __PHYSFS_ARRAYLEN(case_fold_086), case_fold_086 },
+    { __PHYSFS_ARRAYLEN(case_fold_087), case_fold_087 },
+    { __PHYSFS_ARRAYLEN(case_fold_088), case_fold_088 },
+    { __PHYSFS_ARRAYLEN(case_fold_089), case_fold_089 },
+    { __PHYSFS_ARRAYLEN(case_fold_090), case_fold_090 },
+    { __PHYSFS_ARRAYLEN(case_fold_091), case_fold_091 },
+    { __PHYSFS_ARRAYLEN(case_fold_092), case_fold_092 },
+    { __PHYSFS_ARRAYLEN(case_fold_093), case_fold_093 },
+    { __PHYSFS_ARRAYLEN(case_fold_094), case_fold_094 },
+    { __PHYSFS_ARRAYLEN(case_fold_095), case_fold_095 },
+    { __PHYSFS_ARRAYLEN(case_fold_096), case_fold_096 },
+    { __PHYSFS_ARRAYLEN(case_fold_097), case_fold_097 },
+    { __PHYSFS_ARRAYLEN(case_fold_098), case_fold_098 },
+    { __PHYSFS_ARRAYLEN(case_fold_099), case_fold_099 },
+    { __PHYSFS_ARRAYLEN(case_fold_100), case_fold_100 },
+    { __PHYSFS_ARRAYLEN(case_fold_101), case_fold_101 },
+    { __PHYSFS_ARRAYLEN(case_fold_102), case_fold_102 },
+    { __PHYSFS_ARRAYLEN(case_fold_103), case_fold_103 },
+    { __PHYSFS_ARRAYLEN(case_fold_104), case_fold_104 },
+    { __PHYSFS_ARRAYLEN(case_fold_105), case_fold_105 },
+    { __PHYSFS_ARRAYLEN(case_fold_106), case_fold_106 },
+    { __PHYSFS_ARRAYLEN(case_fold_107), case_fold_107 },
+    { __PHYSFS_ARRAYLEN(case_fold_108), case_fold_108 },
+    { __PHYSFS_ARRAYLEN(case_fold_109), case_fold_109 },
+    { __PHYSFS_ARRAYLEN(case_fold_110), case_fold_110 },
+    { __PHYSFS_ARRAYLEN(case_fold_111), case_fold_111 },
+    { __PHYSFS_ARRAYLEN(case_fold_112), case_fold_112 },
+    { __PHYSFS_ARRAYLEN(case_fold_113), case_fold_113 },
+    { __PHYSFS_ARRAYLEN(case_fold_114), case_fold_114 },
+    { __PHYSFS_ARRAYLEN(case_fold_115), case_fold_115 },
+    { __PHYSFS_ARRAYLEN(case_fold_116), case_fold_116 },
+    { __PHYSFS_ARRAYLEN(case_fold_117), case_fold_117 },
+    { __PHYSFS_ARRAYLEN(case_fold_118), case_fold_118 },
+    { __PHYSFS_ARRAYLEN(case_fold_119), case_fold_119 },
+    { __PHYSFS_ARRAYLEN(case_fold_120), case_fold_120 },
+    { __PHYSFS_ARRAYLEN(case_fold_121), case_fold_121 },
+    { __PHYSFS_ARRAYLEN(case_fold_122), case_fold_122 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_124), case_fold_124 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_126), case_fold_126 },
+    { 0, NULL },
+    { __PHYSFS_ARRAYLEN(case_fold_128), case_fold_128 },
+    { __PHYSFS_ARRAYLEN(case_fold_129), case_fold_129 },
+    { __PHYSFS_ARRAYLEN(case_fold_130), case_fold_130 },
+    { __PHYSFS_ARRAYLEN(case_fold_131), case_fold_131 },
+    { __PHYSFS_ARRAYLEN(case_fold_132), case_fold_132 },
+    { __PHYSFS_ARRAYLEN(case_fold_133), case_fold_133 },
+    { __PHYSFS_ARRAYLEN(case_fold_134), case_fold_134 },
+    { __PHYSFS_ARRAYLEN(case_fold_135), case_fold_135 },
+    { __PHYSFS_ARRAYLEN(case_fold_136), case_fold_136 },
+    { __PHYSFS_ARRAYLEN(case_fold_137), case_fold_137 },
+    { __PHYSFS_ARRAYLEN(case_fold_138), case_fold_138 },
+    { __PHYSFS_ARRAYLEN(case_fold_139), case_fold_139 },
+    { __PHYSFS_ARRAYLEN(case_fold_140), case_fold_140 },
+    { __PHYSFS_ARRAYLEN(case_fold_141), case_fold_141 },
+    { __PHYSFS_ARRAYLEN(case_fold_142), case_fold_142 },
+    { __PHYSFS_ARRAYLEN(case_fold_143), case_fold_143 },
+    { __PHYSFS_ARRAYLEN(case_fold_144), case_fold_144 },
+    { __PHYSFS_ARRAYLEN(case_fold_145), case_fold_145 },
+    { __PHYSFS_ARRAYLEN(case_fold_146), case_fold_146 },
+    { __PHYSFS_ARRAYLEN(case_fold_147), case_fold_147 },
+    { __PHYSFS_ARRAYLEN(case_fold_148), case_fold_148 },
+    { __PHYSFS_ARRAYLEN(case_fold_149), case_fold_149 },
+    { __PHYSFS_ARRAYLEN(case_fold_150), case_fold_150 },
+    { __PHYSFS_ARRAYLEN(case_fold_151), case_fold_151 },
+    { __PHYSFS_ARRAYLEN(case_fold_152), case_fold_152 },
+    { __PHYSFS_ARRAYLEN(case_fold_153), case_fold_153 },
+    { __PHYSFS_ARRAYLEN(case_fold_154), case_fold_154 },
+    { __PHYSFS_ARRAYLEN(case_fold_155), case_fold_155 },
+    { __PHYSFS_ARRAYLEN(case_fold_156), case_fold_156 },
+    { __PHYSFS_ARRAYLEN(case_fold_157), case_fold_157 },
+    { __PHYSFS_ARRAYLEN(case_fold_158), case_fold_158 },
+    { __PHYSFS_ARRAYLEN(case_fold_159), case_fold_159 },
+    { __PHYSFS_ARRAYLEN(case_fold_160), case_fold_160 },
+    { __PHYSFS_ARRAYLEN(case_fold_161), case_fold_161 },
+    { __PHYSFS_ARRAYLEN(case_fold_162), case_fold_162 },
+    { __PHYSFS_ARRAYLEN(case_fold_163), case_fold_163 },
+    { __PHYSFS_ARRAYLEN(case_fold_164), case_fold_164 },
+    { __PHYSFS_ARRAYLEN(case_fold_165), case_fold_165 },
+    { __PHYSFS_ARRAYLEN(case_fold_166), case_fold_166 },
+    { __PHYSFS_ARRAYLEN(case_fold_167), case_fold_167 },
+    { __PHYSFS_ARRAYLEN(case_fold_168), case_fold_168 },
+    { __PHYSFS_ARRAYLEN(case_fold_169), case_fold_169 },
+    { __PHYSFS_ARRAYLEN(case_fold_170), case_fold_170 },
+    { __PHYSFS_ARRAYLEN(case_fold_171), case_fold_171 },
+    { __PHYSFS_ARRAYLEN(case_fold_172), case_fold_172 },
+    { __PHYSFS_ARRAYLEN(case_fold_173), case_fold_173 },
+    { __PHYSFS_ARRAYLEN(case_fold_174), case_fold_174 },
+    { __PHYSFS_ARRAYLEN(case_fold_175), case_fold_175 },
+    { __PHYSFS_ARRAYLEN(case_fold_176), case_fold_176 },
+    { __PHYSFS_ARRAYLEN(case_fold_177), case_fold_177 },
+    { __PHYSFS_ARRAYLEN(case_fold_178), case_fold_178 },
+    { __PHYSFS_ARRAYLEN(case_fold_179), case_fold_179 },
+    { __PHYSFS_ARRAYLEN(case_fold_180), case_fold_180 },
+    { __PHYSFS_ARRAYLEN(case_fold_181), case_fold_181 },
+    { __PHYSFS_ARRAYLEN(case_fold_182), case_fold_182 },
+    { __PHYSFS_ARRAYLEN(case_fold_183), case_fold_183 },
+    { __PHYSFS_ARRAYLEN(case_fold_184), case_fold_184 },
+    { __PHYSFS_ARRAYLEN(case_fold_185), case_fold_185 },
+    { __PHYSFS_ARRAYLEN(case_fold_186), case_fold_186 },
+    { __PHYSFS_ARRAYLEN(case_fold_187), case_fold_187 },
+    { __PHYSFS_ARRAYLEN(case_fold_188), case_fold_188 },
+    { __PHYSFS_ARRAYLEN(case_fold_189), case_fold_189 },
+    { __PHYSFS_ARRAYLEN(case_fold_190), case_fold_190 },
+    { __PHYSFS_ARRAYLEN(case_fold_191), case_fold_191 },
+    { __PHYSFS_ARRAYLEN(case_fold_192), case_fold_192 },
+    { __PHYSFS_ARRAYLEN(case_fold_193), case_fold_193 },
+    { __PHYSFS_ARRAYLEN(case_fold_194), case_fold_194 },
+    { __PHYSFS_ARRAYLEN(case_fold_195), case_fold_195 },
+    { __PHYSFS_ARRAYLEN(case_fold_196), case_fold_196 },
+    { __PHYSFS_ARRAYLEN(case_fold_197), case_fold_197 },
+    { __PHYSFS_ARRAYLEN(case_fold_198), case_fold_198 },
+    { __PHYSFS_ARRAYLEN(case_fold_199), case_fold_199 },
+    { __PHYSFS_ARRAYLEN(case_fold_200), case_fold_200 },
+    { __PHYSFS_ARRAYLEN(case_fold_201), case_fold_201 },
+    { __PHYSFS_ARRAYLEN(case_fold_202), case_fold_202 },
+    { __PHYSFS_ARRAYLEN(case_fold_203), case_fold_203 },
+    { __PHYSFS_ARRAYLEN(case_fold_204), case_fold_204 },
+    { __PHYSFS_ARRAYLEN(case_fold_205), case_fold_205 },
+    { __PHYSFS_ARRAYLEN(case_fold_206), case_fold_206 },
+    { __PHYSFS_ARRAYLEN(case_fold_207), case_fold_207 },
+    { __PHYSFS_ARRAYLEN(case_fold_208), case_fold_208 },
+    { __PHYSFS_ARRAYLEN(case_fold_209), case_fold_209 },
+    { __PHYSFS_ARRAYLEN(case_fold_210), case_fold_210 },
+    { __PHYSFS_ARRAYLEN(case_fold_211), case_fold_211 },
+    { __PHYSFS_ARRAYLEN(case_fold_212), case_fold_212 },
+    { __PHYSFS_ARRAYLEN(case_fold_213), case_fold_213 },
+    { __PHYSFS_ARRAYLEN(case_fold_214), case_fold_214 },
+    { __PHYSFS_ARRAYLEN(case_fold_215), case_fold_215 },
+    { __PHYSFS_ARRAYLEN(case_fold_216), case_fold_216 },
+    { __PHYSFS_ARRAYLEN(case_fold_217), case_fold_217 },
+    { __PHYSFS_ARRAYLEN(case_fold_218), case_fold_218 },
+    { __PHYSFS_ARRAYLEN(case_fold_219), case_fold_219 },
+    { __PHYSFS_ARRAYLEN(case_fold_220), case_fold_220 },
+    { __PHYSFS_ARRAYLEN(case_fold_221), case_fold_221 },
+    { __PHYSFS_ARRAYLEN(case_fold_222), case_fold_222 },
+    { __PHYSFS_ARRAYLEN(case_fold_223), case_fold_223 },
+    { __PHYSFS_ARRAYLEN(case_fold_224), case_fold_224 },
+    { __PHYSFS_ARRAYLEN(case_fold_225), case_fold_225 },
+    { __PHYSFS_ARRAYLEN(case_fold_226), case_fold_226 },
+    { __PHYSFS_ARRAYLEN(case_fold_227), case_fold_227 },
+    { __PHYSFS_ARRAYLEN(case_fold_228), case_fold_228 },
+    { __PHYSFS_ARRAYLEN(case_fold_229), case_fold_229 },
+    { __PHYSFS_ARRAYLEN(case_fold_230), case_fold_230 },
+    { __PHYSFS_ARRAYLEN(case_fold_231), case_fold_231 },
+    { __PHYSFS_ARRAYLEN(case_fold_232), case_fold_232 },
+    { __PHYSFS_ARRAYLEN(case_fold_233), case_fold_233 },
+    { __PHYSFS_ARRAYLEN(case_fold_234), case_fold_234 },
+    { __PHYSFS_ARRAYLEN(case_fold_235), case_fold_235 },
+    { __PHYSFS_ARRAYLEN(case_fold_236), case_fold_236 },
+    { __PHYSFS_ARRAYLEN(case_fold_237), case_fold_237 },
+    { __PHYSFS_ARRAYLEN(case_fold_238), case_fold_238 },
+    { __PHYSFS_ARRAYLEN(case_fold_239), case_fold_239 },
+    { __PHYSFS_ARRAYLEN(case_fold_240), case_fold_240 },
+    { __PHYSFS_ARRAYLEN(case_fold_241), case_fold_241 },
+    { __PHYSFS_ARRAYLEN(case_fold_242), case_fold_242 },
+    { __PHYSFS_ARRAYLEN(case_fold_243), case_fold_243 },
+    { __PHYSFS_ARRAYLEN(case_fold_244), case_fold_244 },
+    { __PHYSFS_ARRAYLEN(case_fold_245), case_fold_245 },
+    { __PHYSFS_ARRAYLEN(case_fold_246), case_fold_246 },
+    { __PHYSFS_ARRAYLEN(case_fold_247), case_fold_247 },
+    { __PHYSFS_ARRAYLEN(case_fold_248), case_fold_248 },
+    { __PHYSFS_ARRAYLEN(case_fold_249), case_fold_249 },
+    { __PHYSFS_ARRAYLEN(case_fold_250), case_fold_250 },
+    { __PHYSFS_ARRAYLEN(case_fold_251), case_fold_251 },
+    { __PHYSFS_ARRAYLEN(case_fold_252), case_fold_252 },
+    { __PHYSFS_ARRAYLEN(case_fold_253), case_fold_253 },
+    { __PHYSFS_ARRAYLEN(case_fold_254), case_fold_254 },
+    { __PHYSFS_ARRAYLEN(case_fold_255), case_fold_255 },
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs_internal.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,776 @@
+/*
+ * Internal function/structure declaration. Do NOT include in your
+ *  application.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#ifndef _INCLUDE_PHYSFS_INTERNAL_H_
+#define _INCLUDE_PHYSFS_INTERNAL_H_
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+#include "physfs.h"
+
+/* The holy trinity. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "physfs_platforms.h"
+
+#include <assert.h>
+
+/* !!! FIXME: remove this when revamping stack allocation code... */
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <malloc.h>
+#endif
+
+#if PHYSFS_PLATFORM_SOLARIS
+#include <alloca.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __GNUC__
+#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) \
+    ( ((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)) )
+#else
+#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) (0)
+#endif
+
+#ifdef __cplusplus
+    /* C++ always has a real inline keyword. */
+#elif (defined macintosh) && !(defined __MWERKS__)
+#   define inline
+#elif (defined _MSC_VER)
+#   define inline __inline
+#endif
+
+#if PHYSFS_PLATFORM_LINUX && !defined(_FILE_OFFSET_BITS)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+/*
+ * Interface for small allocations. If you need a little scratch space for
+ *  a throwaway buffer or string, use this. It will make small allocations
+ *  on the stack if possible, and use allocator.Malloc() if they are too
+ *  large. This helps reduce malloc pressure.
+ * There are some rules, though:
+ * NEVER return a pointer from this, as stack-allocated buffers go away
+ *  when your function returns.
+ * NEVER allocate in a loop, as stack-allocated pointers will pile up. Call
+ *  a function that uses smallAlloc from your loop, so the allocation can
+ *  free each time.
+ * NEVER call smallAlloc with any complex expression (it's a macro that WILL
+ *  have side effects...it references the argument multiple times). Use a
+ *  variable or a literal.
+ * NEVER free a pointer from this with anything but smallFree. It will not
+ *  be a valid pointer to the allocator, regardless of where the memory came
+ *  from.
+ * NEVER realloc a pointer from this.
+ * NEVER forget to use smallFree: it may not be a pointer from the stack.
+ * NEVER forget to check for NULL...allocation can fail here, of course!
+ */
+#define __PHYSFS_SMALLALLOCTHRESHOLD 256
+void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len);
+
+#define __PHYSFS_smallAlloc(bytes) ( \
+    __PHYSFS_initSmallAlloc( \
+        (((bytes) < __PHYSFS_SMALLALLOCTHRESHOLD) ? \
+            alloca((size_t)((bytes)+sizeof(void*))) : NULL), (bytes)) \
+)
+
+void __PHYSFS_smallFree(void *ptr);
+
+
+/* Use the allocation hooks. */
+#define malloc(x) Do not use malloc() directly.
+#define realloc(x, y) Do not use realloc() directly.
+#define free(x) Do not use free() directly.
+/* !!! FIXME: add alloca check here. */
+
+#ifndef PHYSFS_SUPPORTS_ZIP
+#define PHYSFS_SUPPORTS_ZIP 1
+#endif
+#ifndef PHYSFS_SUPPORTS_7Z
+#define PHYSFS_SUPPORTS_7Z 0
+#endif
+#ifndef PHYSFS_SUPPORTS_GRP
+#define PHYSFS_SUPPORTS_GRP 0
+#endif
+#ifndef PHYSFS_SUPPORTS_HOG
+#define PHYSFS_SUPPORTS_HOG 0
+#endif
+#ifndef PHYSFS_SUPPORTS_MVL
+#define PHYSFS_SUPPORTS_MVL 0
+#endif
+#ifndef PHYSFS_SUPPORTS_WAD
+#define PHYSFS_SUPPORTS_WAD 0
+#endif
+#ifndef PHYSFS_SUPPORTS_ISO9660
+#define PHYSFS_SUPPORTS_ISO9660 0
+#endif
+
+/* The latest supported PHYSFS_Io::version value. */
+#define CURRENT_PHYSFS_IO_API_VERSION 0
+
+/* Opaque data for file and dir handlers... */
+typedef void PHYSFS_Dir;
+
+typedef struct
+{
+    /*
+     * Basic info about this archiver...
+     */
+    const PHYSFS_ArchiveInfo info;
+
+
+    /*
+     * DIRECTORY ROUTINES:
+     * These functions are for dir handles. Generate a handle with the
+     *  openArchive() method, then pass it as the "opaque" PHYSFS_Dir to the
+     *  others.
+     *
+     * Symlinks should always be followed (except in stat()); PhysicsFS will
+     *  use the stat() method to check for symlinks and make a judgement on
+     *  whether to continue to call other methods based on that.
+     */
+
+        /*
+         * Open a dirhandle for dir/archive data provided by (io).
+         *  (name) is a filename associated with (io), but doesn't necessarily
+         *  map to anything, let alone a real filename. This possibly-
+         *  meaningless name is in platform-dependent notation.
+         * (forWrite) is non-zero if this is to be used for
+         *  the write directory, and zero if this is to be used for an
+         *  element of the search path.
+         * Returns NULL on failure. We ignore any error code you set here.
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later calls.
+         */
+    PHYSFS_Dir *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite);
+
+        /*
+         * List all files in (dirname). Each file is passed to (cb),
+         *  where a copy is made if appropriate, so you should dispose of
+         *  it properly upon return from the callback.
+         * You should omit symlinks if (omitSymLinks) is non-zero.
+         * If you have a failure, report as much as you can.
+         *  (dirname) is in platform-independent notation.
+         */
+    void (*enumerateFiles)(PHYSFS_Dir *opaque, const char *dirname,
+                           int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                           const char *origdir, void *callbackdata);
+
+        /*
+         * Open file for reading.
+         *  This filename, (fnm), is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Fail if the file does not exist.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         *
+         * Regardless of success or failure, please set *exists to
+         *  non-zero if the file existed (even if it's a broken symlink!),
+         *  zero if it did not.
+         */
+    PHYSFS_Io *(*openRead)(PHYSFS_Dir *opaque, const char *fnm, int *exists);
+
+        /*
+         * Open file for writing.
+         * If the file does not exist, it should be created. If it exists,
+         *  it should be truncated to zero bytes. The writing
+         *  offset should be the start of the file.
+         * This filename is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         */
+    PHYSFS_Io *(*openWrite)(PHYSFS_Dir *opaque, const char *filename);
+
+        /*
+         * Open file for appending.
+         * If the file does not exist, it should be created. The writing
+         *  offset should be the end of the file.
+         * This filename is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         */
+    PHYSFS_Io *(*openAppend)(PHYSFS_Dir *opaque, const char *filename);
+
+        /*
+         * Delete a file in the archive/directory.
+         *  Return non-zero on success, zero on failure.
+         *  This filename is in platform-independent notation.
+         *  This method may be NULL.
+         * On failure, call __PHYSFS_setError().
+         */
+    int (*remove)(PHYSFS_Dir *opaque, const char *filename);
+
+        /*
+         * Create a directory in the archive/directory.
+         *  If the application is trying to make multiple dirs, PhysicsFS
+         *  will split them up into multiple calls before passing them to
+         *  your driver.
+         *  Return non-zero on success, zero on failure.
+         *  This filename is in platform-independent notation.
+         *  This method may be NULL.
+         * On failure, call __PHYSFS_setError().
+         */
+    int (*mkdir)(PHYSFS_Dir *opaque, const char *filename);
+
+        /*
+         * Close directories/archives, and free any associated memory,
+         *  including the original PHYSFS_Io and (opaque) itself, if
+         *  applicable. Implementation can assume that it won't be called if
+         *  there are still files open from this archive.
+         */
+    void (*closeArchive)(PHYSFS_Dir *opaque);
+
+        /*
+         * Obtain basic file metadata.
+         *  Returns non-zero on success, zero on failure.
+         *  On failure, call __PHYSFS_setError().
+         */
+    int (*stat)(PHYSFS_Dir *opaque, const char *fn,
+                int *exists, PHYSFS_Stat *stat);
+} PHYSFS_Archiver;
+
+
+/*
+ * Call this to set the message returned by PHYSFS_getLastError().
+ *  Please only use the ERR_* constants above, or add new constants to the
+ *  above group, but I want these all in one place.
+ *
+ * Calling this with a NULL argument is a safe no-op.
+ */
+void __PHYSFS_setError(const PHYSFS_ErrorCode err);
+
+
+/* This byteorder stuff was lifted from SDL. http://www.libsdl.org/ */
+#define PHYSFS_LIL_ENDIAN  1234
+#define PHYSFS_BIG_ENDIAN  4321
+
+#if  defined(__i386__) || defined(__ia64__) || \
+     defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64) || \
+    (defined(__alpha__) || defined(__alpha)) || \
+     defined(__arm__) || defined(ARM) || \
+    (defined(__mips__) && defined(__MIPSEL__)) || \
+     defined(__SYMBIAN32__) || \
+     defined(__x86_64__) || \
+     defined(__LITTLE_ENDIAN__)
+#define PHYSFS_BYTEORDER    PHYSFS_LIL_ENDIAN
+#else
+#define PHYSFS_BYTEORDER    PHYSFS_BIG_ENDIAN
+#endif
+
+
+/*
+ * When sorting the entries in an archive, we use a modified QuickSort.
+ *  When there are less then PHYSFS_QUICKSORT_THRESHOLD entries left to sort,
+ *  we switch over to a BubbleSort for the remainder. Tweak to taste.
+ *
+ * You can override this setting by defining PHYSFS_QUICKSORT_THRESHOLD
+ *  before #including "physfs_internal.h".
+ */
+#ifndef PHYSFS_QUICKSORT_THRESHOLD
+#define PHYSFS_QUICKSORT_THRESHOLD 4
+#endif
+
+/*
+ * Sort an array (or whatever) of (max) elements. This uses a mixture of
+ *  a QuickSort and BubbleSort internally.
+ * (cmpfn) is used to determine ordering, and (swapfn) does the actual
+ *  swapping of elements in the list.
+ *
+ *  See zip.c for an example.
+ */
+void __PHYSFS_sort(void *entries, size_t max,
+                   int (*cmpfn)(void *, size_t, size_t),
+                   void (*swapfn)(void *, size_t, size_t));
+
+/*
+ * This isn't a formal error code, it's just for BAIL_MACRO.
+ *  It means: there was an error, but someone else already set it for us.
+ */
+#define ERRPASS PHYSFS_ERR_OK
+
+/* These get used all over for lessening code clutter. */
+#define BAIL_MACRO(e, r) do { if (e) __PHYSFS_setError(e); return r; } while (0)
+#define BAIL_IF_MACRO(c, e, r) do { if (c) { if (e) __PHYSFS_setError(e); return r; } } while (0)
+#define BAIL_MACRO_MUTEX(e, m, r) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } while (0)
+#define BAIL_IF_MACRO_MUTEX(c, e, m, r) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } } while (0)
+#define GOTO_MACRO(e, g) do { if (e) __PHYSFS_setError(e); goto g; } while (0)
+#define GOTO_IF_MACRO(c, e, g) do { if (c) { if (e) __PHYSFS_setError(e); goto g; } } while (0)
+#define GOTO_MACRO_MUTEX(e, m, g) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } while (0)
+#define GOTO_IF_MACRO_MUTEX(c, e, m, g) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } } while (0)
+
+#define __PHYSFS_ARRAYLEN(x) ( (sizeof (x)) / (sizeof (x[0])) )
+
+#ifdef PHYSFS_NO_64BIT_SUPPORT
+#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
+#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
+#elif (defined __GNUC__)
+#define __PHYSFS_SI64(x) x##LL
+#define __PHYSFS_UI64(x) x##ULL
+#elif (defined _MSC_VER)
+#define __PHYSFS_SI64(x) x##i64
+#define __PHYSFS_UI64(x) x##ui64
+#else
+#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x))
+#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x))
+#endif
+
+
+/*
+ * Check if a ui64 will fit in the platform's address space.
+ *  The initial sizeof check will optimize this macro out entirely on
+ *  64-bit (and larger?!) platforms, and the other condition will
+ *  return zero or non-zero if the variable will fit in the platform's
+ *  size_t, suitable to pass to malloc. This is kinda messy, but effective.
+ */
+#define __PHYSFS_ui64FitsAddressSpace(s) ( \
+    (sizeof (PHYSFS_uint64) <= sizeof (size_t)) || \
+    ((s) < (__PHYSFS_UI64(0xFFFFFFFFFFFFFFFF) >> (64-(sizeof(size_t)*8)))) \
+)
+
+
+/*
+ * This is a strcasecmp() or stricmp() replacement that expects both strings
+ *  to be in UTF-8 encoding. It will do "case folding" to decide if the
+ *  Unicode codepoints in the strings match.
+ *
+ * It will report which string is "greater than" the other, but be aware that
+ *  this doesn't necessarily mean anything: 'a' may be "less than" 'b', but
+ *  a random Kanji codepoint has no meaningful alphabetically relationship to
+ *  a Greek Lambda, but being able to assign a reliable "value" makes sorting
+ *  algorithms possible, if not entirely sane. Most cases should treat the
+ *  return value as "equal" or "not equal".
+ */
+int __PHYSFS_utf8stricmp(const char *s1, const char *s2);
+
+/*
+ * This works like __PHYSFS_utf8stricmp(), but takes a character (NOT BYTE
+ *  COUNT) argument, like strcasencmp().
+ */
+int __PHYSFS_utf8strnicmp(const char *s1, const char *s2, PHYSFS_uint32 l);
+
+/*
+ * stricmp() that guarantees to only work with low ASCII. The C runtime
+ *  stricmp() might try to apply a locale/codepage/etc, which we don't want.
+ */
+int __PHYSFS_stricmpASCII(const char *s1, const char *s2);
+
+/*
+ * strnicmp() that guarantees to only work with low ASCII. The C runtime
+ *  strnicmp() might try to apply a locale/codepage/etc, which we don't want.
+ */
+int __PHYSFS_strnicmpASCII(const char *s1, const char *s2, PHYSFS_uint32 l);
+
+
+/*
+ * The current allocator. Not valid before PHYSFS_init is called!
+ */
+extern PHYSFS_Allocator __PHYSFS_AllocatorHooks;
+
+/* convenience macro to make this less cumbersome internally... */
+#define allocator __PHYSFS_AllocatorHooks
+
+/*
+ * Create a PHYSFS_Io for a file in the physical filesystem.
+ *  This path is in platform-dependent notation. (mode) must be 'r', 'w', or
+ *  'a' for Read, Write, or Append.
+ */
+PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode);
+
+/*
+ * Create a PHYSFS_Io for a buffer of memory (READ-ONLY). If you already
+ *  have one of these, just use its duplicate() method, and it'll increment
+ *  its refcount without allocating a copy of the buffer.
+ */
+PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len,
+                                   void (*destruct)(void *));
+
+
+/*
+ * Read (len) bytes from (io) into (buf). Returns non-zero on success,
+ *  zero on i/o error. Literally: "return (io->read(io, buf, len) == len);"
+ */
+int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len);
+
+
+/* These are shared between some archivers. */
+
+typedef struct
+{
+    char name[56];
+    PHYSFS_uint32 startPos;
+    PHYSFS_uint32 size;
+} UNPKentry;
+
+void UNPK_closeArchive(PHYSFS_Dir *opaque);
+PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n);
+void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname,
+                         int omitSymLinks, PHYSFS_EnumFilesCallback cb,
+                         const char *origdir, void *callbackdata);
+PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists);
+PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name);
+PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name);
+int UNPK_remove(PHYSFS_Dir *opaque, const char *name);
+int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name);
+int UNPK_stat(PHYSFS_Dir *opaque, const char *fn, int *exist, PHYSFS_Stat *st);
+
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+/*------------                                              ----------------*/
+/*------------  You MUST implement the following functions  ----------------*/
+/*------------        if porting to a new platform.         ----------------*/
+/*------------     (see platform/unix.c for an example)     ----------------*/
+/*------------                                              ----------------*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+
+/*
+ * The dir separator; '/' on unix, '\\' on win32, ":" on MacOS, etc...
+ *  Obviously, this isn't a function. If you need more than one char for this,
+ *  you'll need to pull some old pieces of PhysicsFS out of revision control.
+ */
+#if PHYSFS_PLATFORM_WINDOWS
+#define __PHYSFS_platformDirSeparator '\\'
+#else
+#define __PHYSFS_platformDirSeparator '/'
+#endif
+
+/*
+ * Initialize the platform. This is called when PHYSFS_init() is called from
+ *  the application.
+ *
+ * Return zero if there was a catastrophic failure (which prevents you from
+ *  functioning at all), and non-zero otherwise.
+ */
+int __PHYSFS_platformInit(void);
+
+
+/*
+ * Deinitialize the platform. This is called when PHYSFS_deinit() is called
+ *  from the application. You can use this to clean up anything you've
+ *  allocated in your platform driver.
+ *
+ * Return zero if there was a catastrophic failure (which prevents you from
+ *  functioning at all), and non-zero otherwise.
+ */
+int __PHYSFS_platformDeinit(void);
+
+
+/*
+ * Open a file for reading. (filename) is in platform-dependent notation. The
+ *  file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32.
+ *
+ * The same file can be opened for read multiple times, and each should have
+ *  a unique file handle; this is frequently employed to prevent race
+ *  conditions in the archivers.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenRead(const char *filename);
+
+
+/*
+ * Open a file for writing. (filename) is in platform-dependent notation. If
+ *  the file exists, it should be truncated to zero bytes, and if it doesn't
+ *  exist, it should be created as a zero-byte file. The file pointer should
+ *  be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ *  etc.
+ *
+ * Opening a file for write multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenWrite(const char *filename);
+
+
+/*
+ * Open a file for appending. (filename) is in platform-dependent notation. If
+ *  the file exists, the file pointer should be place just past the end of the
+ *  file, so that the first write will be one byte after the current end of
+ *  the file. If the file doesn't exist, it should be created as a zero-byte
+ *  file. The file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ *  etc.
+ *
+ * Opening a file for append multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenAppend(const char *filename);
+
+/*
+ * Read more data from a platform-specific file handle. (opaque) should be
+ *  cast to whatever data type your platform uses. Read a maximum of (len)
+ *  8-bit bytes to the area pointed to by (buf). If there isn't enough data
+ *  available, return the number of bytes read, and position the file pointer
+ *  immediately after those bytes.
+ *  On success, return (len) and position the file pointer immediately past
+ *  the end of the last read byte. Return (-1) if there is a catastrophic
+ *  error, and call __PHYSFS_setError() to describe the problem; the file
+ *  pointer should not move in such a case. A partial read is success; only
+ *  return (-1) on total failure; presumably, the next read call after a
+ *  partial read will fail as such.
+ */
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len);
+
+/*
+ * Write more data to a platform-specific file handle. (opaque) should be
+ *  cast to whatever data type your platform uses. Write a maximum of (len)
+ *  8-bit bytes from the area pointed to by (buffer). If there is a problem,
+ *  return the number of bytes written, and position the file pointer
+ *  immediately after those bytes. Return (-1) if there is a catastrophic
+ *  error, and call __PHYSFS_setError() to describe the problem; the file
+ *  pointer should not move in such a case. A partial write is success; only
+ *  return (-1) on total failure; presumably, the next write call after a
+ *  partial write will fail as such.
+ */
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint64 len);
+
+/*
+ * Set the file pointer to a new position. (opaque) should be cast to
+ *  whatever data type your platform uses. (pos) specifies the number
+ *  of 8-bit bytes to seek to from the start of the file. Seeking past the
+ *  end of the file is an error condition, and you should check for it.
+ *
+ * Not all file types can seek; this is to be expected by the caller.
+ *
+ * On error, call __PHYSFS_setError() and return zero. On success, return
+ *  a non-zero value.
+ */
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos);
+
+
+/*
+ * Get the file pointer's position, in an 8-bit byte offset from the start of
+ *  the file. (opaque) should be cast to whatever data type your platform
+ *  uses.
+ *
+ * Not all file types can "tell"; this is to be expected by the caller.
+ *
+ * On error, call __PHYSFS_setError() and return -1. On success, return >= 0.
+ */
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque);
+
+
+/*
+ * Determine the current size of a file, in 8-bit bytes, from an open file.
+ *
+ * The caller expects that this information may not be available for all
+ *  file types on all platforms.
+ *
+ * Return -1 if you can't do it, and call __PHYSFS_setError(). Otherwise,
+ *  return the file length in 8-bit bytes.
+ */
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
+
+
+/*
+ * !!! FIXME: comment me.
+ */
+int __PHYSFS_platformStat(const char *fn, int *exists, PHYSFS_Stat *stat);
+
+/*
+ * Flush any pending writes to disk. (opaque) should be cast to whatever data
+ *  type your platform uses. Be sure to check for errors; the caller expects
+ *  that this function can fail if there was a flushing error, etc.
+ *
+ *  Return zero on failure, non-zero on success.
+ */
+int __PHYSFS_platformFlush(void *opaque);
+
+/*
+ * Close file and deallocate resources. (opaque) should be cast to whatever
+ *  data type your platform uses. This should close the file in any scenario:
+ *  flushing is a separate function call, and this function should never fail.
+ *
+ * You should clean up all resources associated with (opaque); the pointer
+ *  will be considered invalid after this call.
+ */
+void __PHYSFS_platformClose(void *opaque);
+
+/*
+ * Platform implementation of PHYSFS_getCdRomDirsCallback()...
+ *  CD directories are discovered and reported to the callback one at a time.
+ *  Pointers passed to the callback are assumed to be invalid to the
+ *  application after the callback returns, so you can free them or whatever.
+ *  Callback does not assume results will be sorted in any meaningful way.
+ */
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data);
+
+/*
+ * Calculate the base dir, if your platform needs special consideration.
+ *  Just return NULL if the standard routines will suffice. (see
+ *  calculateBaseDir() in physfs.c ...)
+ * Your string must end with a dir separator if you don't return NULL.
+ *  Caller will allocator.Free() the retval if it's not NULL.
+ */
+char *__PHYSFS_platformCalcBaseDir(const char *argv0);
+
+/*
+ * Get the platform-specific user dir.
+ * As of PhysicsFS 2.1, returning NULL means fatal error.
+ * Your string must end with a dir separator if you don't return NULL.
+ *  Caller will allocator.Free() the retval if it's not NULL.
+ */
+char *__PHYSFS_platformCalcUserDir(void);
+
+
+/* This is the cached version from PHYSFS_init(). This is a fast call. */
+const char *__PHYSFS_getUserDir(void);  /* not deprecated internal version. */
+
+
+/*
+ * Get the platform-specific pref dir.
+ * Returning NULL means fatal error.
+ * Your string must end with a dir separator if you don't return NULL.
+ *  Caller will allocator.Free() the retval if it's not NULL.
+ *  Caller will make missing directories if necessary; this just reports
+ *   the final path.
+ */
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app);
+
+
+/*
+ * Return a pointer that uniquely identifies the current thread.
+ *  On a platform without threading, (0x1) will suffice. These numbers are
+ *  arbitrary; the only requirement is that no two threads have the same
+ *  pointer.
+ */
+void *__PHYSFS_platformGetThreadID(void);
+
+
+/*
+ * Enumerate a directory of files. This follows the rules for the
+ *  PHYSFS_Archiver->enumerateFiles() method (see above), except that the
+ *  (dirName) that is passed to this function is converted to
+ *  platform-DEPENDENT notation by the caller. The PHYSFS_Archiver version
+ *  uses platform-independent notation. Note that ".", "..", and other
+ *  metaentries should always be ignored.
+ */
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata);
+
+/*
+ * Make a directory in the actual filesystem. (path) is specified in
+ *  platform-dependent notation. On error, return zero and set the error
+ *  message. Return non-zero on success.
+ */
+int __PHYSFS_platformMkDir(const char *path);
+
+
+/*
+ * Remove a file or directory entry in the actual filesystem. (path) is
+ *  specified in platform-dependent notation. Note that this deletes files
+ *  _and_ directories, so you might need to do some determination.
+ *  Non-empty directories should report an error and not delete themselves
+ *  or their contents.
+ *
+ * Deleting a symlink should remove the link, not what it points to.
+ *
+ * On error, return zero and set the error message. Return non-zero on success.
+ */
+int __PHYSFS_platformDelete(const char *path);
+
+
+/*
+ * Create a platform-specific mutex. This can be whatever datatype your
+ *  platform uses for mutexes, but it is cast to a (void *) for abstractness.
+ *
+ * Return (NULL) if you couldn't create one. Systems without threads can
+ *  return any arbitrary non-NULL value.
+ */
+void *__PHYSFS_platformCreateMutex(void);
+
+/*
+ * Destroy a platform-specific mutex, and clean up any resources associated
+ *  with it. (mutex) is a value previously returned by
+ *  __PHYSFS_platformCreateMutex(). This can be a no-op on single-threaded
+ *  platforms.
+ */
+void __PHYSFS_platformDestroyMutex(void *mutex);
+
+/*
+ * Grab possession of a platform-specific mutex. Mutexes should be recursive;
+ *  that is, the same thread should be able to call this function multiple
+ *  times in a row without causing a deadlock. This function should block 
+ *  until a thread can gain possession of the mutex.
+ *
+ * Return non-zero if the mutex was grabbed, zero if there was an 
+ *  unrecoverable problem grabbing it (this should not be a matter of 
+ *  timing out! We're talking major system errors; block until the mutex 
+ *  is available otherwise.)
+ *
+ * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
+ *  function, you'll cause an infinite recursion. This means you can't
+ *  use the BAIL_*MACRO* macros, either.
+ */
+int __PHYSFS_platformGrabMutex(void *mutex);
+
+/*
+ * Relinquish possession of the mutex when this method has been called 
+ *  once for each time that platformGrabMutex was called. Once possession has
+ *  been released, the next thread in line to grab the mutex (if any) may
+ *  proceed.
+ *
+ * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this
+ *  function, you'll cause an infinite recursion. This means you can't
+ *  use the BAIL_*MACRO* macros, either.
+ */
+void __PHYSFS_platformReleaseMutex(void *mutex);
+
+/*
+ * Called at the start of PHYSFS_init() to prepare the allocator, if the user
+ *  hasn't selected their own allocator via PHYSFS_setAllocator().
+ *  If the platform has a custom allocator, it should fill in the fields of
+ *  (a) with the proper function pointers and return non-zero.
+ * If the platform just wants to use malloc()/free()/etc, return zero
+ *  immediately and the higher level will handle it. The Init and Deinit
+ *  fields of (a) are optional...set them to NULL if you don't need them.
+ *  Everything else must be implemented. All rules follow those for
+ *  PHYSFS_setAllocator(). If Init isn't NULL, it will be called shortly
+ *  after this function returns non-zero.
+ */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* end of physfs_internal.h ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs_miniz.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,698 @@
+/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
+   See "unlicense" statement at the end of this file.
+   Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
+   Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
+
+   The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
+*/
+#ifndef TINFL_HEADER_INCLUDED
+#define TINFL_HEADER_INCLUDED
+
+typedef PHYSFS_uint8 mz_uint8;
+typedef PHYSFS_sint16 mz_int16;
+typedef PHYSFS_uint16 mz_uint16;
+typedef PHYSFS_uint32 mz_uint32;
+typedef unsigned int mz_uint; 
+typedef PHYSFS_uint64 mz_uint64;
+
+/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. */
+typedef unsigned long mz_ulong;
+
+/* Heap allocation callbacks. */
+typedef void *(*mz_alloc_func)(void *opaque, unsigned int items, unsigned int size);
+typedef void (*mz_free_func)(void *opaque, void *address);
+
+#if defined(_M_IX86) || defined(_M_X64)
+/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). */
+#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
+#define MINIZ_LITTLE_ENDIAN 1
+#endif
+
+#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
+/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) */
+#define MINIZ_HAS_64BIT_REGISTERS 1
+#endif
+
+/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */
+#ifdef _MSC_VER
+#define MZ_MACRO_END while (0, 0)
+#else
+#define MZ_MACRO_END while (0)
+#endif
+
+/* Decompression flags. */
+enum
+{
+  TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
+  TINFL_FLAG_HAS_MORE_INPUT = 2,
+  TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
+  TINFL_FLAG_COMPUTE_ADLER32 = 8
+};
+
+struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
+
+/* Max size of LZ dictionary. */
+#define TINFL_LZ_DICT_SIZE 32768
+
+/* Return status. */
+typedef enum
+{
+  TINFL_STATUS_BAD_PARAM = -3,
+  TINFL_STATUS_ADLER32_MISMATCH = -2,
+  TINFL_STATUS_FAILED = -1,
+  TINFL_STATUS_DONE = 0,
+  TINFL_STATUS_NEEDS_MORE_INPUT = 1,
+  TINFL_STATUS_HAS_MORE_OUTPUT = 2
+} tinfl_status;
+
+/* Initializes the decompressor to its initial state. */
+#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
+#define tinfl_get_adler32(r) (r)->m_check_adler32
+
+/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */
+/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */
+static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
+
+/* Internal/private bits follow. */
+enum
+{
+  TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
+  TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
+};
+
+typedef struct
+{
+  mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
+  mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
+} tinfl_huff_table;
+
+#if MINIZ_HAS_64BIT_REGISTERS
+  #define TINFL_USE_64BIT_BITBUF 1
+#endif
+
+#if TINFL_USE_64BIT_BITBUF
+  typedef mz_uint64 tinfl_bit_buf_t;
+  #define TINFL_BITBUF_SIZE (64)
+#else
+  typedef mz_uint32 tinfl_bit_buf_t;
+  #define TINFL_BITBUF_SIZE (32)
+#endif
+
+struct tinfl_decompressor_tag
+{
+  mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
+  tinfl_bit_buf_t m_bit_buf;
+  size_t m_dist_from_out_buf_start;
+  tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
+  mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
+};
+
+#endif /* #ifdef TINFL_HEADER_INCLUDED */
+
+/* ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) */
+
+#ifndef TINFL_HEADER_FILE_ONLY
+
+#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
+#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
+#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
+  #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
+  #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
+#else
+  #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
+  #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
+#endif
+
+#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
+#define TINFL_MEMSET(p, c, l) memset(p, c, l)
+
+#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
+#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
+#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
+#define TINFL_CR_FINISH }
+
+/* TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never */
+/* reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. */
+#define TINFL_GET_BYTE(state_index, c) do { \
+  if (pIn_buf_cur >= pIn_buf_end) { \
+    for ( ; ; ) { \
+      if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
+        TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
+        if (pIn_buf_cur < pIn_buf_end) { \
+          c = *pIn_buf_cur++; \
+          break; \
+        } \
+      } else { \
+        c = 0; \
+        break; \
+      } \
+    } \
+  } else c = *pIn_buf_cur++; } MZ_MACRO_END
+
+#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
+#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
+
+/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */
+/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */
+/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */
+/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
+#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
+  do { \
+    temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
+    if (temp >= 0) { \
+      code_len = temp >> 9; \
+      if ((code_len) && (num_bits >= code_len)) \
+      break; \
+    } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
+       code_len = TINFL_FAST_LOOKUP_BITS; \
+       do { \
+          temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
+       } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
+    } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
+  } while (num_bits < 15);
+
+/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */
+/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */
+/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */
+/* The slow path is only executed at the very end of the input buffer. */
+#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
+  int temp; mz_uint code_len, c; \
+  if (num_bits < 15) { \
+    if ((pIn_buf_end - pIn_buf_cur) < 2) { \
+       TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
+    } else { \
+       bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
+    } \
+  } \
+  if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
+    code_len = temp >> 9, temp &= 511; \
+  else { \
+    code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
+  } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
+
+static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
+{
+  static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
+  static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+  static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+  static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+  static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+  static const int s_min_table_sizes[3] = { 257, 1, 4 };
+
+  tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
+  const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+  mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
+  size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
+
+  /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */
+  if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
+
+  num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
+  TINFL_CR_BEGIN
+
+  bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
+  if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+  {
+    TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
+    counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
+    if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
+    if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
+  }
+
+  do
+  {
+    TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
+    if (r->m_type == 0)
+    {
+      TINFL_SKIP_BITS(5, num_bits & 7);
+      for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
+      if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
+      while ((counter) && (num_bits))
+      {
+        TINFL_GET_BITS(51, dist, 8);
+        while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
+        *pOut_buf_cur++ = (mz_uint8)dist;
+        counter--;
+      }
+      while (counter)
+      {
+        size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
+        while (pIn_buf_cur >= pIn_buf_end)
+        {
+          if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
+          {
+            TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
+          }
+          else
+          {
+            TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
+          }
+        }
+        n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
+        TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
+      }
+    }
+    else if (r->m_type == 3)
+    {
+      TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
+    }
+    else
+    {
+      if (r->m_type == 1)
+      {
+        mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
+        r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
+        for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
+      }
+      else
+      {
+        for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
+        MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
+        r->m_table_sizes[2] = 19;
+      }
+      for ( ; (int)r->m_type >= 0; r->m_type--)
+      {
+        int tree_next, tree_cur; tinfl_huff_table *pTable;
+        mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
+        for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
+        used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
+        for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
+        if ((65536 != total) && (used_syms > 1))
+        {
+          TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
+        }
+        for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
+        {
+          mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
+          cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
+          if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
+          if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
+          rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
+          for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
+          {
+            tree_cur -= ((rev_code >>= 1) & 1);
+            if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
+          }
+          tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
+        }
+        if (r->m_type == 2)
+        {
+          for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
+          {
+            mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
+            if ((dist == 16) && (!counter))
+            {
+              TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
+            }
+            num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
+            TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
+          }
+          if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
+          {
+            TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
+          }
+          TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
+        }
+      }
+      for ( ; ; )
+      {
+        mz_uint8 *pSrc;
+        for ( ; ; )
+        {
+          if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
+          {
+            TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
+            if (counter >= 256)
+              break;
+            while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
+            *pOut_buf_cur++ = (mz_uint8)counter;
+          }
+          else
+          {
+            int sym2; mz_uint code_len;
+#if TINFL_USE_64BIT_BITBUF
+            if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
+#else
+            if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+            if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+              code_len = sym2 >> 9;
+            else
+            {
+              code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+            }
+            counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
+            if (counter & 256)
+              break;
+
+#if !TINFL_USE_64BIT_BITBUF
+            if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
+#endif
+            if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+              code_len = sym2 >> 9;
+            else
+            {
+              code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
+            }
+            bit_buf >>= code_len; num_bits -= code_len;
+
+            pOut_buf_cur[0] = (mz_uint8)counter;
+            if (sym2 & 256)
+            {
+              pOut_buf_cur++;
+              counter = sym2;
+              break;
+            }
+            pOut_buf_cur[1] = (mz_uint8)sym2;
+            pOut_buf_cur += 2;
+          }
+        }
+        if ((counter &= 511) == 256) break;
+
+        num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
+        if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
+
+        TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
+        num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
+        if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
+
+        dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
+        if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
+        {
+          TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
+        }
+
+        pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
+
+        if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
+        {
+          while (counter--)
+          {
+            while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
+            *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
+          }
+          continue;
+        }
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+        else if ((counter >= 9) && (counter <= dist))
+        {
+          const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
+          do
+          {
+            ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
+            ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
+            pOut_buf_cur += 8;
+          } while ((pSrc += 8) < pSrc_end);
+          if ((counter &= 7) < 3)
+          {
+            if (counter)
+            {
+              pOut_buf_cur[0] = pSrc[0];
+              if (counter > 1)
+                pOut_buf_cur[1] = pSrc[1];
+              pOut_buf_cur += counter;
+            }
+            continue;
+          }
+        }
+#endif
+        do
+        {
+          pOut_buf_cur[0] = pSrc[0];
+          pOut_buf_cur[1] = pSrc[1];
+          pOut_buf_cur[2] = pSrc[2];
+          pOut_buf_cur += 3; pSrc += 3;
+        } while ((int)(counter -= 3) > 2);
+        if ((int)counter > 0)
+        {
+          pOut_buf_cur[0] = pSrc[0];
+          if ((int)counter > 1)
+            pOut_buf_cur[1] = pSrc[1];
+          pOut_buf_cur += counter;
+        }
+      }
+    }
+  } while (!(r->m_final & 1));
+  if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+  {
+    TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
+  }
+  TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
+  TINFL_CR_FINISH
+
+common_exit:
+  r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
+  *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
+  if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
+  {
+    const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
+    mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
+    while (buf_len)
+    {
+      for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
+      {
+        s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
+        s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
+      }
+      for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
+      s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
+    }
+    r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
+  }
+  return status;
+}
+
+/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other stuff is for advanced use. */
+enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
+
+/* Return status codes. MZ_PARAM_ERROR is non-standard. */
+enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
+
+/* Compression levels. */
+enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_DEFAULT_COMPRESSION = -1 };
+
+/* Window bits */
+#define MZ_DEFAULT_WINDOW_BITS 15
+
+struct mz_internal_state;
+
+/* Compression/decompression stream struct. */
+typedef struct mz_stream_s
+{
+  const unsigned char *next_in;     /* pointer to next byte to read */
+  unsigned int avail_in;            /* number of bytes available at next_in */
+  mz_ulong total_in;                /* total number of bytes consumed so far */
+
+  unsigned char *next_out;          /* pointer to next byte to write */
+  unsigned int avail_out;           /* number of bytes that can be written to next_out */
+  mz_ulong total_out;               /* total number of bytes produced so far */
+
+  char *msg;                        /* error msg (unused) */
+  struct mz_internal_state *state;  /* internal state, allocated by zalloc/zfree */
+
+  mz_alloc_func zalloc;             /* optional heap allocation function (defaults to malloc) */
+  mz_free_func zfree;               /* optional heap free function (defaults to free) */
+  void *opaque;                     /* heap alloc function user pointer */
+
+  int data_type;                    /* data_type (unused) */
+  mz_ulong adler;                   /* adler32 of the source or uncompressed data */
+  mz_ulong reserved;                /* not used */
+} mz_stream;
+
+typedef mz_stream *mz_streamp;
+
+
+typedef struct
+{
+  tinfl_decompressor m_decomp;
+  mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
+  mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
+  tinfl_status m_last_status;
+} inflate_state;
+
+static int mz_inflateInit2(mz_streamp pStream, int window_bits)
+{
+  inflate_state *pDecomp;
+  if (!pStream) return MZ_STREAM_ERROR;
+  if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
+
+  pStream->data_type = 0;
+  pStream->adler = 0;
+  pStream->msg = NULL;
+  pStream->total_in = 0;
+  pStream->total_out = 0;
+  pStream->reserved = 0;
+  /* if (!pStream->zalloc) pStream->zalloc = def_alloc_func; */
+  /* if (!pStream->zfree) pStream->zfree = def_free_func; */
+
+  pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
+  if (!pDecomp) return MZ_MEM_ERROR;
+
+  pStream->state = (struct mz_internal_state *)pDecomp;
+
+  tinfl_init(&pDecomp->m_decomp);
+  pDecomp->m_dict_ofs = 0;
+  pDecomp->m_dict_avail = 0;
+  pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
+  pDecomp->m_first_call = 1;
+  pDecomp->m_has_flushed = 0;
+  pDecomp->m_window_bits = window_bits;
+
+  return MZ_OK;
+}
+
+static int mz_inflate(mz_streamp pStream, int flush)
+{
+  inflate_state* pState;
+  mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
+  size_t in_bytes, out_bytes, orig_avail_in;
+  tinfl_status status;
+
+  if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
+  if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
+  if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
+
+  pState = (inflate_state*)pStream->state;
+  if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
+  orig_avail_in = pStream->avail_in;
+
+  first_call = pState->m_first_call; pState->m_first_call = 0;
+  if (pState->m_last_status < 0) return MZ_DATA_ERROR;
+
+  if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
+  pState->m_has_flushed |= (flush == MZ_FINISH);
+
+  if ((flush == MZ_FINISH) && (first_call))
+  {
+    /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */
+    decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
+    in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
+    status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
+    pState->m_last_status = status;
+    pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
+    pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+    pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
+
+    if (status < 0)
+      return MZ_DATA_ERROR;
+    else if (status != TINFL_STATUS_DONE)
+    {
+      pState->m_last_status = TINFL_STATUS_FAILED;
+      return MZ_BUF_ERROR;
+    }
+    return MZ_STREAM_END;
+  }
+  /* flush != MZ_FINISH then we must assume there's more input. */
+  if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
+
+  if (pState->m_dict_avail)
+  {
+    n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+    memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+    pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
+    pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+    return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+  }
+
+  for ( ; ; )
+  {
+    in_bytes = pStream->avail_in;
+    out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
+
+    status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
+    pState->m_last_status = status;
+
+    pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
+    pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+
+    pState->m_dict_avail = (mz_uint)out_bytes;
+
+    n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+    memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+    pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
+    pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+
+    if (status < 0)
+       return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */
+    else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
+      return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */
+    else if (flush == MZ_FINISH)
+    {
+       /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */
+       if (status == TINFL_STATUS_DONE)
+          return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
+       /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */
+       else if (!pStream->avail_out)
+          return MZ_BUF_ERROR;
+    }
+    else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
+      break;
+  }
+
+  return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+}
+
+static int mz_inflateEnd(mz_streamp pStream)
+{
+  if (!pStream)
+    return MZ_STREAM_ERROR;
+  if (pStream->state)
+  {
+    pStream->zfree(pStream->opaque, pStream->state);
+    pStream->state = NULL;
+  }
+  return MZ_OK;
+}
+
+/* make this a drop-in replacement for zlib... */
+  #define voidpf void*
+  #define uInt unsigned int
+  #define z_stream              mz_stream
+  #define inflateInit2          mz_inflateInit2
+  #define inflate               mz_inflate
+  #define inflateEnd            mz_inflateEnd
+  #define Z_SYNC_FLUSH          MZ_SYNC_FLUSH
+  #define Z_FINISH              MZ_FINISH
+  #define Z_OK                  MZ_OK
+  #define Z_STREAM_END          MZ_STREAM_END
+  #define Z_NEED_DICT           MZ_NEED_DICT
+  #define Z_ERRNO               MZ_ERRNO
+  #define Z_STREAM_ERROR        MZ_STREAM_ERROR
+  #define Z_DATA_ERROR          MZ_DATA_ERROR
+  #define Z_MEM_ERROR           MZ_MEM_ERROR
+  #define Z_BUF_ERROR           MZ_BUF_ERROR
+  #define Z_VERSION_ERROR       MZ_VERSION_ERROR
+  #define MAX_WBITS             15
+
+#endif /* #ifndef TINFL_HEADER_FILE_ONLY */
+
+/* 
+  This is free and unencumbered software released into the public domain.
+
+  Anyone is free to copy, modify, publish, use, compile, sell, or
+  distribute this software, either in source code form or as a compiled
+  binary, for any purpose, commercial or non-commercial, and by any
+  means.
+
+  In jurisdictions that recognize copyright laws, the author or authors
+  of this software dedicate any and all copyright interest in the
+  software to the public domain. We make this dedication for the benefit
+  of the public at large and to the detriment of our heirs and
+  successors. We intend this dedication to be an overt act of
+  relinquishment in perpetuity of all present and future rights to this
+  software under copyright law.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+
+  For more information, please refer to <http://unlicense.org/>
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs_platforms.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,58 @@
+#ifndef _INCL_PHYSFS_PLATFORMS
+#define _INCL_PHYSFS_PLATFORMS
+
+#ifndef __PHYSICSFS_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+/*
+ * These only define the platforms to determine which files in the platforms
+ *  directory should be compiled. For example, technically BeOS can be called
+ *  a "unix" system, but since it doesn't use unix.c, we don't define
+ *  PHYSFS_PLATFORM_UNIX on that system.
+ */
+
+#if (defined __HAIKU__)
+#  define PHYSFS_PLATFORM_HAIKU 1
+#  define PHYSFS_PLATFORM_BEOS 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#elif ((defined __BEOS__) || (defined __beos__))
+#  define PHYSFS_PLATFORM_BEOS 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#elif (defined _WIN32_WCE) || (defined _WIN64_WCE)
+#  error PocketPC support was dropped from PhysicsFS 2.1. Sorry.
+#elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__))
+#  define PHYSFS_PLATFORM_WINDOWS 1
+#elif (defined OS2)
+#  error OS/2 support was dropped from PhysicsFS 2.1. Sorry.
+#elif ((defined __MACH__) && (defined __APPLE__))
+/* To check if iphone or not, we need to include this file */
+#  include <TargetConditionals.h>
+#  if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE))
+#     define PHYSFS_NO_CDROM_SUPPORT 1
+#  endif
+#  define PHYSFS_PLATFORM_MACOSX 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#elif defined(macintosh)
+#  error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X.
+#elif defined(__linux)
+#  define PHYSFS_PLATFORM_LINUX 1
+#  define PHYSFS_PLATFORM_UNIX 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#elif defined(__sun) || defined(sun)
+#  define PHYSFS_PLATFORM_SOLARIS 1
+#  define PHYSFS_PLATFORM_UNIX 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
+#  define PHYSFS_PLATFORM_BSD 1
+#  define PHYSFS_PLATFORM_UNIX 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#elif defined(unix) || defined(__unix__)
+#  define PHYSFS_PLATFORM_UNIX 1
+#  define PHYSFS_PLATFORM_POSIX 1
+#else
+#  error Unknown platform.
+#endif
+
+#endif  /* include-once blocker. */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/physfs_unicode.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,528 @@
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_internal.h"
+
+
+/*
+ * From rfc3629, the UTF-8 spec:
+ *  http://www.ietf.org/rfc/rfc3629.txt
+ *
+ *   Char. number range  |        UTF-8 octet sequence
+ *      (hexadecimal)    |              (binary)
+ *   --------------------+---------------------------------------------
+ *   0000 0000-0000 007F | 0xxxxxxx
+ *   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+ *   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+ *   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ */
+
+
+/*
+ * This may not be the best value, but it's one that isn't represented
+ *  in Unicode (0x10FFFF is the largest codepoint value). We return this
+ *  value from utf8codepoint() if there's bogus bits in the
+ *  stream. utf8codepoint() will turn this value into something
+ *  reasonable (like a question mark), for text that wants to try to recover,
+ *  whereas utf8valid() will use the value to determine if a string has bad
+ *  bits.
+ */
+#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
+
+/*
+ * This is the codepoint we currently return when there was bogus bits in a
+ *  UTF-8 string. May not fly in Asian locales?
+ */
+#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
+
+static PHYSFS_uint32 utf8codepoint(const char **_str)
+{
+    const char *str = *_str;
+    PHYSFS_uint32 retval = 0;
+    PHYSFS_uint32 octet = (PHYSFS_uint32) ((PHYSFS_uint8) *str);
+    PHYSFS_uint32 octet2, octet3, octet4;
+
+    if (octet == 0)  /* null terminator, end of string. */
+        return 0;
+
+    else if (octet < 128)  /* one octet char: 0 to 127 */
+    {
+        (*_str)++;  /* skip to next possible start of codepoint. */
+        return octet;
+    } /* else if */
+
+    else if ((octet > 127) && (octet < 192))  /* bad (starts with 10xxxxxx). */
+    {
+        /*
+         * Apparently each of these is supposed to be flagged as a bogus
+         *  char, instead of just resyncing to the next valid codepoint.
+         */
+        (*_str)++;  /* skip to next possible start of codepoint. */
+        return UNICODE_BOGUS_CHAR_VALUE;
+    } /* else if */
+
+    else if (octet < 224)  /* two octets */
+    {
+        (*_str)++;  /* advance at least one byte in case of an error */
+        octet -= (128+64);
+        octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet2 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 1;  /* skip to next possible start of codepoint. */
+        retval = ((octet << 6) | (octet2 - 128));
+        if ((retval >= 0x80) && (retval <= 0x7FF))
+            return retval;
+    } /* else if */
+
+    else if (octet < 240)  /* three octets */
+    {
+        (*_str)++;  /* advance at least one byte in case of an error */
+        octet -= (128+64+32);
+        octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet2 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet3 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 2;  /* skip to next possible start of codepoint. */
+        retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) );
+
+        /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
+        switch (retval)
+        {
+            case 0xD800:
+            case 0xDB7F:
+            case 0xDB80:
+            case 0xDBFF:
+            case 0xDC00:
+            case 0xDF80:
+            case 0xDFFF:
+                return UNICODE_BOGUS_CHAR_VALUE;
+        } /* switch */
+
+        /* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */
+        if ((retval >= 0x800) && (retval <= 0xFFFD))
+            return retval;
+    } /* else if */
+
+    else if (octet < 248)  /* four octets */
+    {
+        (*_str)++;  /* advance at least one byte in case of an error */
+        octet -= (128+64+32+16);
+        octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet2 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet3 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet4 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet4 & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 3;  /* skip to next possible start of codepoint. */
+        retval = ( ((octet << 18)) | ((octet2 - 128) << 12) |
+                   ((octet3 - 128) << 6) | ((octet4 - 128)) );
+        if ((retval >= 0x10000) && (retval <= 0x10FFFF))
+            return retval;
+    } /* else if */
+
+    /*
+     * Five and six octet sequences became illegal in rfc3629.
+     *  We throw the codepoint away, but parse them to make sure we move
+     *  ahead the right number of bytes and don't overflow the buffer.
+     */
+
+    else if (octet < 252)  /* five octets */
+    {
+        (*_str)++;  /* advance at least one byte in case of an error */
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 4;  /* skip to next possible start of codepoint. */
+        return UNICODE_BOGUS_CHAR_VALUE;
+    } /* else if */
+
+    else  /* six octets */
+    {
+        (*_str)++;  /* advance at least one byte in case of an error */
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str));
+        if ((octet & (128+64)) != 128)  /* Format isn't 10xxxxxx? */
+            return UNICODE_BOGUS_CHAR_VALUE;
+
+        *_str += 6;  /* skip to next possible start of codepoint. */
+        return UNICODE_BOGUS_CHAR_VALUE;
+    } /* else if */
+
+    return UNICODE_BOGUS_CHAR_VALUE;
+} /* utf8codepoint */
+
+
+void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len)
+{
+    len -= sizeof (PHYSFS_uint32);   /* save room for null char. */
+    while (len >= sizeof (PHYSFS_uint32))
+    {
+        PHYSFS_uint32 cp = utf8codepoint(&src);
+        if (cp == 0)
+            break;
+        else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+        *(dst++) = cp;
+        len -= sizeof (PHYSFS_uint32);
+    } /* while */
+
+    *dst = 0;
+} /* PHYSFS_utf8ToUcs4 */
+
+
+void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+{
+    len -= sizeof (PHYSFS_uint16);   /* save room for null char. */
+    while (len >= sizeof (PHYSFS_uint16))
+    {
+        PHYSFS_uint32 cp = utf8codepoint(&src);
+        if (cp == 0)
+            break;
+        else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+        if (cp > 0xFFFF)  /* UTF-16 surrogates (bogus chars in UCS-2) */
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+        *(dst++) = cp;
+        len -= sizeof (PHYSFS_uint16);
+    } /* while */
+
+    *dst = 0;
+} /* PHYSFS_utf8ToUcs2 */
+
+
+void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len)
+{
+    len -= sizeof (PHYSFS_uint16);   /* save room for null char. */
+    while (len >= sizeof (PHYSFS_uint16))
+    {
+        PHYSFS_uint32 cp = utf8codepoint(&src);
+        if (cp == 0)
+            break;
+        else if (cp == UNICODE_BOGUS_CHAR_VALUE)
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+
+        if (cp > 0xFFFF)  /* encode as surrogate pair */
+        {
+            if (len < (sizeof (PHYSFS_uint16) * 2))
+                break;  /* not enough room for the pair, stop now. */
+
+            cp -= 0x10000;  /* Make this a 20-bit value */
+
+            *(dst++) = 0xD800 + ((cp >> 10) & 0x3FF);
+            len -= sizeof (PHYSFS_uint16);
+
+            cp = 0xDC00 + (cp & 0x3FF);
+        } /* if */
+
+        *(dst++) = cp;
+        len -= sizeof (PHYSFS_uint16);
+    } /* while */
+
+    *dst = 0;
+} /* PHYSFS_utf8ToUtf16 */
+
+static void utf8fromcodepoint(PHYSFS_uint32 cp, char **_dst, PHYSFS_uint64 *_len)
+{
+    char *dst = *_dst;
+    PHYSFS_uint64 len = *_len;
+
+    if (len == 0)
+        return;
+
+    if (cp > 0x10FFFF)
+        cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+    else if ((cp == 0xFFFE) || (cp == 0xFFFF))  /* illegal values. */
+        cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+    else
+    {
+        /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */
+        switch (cp)
+        {
+            case 0xD800:
+            case 0xDB7F:
+            case 0xDB80:
+            case 0xDBFF:
+            case 0xDC00:
+            case 0xDF80:
+            case 0xDFFF:
+                cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+        } /* switch */
+    } /* else */
+
+    /* Do the encoding... */
+    if (cp < 0x80)
+    {
+        *(dst++) = (char) cp;
+        len--;
+    } /* if */
+
+    else if (cp < 0x800)
+    {
+        if (len < 2)
+            len = 0;
+        else
+        {
+            *(dst++) = (char) ((cp >> 6) | 128 | 64);
+            *(dst++) = (char) (cp & 0x3F) | 128;
+            len -= 2;
+        } /* else */
+    } /* else if */
+
+    else if (cp < 0x10000)
+    {
+        if (len < 3)
+            len = 0;
+        else
+        {
+            *(dst++) = (char) ((cp >> 12) | 128 | 64 | 32);
+            *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
+            *(dst++) = (char) (cp & 0x3F) | 128;
+            len -= 3;
+        } /* else */
+    } /* else if */
+
+    else
+    {
+        if (len < 4)
+            len = 0;
+        else
+        {
+            *(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16);
+            *(dst++) = (char) ((cp >> 12) & 0x3F) | 128;
+            *(dst++) = (char) ((cp >> 6) & 0x3F) | 128;
+            *(dst++) = (char) (cp & 0x3F) | 128;
+            len -= 4;
+        } /* else if */
+    } /* else */
+
+    *_dst = dst;
+    *_len = len;
+} /* utf8fromcodepoint */
+
+#define UTF8FROMTYPE(typ, src, dst, len) \
+    if (len == 0) return; \
+    len--;  \
+    while (len) \
+    { \
+        const PHYSFS_uint32 cp = (PHYSFS_uint32) ((typ) (*(src++))); \
+        if (cp == 0) break; \
+        utf8fromcodepoint(cp, &dst, &len); \
+    } \
+    *dst = '\0'; \
+
+void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint32, src, dst, len);
+} /* PHYSFS_utf8FromUcs4 */
+
+void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint64, src, dst, len);
+} /* PHYSFS_utf8FromUcs2 */
+
+/* latin1 maps to unicode codepoints directly, we just utf-8 encode it. */
+void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len)
+{
+    UTF8FROMTYPE(PHYSFS_uint8, src, dst, len);
+} /* PHYSFS_utf8FromLatin1 */
+
+#undef UTF8FROMTYPE
+
+
+void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len)
+{
+    if (len == 0)
+        return;
+
+    len--;
+    while (len)
+    {
+        PHYSFS_uint32 cp = (PHYSFS_uint32) *(src++);
+        if (cp == 0)
+            break;
+
+        /* Orphaned second half of surrogate pair? */
+        if ((cp >= 0xDC00) && (cp <= 0xDFFF))
+            cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+        else if ((cp >= 0xD800) && (cp <= 0xDBFF))  /* start surrogate pair! */
+        {
+            const PHYSFS_uint32 pair = (PHYSFS_uint32) *src;
+            if ((pair < 0xDC00) || (pair > 0xDFFF))
+                cp = UNICODE_BOGUS_CHAR_CODEPOINT;
+            else
+            {
+                src++;  /* eat the other surrogate. */
+                cp = (((cp - 0xD800) << 10) | (pair - 0xDC00));
+            } /* else */
+        } /* else if */
+
+        utf8fromcodepoint(cp, &dst, &len);
+    } /* while */
+
+    *dst = '\0';
+} /* PHYSFS_utf8FromUtf16 */
+
+
+typedef struct CaseFoldMapping
+{
+    PHYSFS_uint32 from;
+    PHYSFS_uint32 to0;
+    PHYSFS_uint32 to1;
+    PHYSFS_uint32 to2;
+} CaseFoldMapping;
+
+typedef struct CaseFoldHashBucket
+{
+    const PHYSFS_uint8 count;
+    const CaseFoldMapping *list;
+} CaseFoldHashBucket;
+
+#include "physfs_casefolding.h"
+
+static void locate_case_fold_mapping(const PHYSFS_uint32 from,
+                                     PHYSFS_uint32 *to)
+{
+    PHYSFS_uint32 i;
+    const PHYSFS_uint8 hashed = ((from ^ (from >> 8)) & 0xFF);
+    const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
+    const CaseFoldMapping *mapping = bucket->list;
+
+    for (i = 0; i < bucket->count; i++, mapping++)
+    {
+        if (mapping->from == from)
+        {
+            to[0] = mapping->to0;
+            to[1] = mapping->to1;
+            to[2] = mapping->to2;
+            return;
+        } /* if */
+    } /* for */
+
+    /* Not found...there's no remapping for this codepoint. */
+    to[0] = from;
+    to[1] = 0;
+    to[2] = 0;
+} /* locate_case_fold_mapping */
+
+
+static int utf8codepointcmp(const PHYSFS_uint32 cp1, const PHYSFS_uint32 cp2)
+{
+    PHYSFS_uint32 folded1[3], folded2[3];
+    locate_case_fold_mapping(cp1, folded1);
+    locate_case_fold_mapping(cp2, folded2);
+    return ( (folded1[0] == folded2[0]) &&
+             (folded1[1] == folded2[1]) &&
+             (folded1[2] == folded2[2]) );
+} /* utf8codepointcmp */
+
+
+int __PHYSFS_utf8stricmp(const char *str1, const char *str2)
+{
+    while (1)
+    {
+        const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
+        const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
+        if (!utf8codepointcmp(cp1, cp2)) break;
+        if (cp1 == 0) return 1;
+    } /* while */
+
+    return 0;
+} /* __PHYSFS_utf8stricmp */
+
+
+int __PHYSFS_utf8strnicmp(const char *str1, const char *str2, PHYSFS_uint32 n)
+{
+    while (n > 0)
+    {
+        const PHYSFS_uint32 cp1 = utf8codepoint(&str1);
+        const PHYSFS_uint32 cp2 = utf8codepoint(&str2);
+        if (!utf8codepointcmp(cp1, cp2)) return 0;
+        if (cp1 == 0) return 1;
+        n--;
+    } /* while */
+
+    return 1;  /* matched to n chars. */
+} /* __PHYSFS_utf8strnicmp */
+
+
+int __PHYSFS_stricmpASCII(const char *str1, const char *str2)
+{
+    while (1)
+    {
+        const char ch1 = *(str1++);
+        const char ch2 = *(str2++);
+        const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
+        const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
+        if (cp1 < cp2)
+            return -1;
+        else if (cp1 > cp2)
+            return 1;
+        else if (cp1 == 0)  /* they're both null chars? */
+            break;
+    } /* while */
+
+    return 0;
+} /* __PHYSFS_stricmpASCII */
+
+
+int __PHYSFS_strnicmpASCII(const char *str1, const char *str2, PHYSFS_uint32 n)
+{
+    while (n-- > 0)
+    {
+        const char ch1 = *(str1++);
+        const char ch2 = *(str2++);
+        const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1;
+        const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2;
+        if (cp1 < cp2)
+            return -1;
+        else if (cp1 > cp2)
+            return 1;
+        else if (cp1 == 0)  /* they're both null chars? */
+            return 0;
+    } /* while */
+
+    return 0;
+} /* __PHYSFS_strnicmpASCII */
+
+
+/* end of physfs_unicode.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/platform_beos.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,239 @@
+/*
+ * BeOS platform-dependent support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_BEOS
+
+#ifdef PHYSFS_PLATFORM_HAIKU
+#include <os/kernel/OS.h>
+#include <os/app/Roster.h>
+#include <os/storage/Volume.h>
+#include <os/storage/VolumeRoster.h>
+#include <os/storage/Directory.h>
+#include <os/storage/Entry.h>
+#include <os/storage/Path.h>
+#include <os/kernel/fs_info.h>
+#include <os/device/scsi.h>
+#include <os/support/Locker.h>
+#else
+#include <be/kernel/OS.h>
+#include <be/app/Roster.h>
+#include <be/storage/Volume.h>
+#include <be/storage/VolumeRoster.h>
+#include <be/storage/Directory.h>
+#include <be/storage/Entry.h>
+#include <be/storage/Path.h>
+#include <be/kernel/fs_info.h>
+#include <be/device/scsi.h>
+#include <be/support/Locker.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "physfs_internal.h"
+
+int __PHYSFS_platformInit(void)
+{
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+static char *getMountPoint(const char *devname, char *buf, size_t bufsize)
+{
+    BVolumeRoster mounts;
+    BVolume vol;
+
+    mounts.Rewind();
+    while (mounts.GetNextVolume(&vol) == B_NO_ERROR)
+    {
+        fs_info fsinfo;
+        fs_stat_dev(vol.Device(), &fsinfo);
+        if (strcmp(devname, fsinfo.device_name) == 0)
+        {
+            BDirectory directory;
+            BEntry entry;
+            BPath path;
+            const char *str;
+
+            if ( (vol.GetRootDirectory(&directory) < B_OK) ||
+                 (directory.GetEntry(&entry) < B_OK) ||
+                 (entry.GetPath(&path) < B_OK) ||
+                 ( (str = path.Path()) == NULL) )
+                return NULL;
+
+            strncpy(buf, str, bufsize-1);
+            buf[bufsize-1] = '\0';
+            return buf;
+        } /* if */
+    } /* while */
+
+    return NULL;
+} /* getMountPoint */
+
+
+    /*
+     * This function is lifted from Simple Directmedia Layer (SDL):
+     *  http://www.libsdl.org/  ... this is zlib-licensed code, too.
+     */
+static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
+{
+    BDirectory dir;
+    dir.SetTo(d);
+    if (dir.InitCheck() != B_NO_ERROR)
+        return;
+
+    dir.Rewind();
+    BEntry entry;
+    while (dir.GetNextEntry(&entry) >= 0)
+    {
+        BPath path;
+        const char *name;
+        entry_ref e;
+
+        if (entry.GetPath(&path) != B_NO_ERROR)
+            continue;
+
+        name = path.Path();
+
+        if (entry.GetRef(&e) != B_NO_ERROR)
+            continue;
+
+        if (entry.IsDirectory())
+        {
+            if (strcmp(e.name, "floppy") != 0)
+                tryDir(name, callback, data);
+            continue;
+        } /* if */
+
+        if (strcmp(e.name, "raw") != 0)  /* ignore partitions. */
+            continue;
+
+        const int devfd = open(name, O_RDONLY);
+        if (devfd < 0)
+            continue;
+
+        device_geometry g;
+        const int rc = ioctl(devfd, B_GET_GEOMETRY, &g, sizeof (g));
+        close(devfd);
+        if (rc < 0)
+            continue;
+
+        if (g.device_type != B_CD)
+            continue;
+
+        char mntpnt[B_FILE_NAME_LENGTH];
+        if (getMountPoint(name, mntpnt, sizeof (mntpnt)))
+            callback(data, mntpnt);
+    } /* while */
+} /* tryDir */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    tryDir("/dev/disk", cb, data);
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static team_id getTeamID(void)
+{
+    thread_info info;
+    thread_id tid = find_thread(NULL);
+    get_thread_info(tid, &info);
+    return info.team;
+} /* getTeamID */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    image_info info;
+    int32 cookie = 0;
+
+    while (get_next_image_info(0, &cookie, &info) == B_OK)
+    {
+        if (info.type == B_APP_IMAGE)
+            break;
+    } /* while */
+
+    BEntry entry(info.name, true);
+    BPath path;
+    status_t rc = entry.GetPath(&path);  /* (path) now has binary's path. */
+    assert(rc == B_OK);
+    rc = path.GetParent(&path); /* chop filename, keep directory. */
+    assert(rc == B_OK);
+    const char *str = path.Path();
+    assert(str != NULL);
+    const size_t len = strlen(str);
+    char *retval = (char *) allocator.Malloc(len + 2);
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    strcpy(retval, str);
+    retval[len] = '/';
+    retval[len+1] = '\0';
+    return retval;
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+    const char *userdir = __PHYSFS_getUserDir();
+    const char *append = "config/settings/";
+    const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
+    char *retval = allocator.Malloc(len);
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    snprintf(retval, len, "%s%s%s/", userdir, append, app);
+    return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+    return (void *) find_thread(NULL);
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    return new BLocker("PhysicsFS lock", true);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    delete ((BLocker *) mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    return ((BLocker *) mutex)->Lock() ? 1 : 0;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    ((BLocker *) mutex)->Unlock();
+} /* __PHYSFS_platformReleaseMutex */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return 0;  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_BEOS */
+
+/* end of beos.cpp ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/platform_macosx.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,326 @@
+/*
+ * Mac OS X support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_MACOSX
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#if !defined(PHYSFS_NO_CDROM_SUPPORT)
+#include <Carbon/Carbon.h>  /* !!! FIXME */
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IODVDMedia.h>
+#include <sys/mount.h>
+#endif
+
+/* Seems to get defined in some system header... */
+#ifdef Free
+#undef Free
+#endif
+
+#include "physfs_internal.h"
+
+
+/* Wrap PHYSFS_Allocator in a CFAllocator... */
+static CFAllocatorRef cfallocator = NULL;
+
+static CFStringRef cfallocDesc(const void *info)
+{
+    return CFStringCreateWithCString(cfallocator, "PhysicsFS",
+                                     kCFStringEncodingASCII);
+} /* cfallocDesc */
+
+
+static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
+{
+    return allocator.Malloc(allocSize);
+} /* cfallocMalloc */
+
+
+static void cfallocFree(void *ptr, void *info)
+{
+    allocator.Free(ptr);
+} /* cfallocFree */
+
+
+static void *cfallocRealloc(void *ptr, CFIndex newsize,
+                            CFOptionFlags hint, void *info)
+{
+    if ((ptr == NULL) || (newsize <= 0))
+        return NULL;  /* ADC docs say you should always return NULL here. */
+    return allocator.Realloc(ptr, newsize);
+} /* cfallocRealloc */
+
+
+int __PHYSFS_platformInit(void)
+{
+    /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */
+    CFAllocatorContext ctx;
+    memset(&ctx, '\0', sizeof (ctx));
+    ctx.copyDescription = cfallocDesc;
+    ctx.allocate = cfallocMalloc;
+    ctx.reallocate = cfallocRealloc;
+    ctx.deallocate = cfallocFree;
+    cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx);
+    BAIL_IF_MACRO(!cfallocator, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    return 1;  /* success. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    CFRelease(cfallocator);
+    cfallocator = NULL;
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+
+/* CD-ROM detection code... */
+
+/*
+ * Code based on sample from Apple Developer Connection:
+ *  http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
+ */
+
+#if !defined(PHYSFS_NO_CDROM_SUPPORT)
+
+static int darwinIsWholeMedia(io_service_t service)
+{
+    int retval = 0;
+    CFTypeRef wholeMedia;
+
+    if (!IOObjectConformsTo(service, kIOMediaClass))
+        return 0;
+        
+    wholeMedia = IORegistryEntryCreateCFProperty(service,
+                                                 CFSTR(kIOMediaWholeKey),
+                                                 cfallocator, 0);
+    if (wholeMedia == NULL)
+        return 0;
+
+    retval = CFBooleanGetValue(wholeMedia);
+    CFRelease(wholeMedia);
+
+    return retval;
+} /* darwinIsWholeMedia */
+
+
+static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
+{
+    int retval = 0;
+    CFMutableDictionaryRef matchingDict;
+    kern_return_t rc;
+    io_iterator_t iter;
+    io_service_t service;
+
+    if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
+        return 0;
+
+    rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
+    if ((rc != KERN_SUCCESS) || (!iter))
+        return 0;
+
+    service = IOIteratorNext(iter);
+    IOObjectRelease(iter);
+    if (!service)
+        return 0;
+
+    rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
+             kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
+    
+    if (!iter)
+        return 0;
+
+    if (rc != KERN_SUCCESS)
+    {
+        IOObjectRelease(iter);
+        return 0;
+    } /* if */
+
+    IOObjectRetain(service);  /* add an extra object reference... */
+
+    do
+    {
+        if (darwinIsWholeMedia(service))
+        {
+            if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
+                 (IOObjectConformsTo(service, kIODVDMediaClass)) )
+            {
+                retval = 1;
+            } /* if */
+        } /* if */
+        IOObjectRelease(service);
+    } while ((service = IOIteratorNext(iter)) && (!retval));
+                
+    IOObjectRelease(iter);
+    IOObjectRelease(service);
+
+    return retval;
+} /* darwinIsMountedDisc */
+
+#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+#if !defined(PHYSFS_NO_CDROM_SUPPORT)
+    const char *devPrefix = "/dev/";
+    const int prefixLen = strlen(devPrefix);
+    mach_port_t masterPort = 0;
+    struct statfs *mntbufp;
+    int i, mounts;
+
+    if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
+        BAIL_MACRO(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
+
+    mounts = getmntinfo(&mntbufp, MNT_WAIT);  /* NOT THREAD SAFE! */
+    for (i = 0; i < mounts; i++)
+    {
+        char *dev = mntbufp[i].f_mntfromname;
+        char *mnt = mntbufp[i].f_mntonname;
+        if (strncmp(dev, devPrefix, prefixLen) != 0)  /* a virtual device? */
+            continue;
+
+        dev += prefixLen;
+        if (darwinIsMountedDisc(dev, masterPort))
+            cb(data, mnt);
+    } /* for */
+#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+static char *convertCFString(CFStringRef cfstr)
+{
+    CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
+                                                    kCFStringEncodingUTF8) + 1;
+    char *retval = (char *) allocator.Malloc(len);
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+
+    if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
+    {
+        /* shrink overallocated buffer if possible... */
+        CFIndex newlen = strlen(retval) + 1;
+        if (newlen < len)
+        {
+            void *ptr = allocator.Realloc(retval, newlen);
+            if (ptr != NULL)
+                retval = (char *) ptr;
+        } /* if */
+    } /* if */
+
+    else  /* probably shouldn't fail, but just in case... */
+    {
+        allocator.Free(retval);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    } /* else */
+
+    return retval;
+} /* convertCFString */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    CFURLRef cfurl = NULL;
+    CFStringRef cfstr = NULL;
+    CFMutableStringRef cfmutstr = NULL;
+    char *retval = NULL;
+
+    cfurl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+    BAIL_IF_MACRO(cfurl == NULL, PHYSFS_ERR_OS_ERROR, NULL);
+    cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
+    CFRelease(cfurl);
+    BAIL_IF_MACRO(!cfstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr);
+    CFRelease(cfstr);
+    BAIL_IF_MACRO(!cfmutstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    CFStringAppendCString(cfmutstr, "/", kCFStringEncodingUTF8);
+    retval = convertCFString(cfmutstr);
+    CFRelease(cfmutstr);
+
+    return retval;  /* whew. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+    /* !!! FIXME: there's a real API to determine this */
+    const char *userdir = __PHYSFS_getUserDir();
+    const char *append = "Library/Application Support/";
+    const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
+    char *retval = allocator.Malloc(len);
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    snprintf(retval, len, "%s%s%s/", userdir, append, app);
+    return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */
+
+static CFAllocatorRef cfallocdef = NULL;
+
+static int macosxAllocatorInit(void)
+{
+    int retval = 0;
+    cfallocdef = CFAllocatorGetDefault();
+    retval = (cfallocdef != NULL);
+    if (retval)
+        CFRetain(cfallocdef);
+    return retval;
+} /* macosxAllocatorInit */
+
+
+static void macosxAllocatorDeinit(void)
+{
+    if (cfallocdef != NULL)
+    {
+        CFRelease(cfallocdef);
+        cfallocdef = NULL;
+    } /* if */
+} /* macosxAllocatorDeinit */
+
+
+static void *macosxAllocatorMalloc(PHYSFS_uint64 s)
+{
+    if (!__PHYSFS_ui64FitsAddressSpace(s))
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    return CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0);
+} /* macosxAllocatorMalloc */
+
+
+static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
+{
+    if (!__PHYSFS_ui64FitsAddressSpace(s))
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    return CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0);
+} /* macosxAllocatorRealloc */
+
+
+static void macosxAllocatorFree(void *ptr)
+{
+    CFAllocatorDeallocate(cfallocdef, ptr);
+} /* macosxAllocatorFree */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    allocator.Init = macosxAllocatorInit;
+    allocator.Deinit = macosxAllocatorDeinit;
+    allocator.Malloc = macosxAllocatorMalloc;
+    allocator.Realloc = macosxAllocatorRealloc;
+    allocator.Free = macosxAllocatorFree;
+    return 1;  /* return non-zero: we're supplying custom allocator. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif /* PHYSFS_PLATFORM_MACOSX */
+
+/* end of macosx.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/platform_posix.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,479 @@
+/*
+ * Posix-esque support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+/* !!! FIXME: check for EINTR? */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_POSIX
+
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#if ((!defined PHYSFS_NO_THREAD_SUPPORT) && (!defined PHYSFS_PLATFORM_BEOS))
+#include <pthread.h>
+#endif
+
+#include "physfs_internal.h"
+
+
+static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
+{
+    switch (err)
+    {
+        case 0: return PHYSFS_ERR_OK;
+        case EACCES: return PHYSFS_ERR_PERMISSION;
+        case EPERM: return PHYSFS_ERR_PERMISSION;
+        case EDQUOT: return PHYSFS_ERR_NO_SPACE;
+        case EIO: return PHYSFS_ERR_IO;
+        case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
+        case EMLINK: return PHYSFS_ERR_NO_SPACE;
+        case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME;
+        case ENOENT: return PHYSFS_ERR_NO_SUCH_PATH;
+        case ENOSPC: return PHYSFS_ERR_NO_SPACE;
+        case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH;
+        case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
+        case EROFS: return PHYSFS_ERR_READ_ONLY;
+        case ETXTBSY: return PHYSFS_ERR_BUSY;
+        case EBUSY: return PHYSFS_ERR_BUSY;
+        case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
+        case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
+        default: return PHYSFS_ERR_OS_ERROR;
+    } /* switch */
+} /* errcodeFromErrnoError */
+
+
+static inline PHYSFS_ErrorCode errcodeFromErrno(void)
+{
+    return errcodeFromErrnoError(errno);
+} /* errcodeFromErrno */
+
+
+static char *getUserDirByUID(void)
+{
+    uid_t uid = getuid();
+    struct passwd *pw;
+    char *retval = NULL;
+
+    pw = getpwuid(uid);
+    if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0'))
+    {
+        const size_t dlen = strlen(pw->pw_dir);
+        const size_t add_dirsep = (pw->pw_dir[dlen-1] != '/') ? 1 : 0;
+        retval = (char *) allocator.Malloc(dlen + 1 + add_dirsep);
+        if (retval != NULL)
+        {
+            strcpy(retval, pw->pw_dir);
+            if (add_dirsep)
+            {
+                retval[dlen] = '/';
+                retval[dlen+1] = '\0';
+            } /* if */
+        } /* if */
+    } /* if */
+    
+    return retval;
+} /* getUserDirByUID */
+
+
+char *__PHYSFS_platformCalcUserDir(void)
+{
+    char *retval = NULL;
+    char *envr = getenv("HOME");
+
+    /* if the environment variable was set, make sure it's really a dir. */
+    if (envr != NULL)
+    {
+        struct stat statbuf;
+        if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode)))
+        {
+            const size_t envrlen = strlen(envr);
+            const size_t add_dirsep = (envr[envrlen-1] != '/') ? 1 : 0;
+            retval = allocator.Malloc(envrlen + 1 + add_dirsep);
+            if (retval)
+            {
+                strcpy(retval, envr);
+                if (add_dirsep)
+                {
+                    retval[envrlen] = '/';
+                    retval[envrlen+1] = '\0';
+                } /* if */
+            } /* if */
+        } /* if */
+    } /* if */
+
+    if (retval == NULL)
+        retval = getUserDirByUID();
+
+    return retval;
+} /* __PHYSFS_platformCalcUserDir */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    DIR *dir;
+    struct dirent *ent;
+    int bufsize = 0;
+    char *buf = NULL;
+    int dlen = 0;
+
+    if (omitSymLinks)  /* !!! FIXME: this malloc sucks. */
+    {
+        dlen = strlen(dirname);
+        bufsize = dlen + 256;
+        buf = (char *) allocator.Malloc(bufsize);
+        if (buf == NULL)
+            return;
+        strcpy(buf, dirname);
+        if (buf[dlen - 1] != '/')
+        {
+            buf[dlen++] = '/';
+            buf[dlen] = '\0';
+        } /* if */
+    } /* if */
+
+    errno = 0;
+    dir = opendir(dirname);
+    if (dir == NULL)
+    {
+        allocator.Free(buf);
+        return;
+    } /* if */
+
+    while ((ent = readdir(dir)) != NULL)
+    {
+        if (strcmp(ent->d_name, ".") == 0)
+            continue;
+
+        if (strcmp(ent->d_name, "..") == 0)
+            continue;
+
+        if (omitSymLinks)
+        {
+            PHYSFS_Stat statbuf;
+            int exists = 0;
+            char *p;
+            int len = strlen(ent->d_name) + dlen + 1;
+            if (len > bufsize)
+            {
+                p = (char *) allocator.Realloc(buf, len);
+                if (p == NULL)
+                    continue;
+                buf = p;
+                bufsize = len;
+            } /* if */
+
+            strcpy(buf + dlen, ent->d_name);
+
+            if (!__PHYSFS_platformStat(buf, &exists, &statbuf))
+                continue;
+            else if (!exists)
+                continue;  /* probably can't happen, but just in case. */
+            else if (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK)
+                continue;
+        } /* if */
+
+        callback(callbackdata, origdir, ent->d_name);
+    } /* while */
+
+    allocator.Free(buf);
+    closedir(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    const int rc = mkdir(path, S_IRWXU);
+    BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
+    return 1;
+} /* __PHYSFS_platformMkDir */
+
+
+static void *doOpen(const char *filename, int mode)
+{
+    const int appending = (mode & O_APPEND);
+    int fd;
+    int *retval;
+    errno = 0;
+
+    /* O_APPEND doesn't actually behave as we'd like. */
+    mode &= ~O_APPEND;
+
+    fd = open(filename, mode, S_IRUSR | S_IWUSR);
+    BAIL_IF_MACRO(fd < 0, errcodeFromErrno(), NULL);
+
+    if (appending)
+    {
+        if (lseek(fd, 0, SEEK_END) < 0)
+        {
+            const int err = errno;
+            close(fd);
+            BAIL_MACRO(errcodeFromErrnoError(err), NULL);
+        } /* if */
+    } /* if */
+
+    retval = (int *) allocator.Malloc(sizeof (int));
+    if (!retval)
+    {
+        close(fd);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    *retval = fd;
+    return ((void *) retval);
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    return doOpen(filename, O_RDONLY);
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
+                                    PHYSFS_uint64 len)
+{
+    const int fd = *((int *) opaque);
+    ssize_t rc = 0;
+
+    if (!__PHYSFS_ui64FitsAddressSpace(len))
+        BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+    rc = read(fd, buffer, (size_t) len);
+    BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), -1);
+    assert(rc >= 0);
+    assert(rc <= len);
+    return (PHYSFS_sint64) rc;
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint64 len)
+{
+    const int fd = *((int *) opaque);
+    ssize_t rc = 0;
+
+    if (!__PHYSFS_ui64FitsAddressSpace(len))
+        BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+    rc = write(fd, (void *) buffer, (size_t) len);
+    BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), rc);
+    assert(rc >= 0);
+    assert(rc <= len);
+    return (PHYSFS_sint64) rc;
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    const int fd = *((int *) opaque);
+    const int rc = lseek(fd, (off_t) pos, SEEK_SET);
+    BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
+    return 1;
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    const int fd = *((int *) opaque);
+    PHYSFS_sint64 retval;
+    retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
+    BAIL_IF_MACRO(retval == -1, errcodeFromErrno(), -1);
+    return retval;
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    const int fd = *((int *) opaque);
+    struct stat statbuf;
+    BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
+    return ((PHYSFS_sint64) statbuf.st_size);
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    const int fd = *((int *) opaque);
+    BAIL_IF_MACRO(fsync(fd) == -1, errcodeFromErrno(), 0);
+    return 1;
+} /* __PHYSFS_platformFlush */
+
+
+void __PHYSFS_platformClose(void *opaque)
+{
+    const int fd = *((int *) opaque);
+    (void) close(fd);  /* we don't check this. You should have used flush! */
+    allocator.Free(opaque);
+} /* __PHYSFS_platformClose */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    BAIL_IF_MACRO(remove(path) == -1, errcodeFromErrno(), 0);
+    return 1;
+} /* __PHYSFS_platformDelete */
+
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *st)
+{
+    struct stat statbuf;
+
+    if (lstat(filename, &statbuf) == -1)
+    {
+        *exists = (errno != ENOENT);
+        BAIL_MACRO(errcodeFromErrno(), 0);
+    } /* if */
+
+    *exists = 1;
+
+    if (S_ISREG(statbuf.st_mode))
+    {
+        st->filetype = PHYSFS_FILETYPE_REGULAR;
+        st->filesize = statbuf.st_size;
+    } /* if */
+
+    else if(S_ISDIR(statbuf.st_mode))
+    {
+        st->filetype = PHYSFS_FILETYPE_DIRECTORY;
+        st->filesize = 0;
+    } /* else if */
+
+    else
+    {
+        st->filetype = PHYSFS_FILETYPE_OTHER;
+        st->filesize = statbuf.st_size;
+    } /* else */
+
+    st->modtime = statbuf.st_mtime;
+    st->createtime = statbuf.st_ctime;
+    st->accesstime = statbuf.st_atime;
+
+    /* !!! FIXME: maybe we should just report full permissions? */
+    st->readonly = access(filename, W_OK);
+    return 1;
+} /* __PHYSFS_platformStat */
+
+
+#ifndef PHYSFS_PLATFORM_BEOS  /* BeOS has its own code in platform_beos.cpp */
+#if (defined PHYSFS_NO_THREAD_SUPPORT)
+
+void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
+void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
+void __PHYSFS_platformDestroyMutex(void *mutex) {}
+int __PHYSFS_platformGrabMutex(void *mutex) { return 1; }
+void __PHYSFS_platformReleaseMutex(void *mutex) {}
+
+#else
+
+typedef struct
+{
+    pthread_mutex_t mutex;
+    pthread_t owner;
+    PHYSFS_uint32 count;
+} PthreadMutex;
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+    return ( (void *) ((size_t) pthread_self()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    int rc;
+    PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
+    BAIL_IF_MACRO(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    rc = pthread_mutex_init(&m->mutex, NULL);
+    if (rc != 0)
+    {
+        allocator.Free(m);
+        BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
+    } /* if */
+
+    m->count = 0;
+    m->owner = (pthread_t) 0xDEADBEEF;
+    return ((void *) m);
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    PthreadMutex *m = (PthreadMutex *) mutex;
+
+    /* Destroying a locked mutex is a bug, but we'll try to be helpful. */
+    if ((m->owner == pthread_self()) && (m->count > 0))
+        pthread_mutex_unlock(&m->mutex);
+
+    pthread_mutex_destroy(&m->mutex);
+    allocator.Free(m);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    PthreadMutex *m = (PthreadMutex *) mutex;
+    pthread_t tid = pthread_self();
+    if (m->owner != tid)
+    {
+        if (pthread_mutex_lock(&m->mutex) != 0)
+            return 0;
+        m->owner = tid;
+    } /* if */
+
+    m->count++;
+    return 1;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    PthreadMutex *m = (PthreadMutex *) mutex;
+    assert(m->owner == pthread_self());  /* catch programming errors. */
+    assert(m->count > 0);  /* catch programming errors. */
+    if (m->owner == pthread_self())
+    {
+        if (--m->count == 0)
+        {
+            m->owner = (pthread_t) 0xDEADBEEF;
+            pthread_mutex_unlock(&m->mutex);
+        } /* if */
+    } /* if */
+} /* __PHYSFS_platformReleaseMutex */
+
+#endif /* !PHYSFS_NO_THREAD_SUPPORT */
+#endif /* !PHYSFS_PLATFORM_BEOS */
+
+#endif  /* PHYSFS_PLATFORM_POSIX */
+
+/* end of posix.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/platform_unix.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,344 @@
+/*
+ * Unix support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_UNIX
+
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <time.h>
+#include <errno.h>
+
+#if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H)
+#define PHYSFS_HAVE_MNTENT_H 1
+#elif PHYSFS_PLATFORM_SOLARIS && !defined(PHYSFS_HAVE_SYS_MNTTAB_H)
+#define PHYSFS_HAVE_SYS_MNTTAB_H 1
+#elif PHYSFS_PLATFORM_BSD && !defined(PHYSFS_HAVE_SYS_UCRED_H)
+#define PHYSFS_HAVE_SYS_UCRED_H 1
+#endif
+
+#ifdef PHYSFS_HAVE_SYS_UCRED_H
+#  ifdef PHYSFS_HAVE_MNTENT_H
+#    undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
+#  endif
+#  include <sys/mount.h>
+#  include <sys/ucred.h>
+#endif
+
+#ifdef PHYSFS_HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#ifdef PHYSFS_HAVE_SYS_MNTTAB_H
+#include <sys/mnttab.h>
+#endif
+
+#include "physfs_internal.h"
+
+int __PHYSFS_platformInit(void)
+{
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformDeinit */
+
+
+/* Stub version for platforms without CD-ROM support. */
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+#if (defined PHYSFS_NO_CDROM_SUPPORT)
+    /* no-op. */
+
+#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
+    int i;
+    struct statfs *mntbufp = NULL;
+    int mounts = getmntinfo(&mntbufp, MNT_WAIT);
+
+    for (i = 0; i < mounts; i++)
+    {
+        int add_it = 0;
+
+        if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
+            add_it = 1;
+        else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
+            add_it = 1;
+
+        /* add other mount types here */
+
+        if (add_it)
+            cb(data, mntbufp[i].f_mntonname);
+    } /* for */
+
+#elif (defined PHYSFS_HAVE_MNTENT_H)
+    FILE *mounts = NULL;
+    struct mntent *ent = NULL;
+
+    mounts = setmntent("/etc/mtab", "r");
+    BAIL_IF_MACRO(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
+
+    while ( (ent = getmntent(mounts)) != NULL )
+    {
+        int add_it = 0;
+        if (strcmp(ent->mnt_type, "iso9660") == 0)
+            add_it = 1;
+        else if (strcmp(ent->mnt_type, "udf") == 0)
+            add_it = 1;
+
+        /* !!! FIXME: these might pick up floppy drives, right? */
+        else if (strcmp(ent->mnt_type, "auto") == 0)
+            add_it = 1;
+        else if (strcmp(ent->mnt_type, "supermount") == 0)
+            add_it = 1;
+
+        /* !!! FIXME: udf? automount? */
+
+        /* add other mount types here */
+
+        if (add_it)
+            cb(data, ent->mnt_dir);
+    } /* while */
+
+    endmntent(mounts);
+
+#elif (defined PHYSFS_HAVE_SYS_MNTTAB_H)
+    FILE *mounts = fopen(MNTTAB, "r");
+    struct mnttab ent;
+
+    BAIL_IF_MACRO(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
+    while (getmntent(mounts, &ent) == 0)
+    {
+        int add_it = 0;
+        if (strcmp(ent.mnt_fstype, "hsfs") == 0)
+            add_it = 1;
+
+        /* add other mount types here */
+
+        if (add_it)
+            cb(data, ent.mnt_mountp);
+    } /* while */
+
+    fclose(mounts);
+
+#else
+#error Unknown platform. Should have defined PHYSFS_NO_CDROM_SUPPORT, perhaps.
+#endif
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+/*
+ * See where program (bin) resides in the $PATH specified by (envr).
+ *  returns a copy of the first element in envr that contains it, or NULL
+ *  if it doesn't exist or there were other problems. PHYSFS_SetError() is
+ *  called if we have a problem.
+ *
+ * (envr) will be scribbled over, and you are expected to allocator.Free() the
+ *  return value when you're done with it.
+ */
+static char *findBinaryInPath(const char *bin, char *envr)
+{
+    size_t alloc_size = 0;
+    char *exe = NULL;
+    char *start = envr;
+    char *ptr;
+
+    assert(bin != NULL);
+    assert(envr != NULL);
+
+    do
+    {
+        size_t size;
+        size_t binlen;
+
+        ptr = strchr(start, ':');  /* find next $PATH separator. */
+        if (ptr)
+            *ptr = '\0';
+
+        binlen = strlen(bin);
+        size = strlen(start) + binlen + 2;
+        if (size > alloc_size)
+        {
+            char *x = (char *) allocator.Realloc(exe, size);
+            if (!x)
+            {
+                if (exe != NULL)
+                    allocator.Free(exe);
+                BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+            } /* if */
+
+            alloc_size = size;
+            exe = x;
+        } /* if */
+
+        /* build full binary path... */
+        strcpy(exe, start);
+        if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
+            strcat(exe, "/");
+        strcat(exe, bin);
+
+        if (access(exe, X_OK) == 0)  /* Exists as executable? We're done. */
+        {
+            exe[size - binlen] = '\0'; /* chop off filename, leave '/' */
+            return exe;
+        } /* if */
+
+        start = ptr + 1;  /* start points to beginning of next element. */
+    } while (ptr != NULL);
+
+    if (exe != NULL)
+        allocator.Free(exe);
+
+    return NULL;  /* doesn't exist in path. */
+} /* findBinaryInPath */
+
+
+static char *readSymLink(const char *path)
+{
+    ssize_t len = 64;
+    ssize_t rc = -1;
+    char *retval = NULL;
+
+    while (1)
+    {
+         char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
+         if (ptr == NULL)
+             break;   /* out of memory. */
+         retval = ptr;
+
+         rc = readlink(path, retval, len);
+         if (rc == -1)
+             break;  /* not a symlink, i/o error, etc. */
+
+         else if (rc < len)
+         {
+             retval[rc] = '\0';  /* readlink doesn't null-terminate. */
+             return retval;  /* we're good to go. */
+         } /* else if */
+
+         len *= 2;  /* grow buffer, try again. */
+    } /* while */
+
+    if (retval != NULL)
+        allocator.Free(retval);
+    return NULL;
+} /* readSymLink */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    char *retval = NULL;
+    const char *envr = NULL;
+
+    /*
+     * Try to avoid using argv0 unless forced to. If there's a Linux-like
+     *  /proc filesystem, you can get the full path to the current process from
+     *  the /proc/self/exe symlink.
+     */
+    retval = readSymLink("/proc/self/exe");
+    if (retval == NULL)
+    {
+        /* older kernels don't have /proc/self ... try PID version... */
+        const unsigned long long pid = (unsigned long long) getpid();
+        char path[64];
+        const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
+        if ( (rc > 0) && (rc < sizeof(path)) )
+            retval = readSymLink(path);
+    } /* if */
+
+    if (retval != NULL)  /* chop off filename. */
+    {
+        char *ptr = strrchr(retval, '/');
+        if (ptr != NULL)
+            *(ptr+1) = '\0';
+        else  /* shouldn't happen, but just in case... */
+        {
+            allocator.Free(retval);
+            retval = NULL;
+        } /* else */
+    } /* if */
+
+    /* No /proc/self/exe, but we have an argv[0] we can parse? */
+    if ((retval == NULL) && (argv0 != NULL))
+    {
+        /* fast path: default behaviour can handle this. */
+        if (strchr(argv0, '/') != NULL)
+            return NULL;  /* higher level parses out real path from argv0. */
+
+        /* If there's no dirsep on argv0, then look through $PATH for it. */
+        envr = getenv("PATH");
+        if (envr != NULL)
+        {
+            char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1);
+            BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+            strcpy(path, envr);
+            retval = findBinaryInPath(argv0, path);
+            __PHYSFS_smallFree(path);
+        } /* if */
+    } /* if */
+
+    if (retval != NULL)
+    {
+        /* try to shrink buffer... */
+        char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
+        if (ptr != NULL)
+            retval = ptr;  /* oh well if it failed. */
+    } /* if */
+
+    return retval;
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+    /*
+     * We use XDG's base directory spec, even if you're not on Linux.
+     *  This isn't strictly correct, but the results are relatively sane
+     *  in any case.
+     *
+     * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+     */
+    const char *envr = getenv("XDG_DATA_HOME");
+    const char *append = "/";
+    char *retval = NULL;
+    size_t len = 0;
+
+    if (!envr)
+    {
+        /* You end up with "$HOME/.local/share/Game Name 2" */
+        envr = __PHYSFS_getUserDir();
+        BAIL_IF_MACRO(!envr, ERRPASS, NULL);  /* oh well. */
+        append = ".local/share/";
+    } /* if */
+
+    len = strlen(envr) + strlen(append) + strlen(app) + 2;
+    retval = (char *) allocator.Malloc(len);
+    BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    snprintf(retval, len, "%s%s%s/", envr, append, app);
+    return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return 0;  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif /* PHYSFS_PLATFORM_UNIX */
+
+/* end of unix.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/physfs/src/platform_windows.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,936 @@
+/*
+ * Windows support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon, and made sane by Gregory S. Read.
+ */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_WINDOWS
+
+/* Forcibly disable UNICODE macro, since we manage this ourselves. */
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#include <userenv.h>
+#include <shlobj.h>
+#include <dbt.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "physfs_internal.h"
+
+#define LOWORDER_UINT64(pos) ((PHYSFS_uint32) (pos & 0xFFFFFFFF))
+#define HIGHORDER_UINT64(pos) ((PHYSFS_uint32) ((pos >> 32) & 0xFFFFFFFF))
+
+/*
+ * Users without the platform SDK don't have this defined.  The original docs
+ *  for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
+ *  work as desired.
+ */
+#define PHYSFS_INVALID_SET_FILE_POINTER  0xFFFFFFFF
+
+/* just in case... */
+#define PHYSFS_INVALID_FILE_ATTRIBUTES   0xFFFFFFFF
+
+/* Not defined before the Vista SDK. */
+#define PHYSFS_IO_REPARSE_TAG_SYMLINK    0xA000000C
+
+
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+    if (str == NULL) \
+        w_assignto = NULL; \
+    else { \
+        const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) + 1) * 2); \
+        w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \
+        if (w_assignto != NULL) \
+            PHYSFS_utf8ToUtf16(str, (PHYSFS_uint16 *) w_assignto, len); \
+    } \
+} \
+
+/* Note this counts WCHARs, not codepoints! */
+static PHYSFS_uint64 wStrLen(const WCHAR *wstr)
+{
+    PHYSFS_uint64 len = 0;
+    while (*(wstr++))
+        len++;
+    return len;
+} /* wStrLen */
+
+static char *unicodeToUtf8Heap(const WCHAR *w_str)
+{
+    char *retval = NULL;
+    if (w_str != NULL)
+    {
+        void *ptr = NULL;
+        const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1;
+        retval = allocator.Malloc(len);
+        BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+        PHYSFS_utf8FromUtf16((const PHYSFS_uint16 *) w_str, retval, len);
+        ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */
+        if (ptr != NULL)
+            retval = (char *) ptr;
+    } /* if */
+    return retval;
+} /* unicodeToUtf8Heap */
+
+/* !!! FIXME: do we really need readonly? If not, do we need this struct? */
+typedef struct
+{
+    HANDLE handle;
+    int readonly;
+} WinApiFile;
+
+static HANDLE detectCDThreadHandle = NULL;
+static HWND detectCDHwnd = 0;
+static volatile int initialDiscDetectionComplete = 0;
+static volatile DWORD drivesWithMediaBitmap = 0;
+
+
+static PHYSFS_ErrorCode errcodeFromWinApiError(const DWORD err)
+{
+    /*
+     * win32 error codes are sort of a tricky thing; Microsoft intentionally
+     *  doesn't list which ones a given API might trigger, there are several
+     *  with overlapping and unclear meanings...and there's 16 thousand of
+     *  them in Windows 7. It looks like the ones we care about are in the
+     *  first 500, but I can't say this list is perfect; we might miss
+     *  important values or misinterpret others.
+     *
+     * Don't treat this list as anything other than a work in progress.
+     */
+    switch (err)
+    {
+        case ERROR_SUCCESS: return PHYSFS_ERR_OK;
+        case ERROR_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
+        case ERROR_NETWORK_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
+        case ERROR_NOT_READY: return PHYSFS_ERR_IO;
+        case ERROR_CRC: return PHYSFS_ERR_IO;
+        case ERROR_SEEK: return PHYSFS_ERR_IO;
+        case ERROR_SECTOR_NOT_FOUND: return PHYSFS_ERR_IO;
+        case ERROR_NOT_DOS_DISK: return PHYSFS_ERR_IO;
+        case ERROR_WRITE_FAULT: return PHYSFS_ERR_IO;
+        case ERROR_READ_FAULT: return PHYSFS_ERR_IO;
+        case ERROR_DEV_NOT_EXIST: return PHYSFS_ERR_IO;
+        /* !!! FIXME: ?? case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; */
+        case ERROR_BUFFER_OVERFLOW: return PHYSFS_ERR_BAD_FILENAME;
+        case ERROR_INVALID_NAME: return PHYSFS_ERR_BAD_FILENAME;
+        case ERROR_BAD_PATHNAME: return PHYSFS_ERR_BAD_FILENAME;
+        case ERROR_DIRECTORY: return PHYSFS_ERR_BAD_FILENAME;
+        case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH;
+        case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH;
+        case ERROR_DELETE_PENDING: return PHYSFS_ERR_NO_SUCH_PATH;
+        case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NO_SUCH_PATH;
+        case ERROR_HANDLE_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
+        case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
+        /* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; */
+        /* !!! FIXME: ?? case EISDIR: return PHYSFS_ERR_NOT_A_FILE; */
+        case ERROR_WRITE_PROTECT: return PHYSFS_ERR_READ_ONLY;
+        case ERROR_LOCK_VIOLATION: return PHYSFS_ERR_BUSY;
+        case ERROR_SHARING_VIOLATION: return PHYSFS_ERR_BUSY;
+        case ERROR_CURRENT_DIRECTORY: return PHYSFS_ERR_BUSY;
+        case ERROR_DRIVE_LOCKED: return PHYSFS_ERR_BUSY;
+        case ERROR_PATH_BUSY: return PHYSFS_ERR_BUSY;
+        case ERROR_BUSY: return PHYSFS_ERR_BUSY;
+        case ERROR_NOT_ENOUGH_MEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
+        case ERROR_OUTOFMEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
+        case ERROR_DIR_NOT_EMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
+        default: return PHYSFS_ERR_OS_ERROR;
+    } /* switch */
+} /* errcodeFromWinApiError */
+
+static inline PHYSFS_ErrorCode errcodeFromWinApi(void)
+{
+    return errcodeFromWinApiError(GetLastError());
+} /* errcodeFromWinApi */
+
+
+typedef BOOL (WINAPI *fnSTEM)(DWORD, LPDWORD b);
+
+static DWORD pollDiscDrives(void)
+{
+    /* Try to use SetThreadErrorMode(), which showed up in Windows 7. */
+    HANDLE lib = LoadLibraryA("kernel32.dll");
+    fnSTEM stem = NULL;
+    char drive[4] = { 'x', ':', '\\', '\0' };
+    DWORD oldErrorMode = 0;
+    DWORD drives = 0;
+    DWORD i;
+
+    if (lib)
+        stem = (fnSTEM) GetProcAddress(lib, "SetThreadErrorMode");
+
+    if (stem)
+        stem(SEM_FAILCRITICALERRORS, &oldErrorMode);
+    else
+        oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+    
+    /* Do detection. This may block if a disc is spinning up. */
+    for (i = 'A'; i <= 'Z'; i++)
+    {
+        DWORD tmp = 0;
+        drive[0] = (char) i;
+        if (GetDriveTypeA(drive) != DRIVE_CDROM)
+            continue;
+
+        /* If this function succeeds, there's media in the drive */
+        if (GetVolumeInformationA(drive, NULL, 0, NULL, NULL, &tmp, NULL, 0))
+            drives |= (1 << (i - 'A'));
+    } /* for */
+
+    if (stem)
+        stem(oldErrorMode, NULL);
+    else
+        SetErrorMode(oldErrorMode);
+
+    if (lib)
+        FreeLibrary(lib);
+
+    return drives;
+} /* pollDiscDrives */
+
+
+static LRESULT CALLBACK detectCDWndProc(HWND hwnd, UINT msg,
+                                        WPARAM wp, LPARAM lparam)
+{
+    PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lparam;
+    PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lparam;
+    const int removed = (wp == DBT_DEVICEREMOVECOMPLETE);
+
+    if (msg == WM_DESTROY)
+        return 0;
+    else if ((msg != WM_DEVICECHANGE) ||
+             ((wp != DBT_DEVICEARRIVAL) && (wp != DBT_DEVICEREMOVECOMPLETE)) ||
+             (lpdb->dbch_devicetype != DBT_DEVTYP_VOLUME) ||
+             ((lpdbv->dbcv_flags & DBTF_MEDIA) == 0))
+    {
+        return DefWindowProcW(hwnd, msg, wp, lparam);
+    } /* else if */
+
+    if (removed)
+        drivesWithMediaBitmap &= ~lpdbv->dbcv_unitmask;
+    else
+        drivesWithMediaBitmap |= lpdbv->dbcv_unitmask;
+
+    return TRUE;
+} /* detectCDWndProc */
+
+
+static DWORD WINAPI detectCDThread(LPVOID lpParameter)
+{
+    const char *classname = "PhysicsFSDetectCDCatcher";
+    const char *winname = "PhysicsFSDetectCDMsgWindow";
+    HINSTANCE hInstance = GetModuleHandleW(NULL);
+    ATOM class_atom = 0;
+    WNDCLASSEXA wce;
+    MSG msg;
+
+    memset(&wce, '\0', sizeof (wce));
+    wce.cbSize = sizeof (wce);
+    wce.lpfnWndProc = detectCDWndProc;
+    wce.lpszClassName = classname;
+    wce.hInstance = hInstance;
+    class_atom = RegisterClassExA(&wce);
+    if (class_atom == 0)
+    {
+        initialDiscDetectionComplete = 1;  /* let main thread go on. */
+        return 0;
+    } /* if */
+
+    detectCDHwnd = CreateWindowExA(0, classname, winname, WS_OVERLAPPEDWINDOW,
+                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+                        CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL);
+
+    if (detectCDHwnd == NULL)
+    {
+        initialDiscDetectionComplete = 1;  /* let main thread go on. */
+        UnregisterClassA(classname, hInstance);
+        return 0;
+    } /* if */
+
+    /* We'll get events when discs come and go from now on. */
+
+    /* Do initial detection, possibly blocking awhile... */
+    drivesWithMediaBitmap = pollDiscDrives();
+    initialDiscDetectionComplete = 1;  /* let main thread go on. */
+
+    do
+    {
+        const BOOL rc = GetMessageW(&msg, detectCDHwnd, 0, 0);
+        if ((rc == 0) || (rc == -1))
+            break;  /* don't care if WM_QUIT or error break this loop. */
+        TranslateMessage(&msg);
+        DispatchMessageW(&msg);
+    } while (1);
+
+    /* we've been asked to quit. */
+    DestroyWindow(detectCDHwnd);
+
+    do
+    {
+        const BOOL rc = GetMessage(&msg, detectCDHwnd, 0, 0);
+        if ((rc == 0) || (rc == -1))
+            break;
+        TranslateMessage(&msg);
+        DispatchMessageW(&msg);
+    } while (1);
+
+    UnregisterClassA(classname, hInstance);
+
+    return 0;
+} /* detectCDThread */
+
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+    char drive_str[4] = { 'x', ':', '\\', '\0' };
+    DWORD drives = 0;
+    DWORD i;
+
+    /*
+     * If you poll a drive while a user is inserting a disc, the OS will
+     *  block this thread until the drive has spun up. So we swallow the risk
+     *  once for initial detection, and spin a thread that will get device
+     *  events thereafter, for apps that use this interface to poll for
+     *  disc insertion.
+     */
+    if (!detectCDThreadHandle)
+    {
+        initialDiscDetectionComplete = 0;
+        detectCDThreadHandle = CreateThread(NULL,0,detectCDThread,NULL,0,NULL);
+        if (detectCDThreadHandle == NULL)
+            return;  /* oh well. */
+
+        while (!initialDiscDetectionComplete)
+            Sleep(50);
+    } /* if */
+
+    drives = drivesWithMediaBitmap; /* whatever the thread has seen, we take. */
+    for (i = 'A'; i <= 'Z'; i++)
+    {
+        if (drives & (1 << (i - 'A')))
+        {
+            drive_str[0] = (char) i;
+            cb(data, drive_str);
+        } /* if */
+    } /* for */
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    DWORD buflen = 64;
+    LPWSTR modpath = NULL;
+    char *retval = NULL;
+
+    while (1)
+    {
+        DWORD rc;
+        void *ptr;
+
+        if ( (ptr = allocator.Realloc(modpath, buflen*sizeof(WCHAR))) == NULL )
+        {
+            allocator.Free(modpath);
+            BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+        } /* if */
+        modpath = (LPWSTR) ptr;
+
+        rc = GetModuleFileNameW(NULL, modpath, buflen);
+        if (rc == 0)
+        {
+            allocator.Free(modpath);
+            BAIL_MACRO(errcodeFromWinApi(), NULL);
+        } /* if */
+
+        if (rc < buflen)
+        {
+            buflen = rc;
+            break;
+        } /* if */
+
+        buflen *= 2;
+    } /* while */
+
+    if (buflen > 0)  /* just in case... */
+    {
+        WCHAR *ptr = (modpath + buflen) - 1;
+        while (ptr != modpath)
+        {
+            if (*ptr == '\\')
+                break;
+            ptr--;
+        } /* while */
+
+        if ((ptr == modpath) && (*ptr != '\\'))
+            __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR);  /* oh well. */
+        else
+        {
+            *(ptr+1) = '\0';  /* chop off filename. */
+            retval = unicodeToUtf8Heap(modpath);
+        } /* else */
+    } /* else */
+    allocator.Free(modpath);
+
+    return retval;   /* w00t. */
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+    /*
+     * Vista and later has a new API for this, but SHGetFolderPath works there,
+     *  and apparently just wraps the new API. This is the new way to do it:
+     *
+     *     SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE,
+     *                          NULL, &wszPath);
+     */
+
+    WCHAR path[MAX_PATH];
+    char *utf8 = NULL;
+    size_t len = 0;
+    char *retval = NULL;
+
+    if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE,
+                                   NULL, 0, path)))
+        BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
+
+    utf8 = unicodeToUtf8Heap(path);
+    BAIL_IF_MACRO(!utf8, ERRPASS, NULL);
+    len = strlen(utf8) + strlen(org) + strlen(app) + 4;
+    retval = allocator.Malloc(len);
+    if (!retval)
+    {
+        allocator.Free(utf8);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    sprintf(retval, "%s\\%s\\%s\\", utf8, org, app);
+    return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+char *__PHYSFS_platformCalcUserDir(void)
+{
+    typedef BOOL (WINAPI *fnGetUserProfDirW)(HANDLE, LPWSTR, LPDWORD);
+    fnGetUserProfDirW pGetDir = NULL;
+    HANDLE lib = NULL;
+    HANDLE accessToken = NULL;       /* Security handle to process */
+    char *retval = NULL;
+
+    lib = LoadLibraryA("userenv.dll");
+    BAIL_IF_MACRO(!lib, errcodeFromWinApi(), NULL);
+    pGetDir=(fnGetUserProfDirW) GetProcAddress(lib,"GetUserProfileDirectoryW");
+    GOTO_IF_MACRO(!pGetDir, errcodeFromWinApi(), done);
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &accessToken))
+        GOTO_MACRO(errcodeFromWinApi(), done);
+    else
+    {
+        DWORD psize = 0;
+        WCHAR dummy = 0;
+        LPWSTR wstr = NULL;
+        BOOL rc = 0;
+
+        /*
+         * Should fail. Will write the size of the profile path in
+         *  psize. Also note that the second parameter can't be
+         *  NULL or the function fails.
+         */
+    	rc = pGetDir(accessToken, &dummy, &psize);
+        assert(!rc);  /* !!! FIXME: handle this gracefully. */
+        (void) rc;
+
+        /* Allocate memory for the profile directory */
+        wstr = (LPWSTR) __PHYSFS_smallAlloc((psize + 1) * sizeof (WCHAR));
+        if (wstr != NULL)
+        {
+            if (pGetDir(accessToken, wstr, &psize))
+            {
+                /* Make sure it ends in a dirsep. We allocated +1 for this. */
+                if (wstr[psize - 2] != '\\')
+                {
+                    wstr[psize - 1] = '\\';
+                    wstr[psize - 0] = '\0';
+                } /* if */
+                retval = unicodeToUtf8Heap(wstr);
+            } /* if */
+            __PHYSFS_smallFree(wstr);
+        } /* if */
+
+        CloseHandle(accessToken);
+    } /* if */
+
+done:
+    FreeLibrary(lib);
+    return retval;  /* We made it: hit the showers. */
+} /* __PHYSFS_platformCalcUserDir */
+
+
+void *__PHYSFS_platformGetThreadID(void)
+{
+    return ( (void *) ((size_t) GetCurrentThreadId()) );
+} /* __PHYSFS_platformGetThreadID */
+
+
+static int isSymlinkAttrs(const DWORD attr, const DWORD tag)
+{
+    return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) && 
+             (tag == PHYSFS_IO_REPARSE_TAG_SYMLINK) );
+} /* isSymlinkAttrs */
+
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_EnumFilesCallback callback,
+                                     const char *origdir,
+                                     void *callbackdata)
+{
+    HANDLE dir = INVALID_HANDLE_VALUE;
+    WIN32_FIND_DATAW entw;
+    size_t len = strlen(dirname);
+    char *searchPath = NULL;
+    WCHAR *wSearchPath = NULL;
+
+    /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
+    searchPath = (char *) __PHYSFS_smallAlloc(len + 3);
+    if (searchPath == NULL)
+        return;
+
+    /* Copy current dirname */
+    strcpy(searchPath, dirname);
+
+    /* if there's no '\\' at the end of the path, stick one in there. */
+    if (searchPath[len - 1] != '\\')
+    {
+        searchPath[len++] = '\\';
+        searchPath[len] = '\0';
+    } /* if */
+
+    /* Append the "*" to the end of the string */
+    strcat(searchPath, "*");
+
+    UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath);
+    if (!wSearchPath)
+        return;  /* oh well. */
+
+    dir = FindFirstFileW(wSearchPath, &entw);
+
+    __PHYSFS_smallFree(wSearchPath);
+    __PHYSFS_smallFree(searchPath);
+    if (dir == INVALID_HANDLE_VALUE)
+        return;
+
+    do
+    {
+        const DWORD attr = entw.dwFileAttributes;
+        const DWORD tag = entw.dwReserved0;
+        const WCHAR *fn = entw.cFileName;
+        char *utf8;
+
+        if ((fn[0] == '.') && (fn[1] == '\0'))
+            continue;
+        if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
+            continue;
+        if ((omitSymLinks) && (isSymlinkAttrs(attr, tag)))
+            continue;
+
+        utf8 = unicodeToUtf8Heap(fn);
+        if (utf8 != NULL)
+        {
+            callback(callbackdata, origdir, utf8);
+            allocator.Free(utf8);
+        } /* if */
+    } while (FindNextFileW(dir, &entw) != 0);
+
+    FindClose(dir);
+} /* __PHYSFS_platformEnumerateFiles */
+
+
+int __PHYSFS_platformMkDir(const char *path)
+{
+    WCHAR *wpath;
+    DWORD rc;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+    rc = CreateDirectoryW(wpath, NULL);
+    __PHYSFS_smallFree(wpath);
+    BAIL_IF_MACRO(rc == 0, errcodeFromWinApi(), 0);
+    return 1;
+} /* __PHYSFS_platformMkDir */
+
+
+int __PHYSFS_platformInit(void)
+{
+    return 1;  /* It's all good */
+} /* __PHYSFS_platformInit */
+
+
+int __PHYSFS_platformDeinit(void)
+{
+    if (detectCDThreadHandle)
+    {
+        if (detectCDHwnd)
+            PostMessageW(detectCDHwnd, WM_QUIT, 0, 0);
+        CloseHandle(detectCDThreadHandle);
+        detectCDThreadHandle = NULL;
+        initialDiscDetectionComplete = 0;
+        drivesWithMediaBitmap = 0;
+    } /* if */
+
+    return 1; /* It's all good */
+} /* __PHYSFS_platformDeinit */
+
+
+static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
+{
+    HANDLE fileh;
+    WinApiFile *retval;
+    WCHAR *wfname;
+
+    UTF8_TO_UNICODE_STACK_MACRO(wfname, fname);
+    BAIL_IF_MACRO(!wfname, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    fileh = CreateFileW(wfname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                             NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
+    __PHYSFS_smallFree(wfname);
+
+    BAIL_IF_MACRO(fileh == INVALID_HANDLE_VALUE,errcodeFromWinApi(), NULL);
+
+    retval = (WinApiFile *) allocator.Malloc(sizeof (WinApiFile));
+    if (!retval)
+    {
+        CloseHandle(fileh);
+        BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    } /* if */
+
+    retval->readonly = rdonly;
+    retval->handle = fileh;
+    return retval;
+} /* doOpen */
+
+
+void *__PHYSFS_platformOpenRead(const char *filename)
+{
+    return doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1);
+} /* __PHYSFS_platformOpenRead */
+
+
+void *__PHYSFS_platformOpenWrite(const char *filename)
+{
+    return doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0);
+} /* __PHYSFS_platformOpenWrite */
+
+
+void *__PHYSFS_platformOpenAppend(const char *filename)
+{
+    void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
+    if (retval != NULL)
+    {
+        HANDLE h = ((WinApiFile *) retval)->handle;
+        DWORD rc = SetFilePointer(h, 0, NULL, FILE_END);
+        if (rc == PHYSFS_INVALID_SET_FILE_POINTER)
+        {
+            const PHYSFS_ErrorCode err = errcodeFromWinApi();
+            CloseHandle(h);
+            allocator.Free(retval);
+            BAIL_MACRO(err, NULL);
+        } /* if */
+    } /* if */
+
+    return retval;
+} /* __PHYSFS_platformOpenAppend */
+
+
+PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    PHYSFS_sint64 totalRead = 0;
+
+    if (!__PHYSFS_ui64FitsAddressSpace(len))
+        BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+    while (len > 0)
+    {
+        const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len;
+        DWORD numRead = 0;
+        if (!ReadFile(Handle, buf, thislen, &numRead, NULL))
+            BAIL_MACRO(errcodeFromWinApi(), -1);
+        len -= (PHYSFS_uint64) numRead;
+        totalRead += (PHYSFS_sint64) numRead;
+        if (numRead != thislen)
+            break;
+    } /* while */
+
+    return totalRead;
+} /* __PHYSFS_platformRead */
+
+
+PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
+                                     PHYSFS_uint64 len)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    PHYSFS_sint64 totalWritten = 0;
+
+    if (!__PHYSFS_ui64FitsAddressSpace(len))
+        BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
+
+    while (len > 0)
+    {
+        const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len;
+        DWORD numWritten = 0;
+        if (!WriteFile(Handle, buffer, thislen, &numWritten, NULL))
+            BAIL_MACRO(errcodeFromWinApi(), -1);
+        len -= (PHYSFS_uint64) numWritten;
+        totalWritten += (PHYSFS_sint64) numWritten;
+        if (numWritten != thislen)
+            break;
+    } /* while */
+
+    return totalWritten;
+} /* __PHYSFS_platformWrite */
+
+
+int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    LONG HighOrderPos;
+    PLONG pHighOrderPos;
+    DWORD rc;
+
+    /* Get the high order 32-bits of the position */
+    HighOrderPos = HIGHORDER_UINT64(pos);
+
+    /*
+     * MSDN: "If you do not need the high-order 32 bits, this
+     *         pointer must be set to NULL."
+     */
+    pHighOrderPos = (HighOrderPos) ? &HighOrderPos : NULL;
+
+    /* Move pointer "pos" count from start of file */
+    rc = SetFilePointer(Handle, LOWORDER_UINT64(pos),
+                        pHighOrderPos, FILE_BEGIN);
+
+    if ( (rc == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(errcodeFromWinApi(), 0);
+    } /* if */
+    
+    return 1;  /* No error occured */
+} /* __PHYSFS_platformSeek */
+
+
+PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    LONG HighPos = 0;
+    DWORD LowPos;
+    PHYSFS_sint64 retval;
+
+    /* Get current position */
+    LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT);
+    if ( (LowPos == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(errcodeFromWinApi(), -1);
+    } /* if */
+    else
+    {
+        /* Combine the high/low order to create the 64-bit position value */
+        retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
+        assert(retval >= 0);
+    } /* else */
+
+    return retval;
+} /* __PHYSFS_platformTell */
+
+
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    DWORD SizeHigh;
+    DWORD SizeLow;
+    PHYSFS_sint64 retval;
+
+    SizeLow = GetFileSize(Handle, &SizeHigh);
+    if ( (SizeLow == PHYSFS_INVALID_SET_FILE_POINTER) &&
+         (GetLastError() != NO_ERROR) )
+    {
+        BAIL_MACRO(errcodeFromWinApi(), -1);
+    } /* if */
+    else
+    {
+        /* Combine the high/low order to create the 64-bit position value */
+        retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
+        assert(retval >= 0);
+    } /* else */
+
+    return retval;
+} /* __PHYSFS_platformFileLength */
+
+
+int __PHYSFS_platformFlush(void *opaque)
+{
+    WinApiFile *fh = ((WinApiFile *) opaque);
+    if (!fh->readonly)
+        BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), errcodeFromWinApi(), 0);
+
+    return 1;
+} /* __PHYSFS_platformFlush */
+
+
+void __PHYSFS_platformClose(void *opaque)
+{
+    HANDLE Handle = ((WinApiFile *) opaque)->handle;
+    (void) CloseHandle(Handle); /* ignore errors. You should have flushed! */
+    allocator.Free(opaque);
+} /* __PHYSFS_platformClose */
+
+
+static int doPlatformDelete(LPWSTR wpath)
+{
+    const int isdir = (GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY);
+    const BOOL rc = (isdir) ? RemoveDirectoryW(wpath) : DeleteFileW(wpath);
+    BAIL_IF_MACRO(!rc, errcodeFromWinApi(), 0);
+    return 1;   /* if you made it here, it worked. */
+} /* doPlatformDelete */
+
+
+int __PHYSFS_platformDelete(const char *path)
+{
+    int retval = 0;
+    LPWSTR wpath = NULL;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+    BAIL_IF_MACRO(!wpath, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    retval = doPlatformDelete(wpath);
+    __PHYSFS_smallFree(wpath);
+    return retval;
+} /* __PHYSFS_platformDelete */
+
+
+void *__PHYSFS_platformCreateMutex(void)
+{
+    LPCRITICAL_SECTION lpcs;
+    lpcs = (LPCRITICAL_SECTION) allocator.Malloc(sizeof (CRITICAL_SECTION));
+    BAIL_IF_MACRO(!lpcs, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    InitializeCriticalSection(lpcs);
+    return lpcs;
+} /* __PHYSFS_platformCreateMutex */
+
+
+void __PHYSFS_platformDestroyMutex(void *mutex)
+{
+    DeleteCriticalSection((LPCRITICAL_SECTION) mutex);
+    allocator.Free(mutex);
+} /* __PHYSFS_platformDestroyMutex */
+
+
+int __PHYSFS_platformGrabMutex(void *mutex)
+{
+    EnterCriticalSection((LPCRITICAL_SECTION) mutex);
+    return 1;
+} /* __PHYSFS_platformGrabMutex */
+
+
+void __PHYSFS_platformReleaseMutex(void *mutex)
+{
+    LeaveCriticalSection((LPCRITICAL_SECTION) mutex);
+} /* __PHYSFS_platformReleaseMutex */
+
+
+static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
+{
+    SYSTEMTIME st_utc;
+    SYSTEMTIME st_localtz;
+    TIME_ZONE_INFORMATION tzi;
+    DWORD tzid;
+    PHYSFS_sint64 retval;
+    struct tm tm;
+    BOOL rc;
+
+    BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), errcodeFromWinApi(), -1);
+    tzid = GetTimeZoneInformation(&tzi);
+    BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, errcodeFromWinApi(), -1);
+    rc = SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz);
+    BAIL_IF_MACRO(!rc, errcodeFromWinApi(), -1);
+
+    /* Convert to a format that mktime() can grok... */
+    tm.tm_sec = st_localtz.wSecond;
+    tm.tm_min = st_localtz.wMinute;
+    tm.tm_hour = st_localtz.wHour;
+    tm.tm_mday = st_localtz.wDay;
+    tm.tm_mon = st_localtz.wMonth - 1;
+    tm.tm_year = st_localtz.wYear - 1900;
+    tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+    tm.tm_yday = -1;
+    tm.tm_isdst = -1;
+
+    /* Convert to a format PhysicsFS can grok... */
+    retval = (PHYSFS_sint64) mktime(&tm);
+    BAIL_IF_MACRO(retval == -1, PHYSFS_ERR_OS_ERROR, -1);
+    return retval;
+} /* FileTimeToPhysfsTime */
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *stat)
+{
+    WIN32_FILE_ATTRIBUTE_DATA winstat;
+    WCHAR *wstr = NULL;
+    DWORD err = 0;
+    BOOL rc = 0;
+
+    UTF8_TO_UNICODE_STACK_MACRO(wstr, filename);
+    BAIL_IF_MACRO(!wstr, PHYSFS_ERR_OUT_OF_MEMORY, 0);
+    rc = GetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat);
+    err = (!rc) ? GetLastError() : 0;
+    *exists = ((err != ERROR_FILE_NOT_FOUND) && (err != ERROR_PATH_NOT_FOUND));
+    __PHYSFS_smallFree(wstr);
+    BAIL_IF_MACRO(!rc, errcodeFromWinApiError(err), 0);
+
+    stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
+    stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
+    stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
+
+    if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+    {
+        stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+        stat->filesize = 0;
+    } /* if */
+
+    else if(winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE))
+    {
+        /* !!! FIXME: what are reparse points? */
+        stat->filetype = PHYSFS_FILETYPE_OTHER;
+        /* !!! FIXME: don't rely on this */
+        stat->filesize = 0;
+    } /* else if */
+
+    /* !!! FIXME: check for symlinks on Vista. */
+
+    else
+    {
+        stat->filetype = PHYSFS_FILETYPE_REGULAR;
+        stat->filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow;
+    } /* else */
+
+    stat->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
+
+    return 1;
+} /* __PHYSFS_platformStat */
+
+
+/* !!! FIXME: Don't use C runtime for allocators? */
+int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
+{
+    return 0;  /* just use malloc() and friends. */
+} /* __PHYSFS_platformSetDefaultAllocator */
+
+#endif  /* PHYSFS_PLATFORM_WINDOWS */
+
+/* end of windows.c ... */
+
+
--- a/misc/quazip/CMakeLists.txt	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-set(QT_USE_QTCORE TRUE)
-
-find_package(Qt4 REQUIRED)
-if(NOT CROSSAPPLE)
-    include(${QT_USE_FILE})
-endif()
-
-
-file(GLOB SRCS "*.c" "*.cpp")
-file(GLOB PUBLIC_HEADERS "*.h")
-qt4_wrap_cpp(MOC_SRCS "quazipfile.h")
-set(SRCS ${SRCS} ${MOC_SRCS})
-
-add_library(quazip STATIC ${SRCS})
--- a/misc/quazip/JlCompress.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,468 +0,0 @@
-#include "JlCompress.h"
-#include <QDebug>
-/**OK
- * Comprime il file fileName, nell'oggetto zip, con il nome fileDest.
- *
- * La funzione fallisce se:
- * * zip==NULL;
- * * l'oggetto zip è stato aperto in una modalità non compatibile con l'aggiunta di file;
- * * non è possibile aprire il file d'origine;
- * * non è possibile creare il file all'interno dell'oggetto zip;
- * * si è rilevato un errore nella copia dei dati;
- * * non è stato possibile chiudere il file all'interno dell'oggetto zip;
- */
-bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) {
-    // zip: oggetto dove aggiungere il file
-    // fileName: nome del file reale
-    // fileDest: nome del file all'interno del file compresso
-
-    // Controllo l'apertura dello zip
-    if (!zip) return false;
-    if (zip->getMode()!=QuaZip::mdCreate &&
-        zip->getMode()!=QuaZip::mdAppend &&
-        zip->getMode()!=QuaZip::mdAdd) return false;
-
-    // Apro il file originale
-    QFile inFile;
-    inFile.setFileName(fileName);
-    if(!inFile.open(QIODevice::ReadOnly)) return false;
-
-    // Apro il file risulato
-    QuaZipFile outFile(zip);
-    if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false;
-
-    // Copio i dati
-    char c;
-    while(inFile.getChar(&c)&&outFile.putChar(c));
-    if(outFile.getZipError()!=UNZ_OK) return false;
-
-    // Chiudo i file
-    outFile.close();
-    if (outFile.getZipError()!=UNZ_OK) return false;
-    inFile.close();
-
-    return true;
-}
-
-/**OK
- * Comprime la cartella dir nel file fileCompressed, se recursive è true allora
- * comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato
- * togliendo il pat della cartella origDir al path della cartella dir.
- * Se la funzione fallisce restituisce false e cancella il file che si è tentato
- * di creare.
- *
- * La funzione fallisce se:
- * * zip==NULL;
- * * l'oggetto zip è stato aperto in una modalità non compatibile con l'aggiunta di file;
- * * la cartella dir non esiste;
- * * la compressione di una sotto cartella fallisce (1);
- * * la compressione di un file fallisce;
- * (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle
- * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa
- * funzione.
- */
-bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) {
-    // zip: oggetto dove aggiungere il file
-    // dir: cartella reale corrente
-    // origDir: cartella reale originale
-    // (path(dir)-path(origDir)) = path interno all'oggetto zip
-
-    // Controllo l'apertura dello zip
-    if (!zip) return false;
-    if (zip->getMode()!=QuaZip::mdCreate &&
-        zip->getMode()!=QuaZip::mdAppend &&
-        zip->getMode()!=QuaZip::mdAdd) return false;
-
-    // Controllo la cartella
-    QDir directory(dir);
-    if (!directory.exists()) return false;
-
-    // Se comprimo anche le sotto cartelle
-    if (recursive) {
-        // Per ogni sotto cartella
-        QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot);
-        foreach (QFileInfo file, files) {
-            // Comprimo la sotto cartella
-            if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false;
-        }
-    }
-
-    // Per ogni file nella cartella
-    QFileInfoList files = directory.entryInfoList(QDir::Files);
-    QDir origDirectory(origDir);
-    foreach (QFileInfo file, files) {
-        // Se non è un file o è il file compresso che sto creando
-        if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue;
-
-        // Creo il nome relativo da usare all'interno del file compresso
-        QString filename = origDirectory.relativeFilePath(file.absoluteFilePath());
-
-        // Comprimo il file
-        if (!compressFile(zip,file.absoluteFilePath(),filename)) return false;
-    }
-
-    return true;
-}
-
-/**OK
- * Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest.
- * Se la funzione fallisce restituisce false e cancella il file che si è tentato di estrarre.
- *
- * La funzione fallisce se:
- * * zip==NULL;
- * * l'oggetto zip è stato aperto in una modalità non compatibile con l'estrazione di file;
- * * non è possibile aprire il file all'interno dell'oggetto zip;
- * * non è possibile creare il file estratto;
- * * si è rilevato un errore nella copia dei dati (1);
- * * non è stato possibile chiudere il file all'interno dell'oggetto zip (1);
- *
- * (1): prima di uscire dalla funzione cancella il file estratto.
- */
-bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) {
-    // zip: oggetto dove aggiungere il file
-    // filename: nome del file reale
-    // fileincompress: nome del file all'interno del file compresso
-
-    // Controllo l'apertura dello zip
-    if (!zip) return false;
-    if (zip->getMode()!=QuaZip::mdUnzip) return false;
-
-    // Apro il file compresso
-    zip->setCurrentFile(fileName);
-    QuaZipFile inFile(zip);
-    if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false;
-
-    // Controllo esistenza cartella file risultato
-    QDir().mkpath(QFileInfo(fileDest).absolutePath());
-
-    // Apro il file risultato
-    QFile outFile;
-    outFile.setFileName(fileDest);
-    if(!outFile.open(QIODevice::WriteOnly)) return false;
-
-    // Copio i dati
-    char c;
-    while(inFile.getChar(&c)) outFile.putChar(c);
-    if (inFile.getZipError()!=UNZ_OK) {
-        removeFile(QStringList(fileDest));
-        return false;
-    }
-
-    // Chiudo i file
-    inFile.close();
-    if (inFile.getZipError()!=UNZ_OK) {
-        removeFile(QStringList(fileDest));
-        return false;
-    }
-    outFile.close();
-
-    return true;
-}
-
-/**
- * Rimuove i file il cui nome è specificato all'interno di listFile.
- * Restituisce true se tutti i file sono stati cancellati correttamente, attenzione
- * perchè può restituire false anche se alcuni file non esistevano e si è tentato
- * di cancellarli.
- */
-bool JlCompress::removeFile(QStringList listFile) {
-    bool ret = true;
-    // Per ogni file
-    for (int i=0; i<listFile.count(); i++) {
-        // Lo elimino
-        ret = ret && QFile::remove(listFile.at(i));
-    }
-    return ret;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-/**OK
- * Comprime il file fileName nel file fileCompressed.
- * Se la funzione fallisce restituisce false e cancella il file che si è tentato
- * di creare.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * la compressione del file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-bool JlCompress::compressFile(QString fileCompressed, QString file) {
-    // Creo lo zip
-    QuaZip* zip  = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
-    if(!zip->open(QuaZip::mdCreate)) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-
-    // Aggiungo il file
-    if (!compressFile(zip,file,QFileInfo(file).fileName())) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-    delete zip;
-
-    return true;
-}
-
-/**OK
- * Comprime i file specificati in files nel file fileCompressed.
- * Se la funzione fallisce restituisce false e cancella il file che si è tentato
- * di creare.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * la compressione di un file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-bool JlCompress::compressFiles(QString fileCompressed, QStringList files) {
-    // Creo lo zip
-    QuaZip* zip  = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
-    if(!zip->open(QuaZip::mdCreate)) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-
-    // Comprimo i file
-    QFileInfo info;
-    foreach (QString file, files) {
-        info.setFile(file);
-        if (!info.exists() || !compressFile(zip,file,info.fileName())) {
-            delete zip;
-            QFile::remove(fileCompressed);
-            return false;
-        }
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-    delete zip;
-
-    return true;
-}
-
-/**OK
- * Comprime la cartella dir nel file fileCompressed, se recursive è true allora
- * comprime anche le sotto cartelle.
- * Se la funzione fallisce restituisce false e cancella il file che si è tentato
- * di creare.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * la compressione di un file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) {
-    // Creo lo zip
-    QuaZip* zip  = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
-    if(!zip->open(QuaZip::mdCreate)) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-
-    // Aggiungo i file e le sotto cartelle
-    if (!compressSubDir(zip,dir,dir,recursive)<0) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        delete zip;
-        QFile::remove(fileCompressed);
-        return false;
-    }
-    delete zip;
-
-    return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-/**OK
- * Estrae il file fileName, contenuto nel file fileCompressed, con il nome fileDest.
- * Se fileDest = "" allora il file viene estratto con lo stesso nome con cui è
- * stato compresso.
- * Se la funzione fallisce cancella il file che si è tentato di estrarre.
- * Restituisce il nome assoluto del file estratto.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * l'estrazione del file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-QString JlCompress::extractFile(QString fileCompressed, QString fileName, QString fileDest) {
-    // Apro lo zip
-    QuaZip* zip  = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    if(!zip->open(QuaZip::mdUnzip)) {
-        delete zip;
-        return QString();
-    }
-
-    // Estraggo il file
-    if (fileDest.isEmpty()) fileDest = fileName;
-    if (!extractFile(zip,fileName,fileDest)) {
-        delete zip;
-        return QString();
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        removeFile(QStringList(fileDest));
-        return QString();
-    }
-    delete zip;
-
-    return QFileInfo(fileDest).absoluteFilePath();
-}
-
-/**OK
- * Estrae i file specificati in files, contenuti nel file fileCompressed, nella
- * cartella dir. La struttura a cartelle del file compresso viene rispettata.
- * Se dir = "" allora il file viene estratto nella cartella corrente.
- * Se la funzione fallisce cancella i file che si è tentato di estrarre.
- * Restituisce i nomi assoluti dei file estratti.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * l'estrazione di un file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-QStringList JlCompress::extractFiles(QString fileCompressed, QStringList files, QString dir) {
-    // Creo lo zip
-    QuaZip* zip  = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    if(!zip->open(QuaZip::mdUnzip)) {
-        delete zip;
-        return QStringList();
-    }
-
-    // Estraggo i file
-    for (int i=0; i<files.count(); i++) {
-        if (!extractFile(zip, files.at(i), QDir(dir).absoluteFilePath(files.at(i)))) {
-            delete zip;
-            removeFile(files);
-            return QStringList();
-        }
-        files[i] = QDir(dir).absoluteFilePath(files.at(i));
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        delete zip;
-        removeFile(files);
-        return QStringList();
-    }
-    delete zip;
-
-    return files;
-}
-
-/**OK
- * Estrae il file fileCompressed nella cartella dir.
- * Se dir = "" allora il file viene estratto nella cartella corrente.
- * Se la funzione fallisce cancella i file che si è tentato di estrarre.
- * Restituisce i nomi assoluti dei file estratti.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * la compressione di un file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-QStringList JlCompress::extractDir(QString fileCompressed, QString dir) {
-    // Apro lo zip
-    QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    if(!zip->open(QuaZip::mdUnzip)) {
-        delete zip;
-        return QStringList();
-    }
-
-    // Estraggo i file
-    QStringList lst = getFileList(fileCompressed);
-
-    QDir directory(dir);
-    for (int i=0; i<lst.count(); i++) {
-        QString absFilePath = directory.absoluteFilePath(lst.at(i));
-        if (!extractFile(zip, lst.at(i), absFilePath)) {
-            delete zip;
-            removeFile(lst);
-            return QStringList();
-        }
-        lst[i] = absFilePath;
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        delete zip;
-        removeFile(lst);
-        return QStringList();
-    }
-    delete zip;
-
-    return lst;
-}
-
-/**OK
- * Restituisce la lista dei file resenti nel file compresso fileCompressed.
- * Se la funzione fallisce, restituisce un elenco vuoto.
- *
- * La funzione fallisce se:
- * * non si riesce ad aprire l'oggetto zip;
- * * la richiesta di informazioni di un file fallisce;
- * * non si riesce a chiudere l'oggetto zip;
- */
-QStringList JlCompress::getFileList(QString fileCompressed) {
-    // Apro lo zip
-    QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath());
-    if(!zip->open(QuaZip::mdUnzip)) {
-        delete zip;
-        return QStringList();
-    }
-
-    // Estraggo i nomi dei file
-    QStringList lst;
-    QuaZipFileInfo info;
-    for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) {
-      if(!zip->getCurrentFileInfo(&info)) {
-          delete zip;
-          return QStringList();
-      }
-      lst << info.name;
-      //info.name.toLocal8Bit().constData()
-    }
-
-    // Chiudo il file zip
-    zip->close();
-    if(zip->getZipError()!=0) {
-        delete zip;
-        return QStringList();
-    }
-    delete zip;
-
-    return lst;
-}
-
--- a/misc/quazip/JlCompress.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#ifndef JLCOMPRESSFOLDER_H_
-#define JLCOMPRESSFOLDER_H_
-
-#include "quazip.h"
-#include "quazipfile.h"
-#include "quazipfileinfo.h"
-#include <QString>
-#include <QDir>
-#include <QFileInfo>
-#include <QFile>
-
-class QUAZIP_EXPORT JlCompress {
-private:
-    static bool compressFile(QuaZip* zip, QString fileName, QString fileDest);
-    static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true);
-    static bool extractFile(QuaZip* zip, QString fileName, QString fileDest);
-
-    static bool removeFile(QStringList listFile);
-
-public:
-    static bool compressFile(QString fileCompressed, QString file);
-    static bool compressFiles(QString fileCompressed, QStringList files);
-    static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true);
-
-public:
-    static QString extractFile(QString fileCompressed, QString file, QString fileDest = QString());
-    static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString());
-    static QStringList extractDir(QString fileCompressed, QString dir = QString());
-    static QStringList getFileList(QString fileCompressed);
-};
-
-#endif /* JLCOMPRESSFOLDER_H_ */
--- a/misc/quazip/crypt.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/* crypt.h -- base code for crypt/uncrypt ZIPfile
-
-
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   This code is a modified version of crypting code in Infozip distribution
-
-   The encryption/decryption parts of this source code (as opposed to the
-   non-echoing password parts) were originally written in Europe.  The
-   whole source package can be freely distributed, including from the USA.
-   (Prior to January 2000, re-export from the US was a violation of US law.)
-
-   This encryption code is a direct transcription of the algorithm from
-   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
-   file (appnote.txt) is distributed with the PKZIP program (even in the
-   version without encryption capabilities).
-
-   If you don't need crypting in your application, just define symbols
-   NOCRYPT and NOUNCRYPT.
-
-   This code support the "Traditional PKWARE Encryption".
-
-   The new AES encryption added on Zip format by Winzip (see the page
-   http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
-   Encryption is not supported.
-*/
-
-#include "quazip_global.h"
-
-#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
-
-/***********************************************************************
- * Return the next byte in the pseudo-random sequence
- */
-static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab UNUSED)
-{
-    //(void) pcrc_32_tab; /* avoid "unused parameter" warning */
-    unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an
-                     * unpredictable manner on 16-bit systems; not a problem
-                     * with any known compiler so far, though */
-
-    temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
-    return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
-}
-
-/***********************************************************************
- * Update the encryption keys with the next byte of plain text
- */
-static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
-{
-    (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
-    (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
-    (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
-    {
-      register int keyshift = (int)((*(pkeys+1)) >> 24);
-      (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
-    }
-    return c;
-}
-
-
-/***********************************************************************
- * Initialize the encryption keys and the random header according to
- * the given password.
- */
-static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
-{
-    *(pkeys+0) = 305419896L;
-    *(pkeys+1) = 591751049L;
-    *(pkeys+2) = 878082192L;
-    while (*passwd != '\0') {
-        update_keys(pkeys,pcrc_32_tab,(int)*passwd);
-        passwd++;
-    }
-}
-
-#define zdecode(pkeys,pcrc_32_tab,c) \
-    (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
-
-#define zencode(pkeys,pcrc_32_tab,c,t) \
-    (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
-
-#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
-
-#define RAND_HEAD_LEN  12
-   /* "last resort" source for second part of crypt seed pattern */
-#  ifndef ZCR_SEED2
-#    define ZCR_SEED2 3141592654UL     /* use PI as default pattern */
-#  endif
-
-static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)
-    const char *passwd;         /* password string */
-    unsigned char *buf;         /* where to write header */
-    int bufSize;
-    unsigned long* pkeys;
-    const unsigned long* pcrc_32_tab;
-    unsigned long crcForCrypting;
-{
-    int n;                       /* index in random header */
-    int t;                       /* temporary */
-    int c;                       /* random byte */
-    unsigned char header[RAND_HEAD_LEN-2]; /* random header */
-    static unsigned calls = 0;   /* ensure different random header each time */
-
-    if (bufSize<RAND_HEAD_LEN)
-      return 0;
-
-    /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
-     * output of rand() to get less predictability, since rand() is
-     * often poorly implemented.
-     */
-    if (++calls == 1)
-    {
-        srand((unsigned)(time(NULL) ^ ZCR_SEED2));
-    }
-    init_keys(passwd, pkeys, pcrc_32_tab);
-    for (n = 0; n < RAND_HEAD_LEN-2; n++)
-    {
-        c = (rand() >> 7) & 0xff;
-        header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
-    }
-    /* Encrypt random header (last two bytes is high word of crc) */
-    init_keys(passwd, pkeys, pcrc_32_tab);
-    for (n = 0; n < RAND_HEAD_LEN-2; n++)
-    {
-        buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
-    }
-    buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
-    buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
-    return n;
-}
-
-#endif
--- a/misc/quazip/doc/faq.dox	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/**
- * \page faq QuaZip FAQ
- *
- * <!--
- * \ref faq-GPL "Q. Is it possible to release an LGPL version of the QuaZip?"
- *
- * \ref faq-non-QIODevice "Q. Is there any way to use QuaZipFile in Qt where you are supposed to use normal (non-zipped) file, but not through QIODevice API?"
- * -->
- *
- * \anchor faq-GPL Q. Is it possible to release an LGPL version of the
- * QuaZip?
- *
- * A. I do not know much about licensing, so I can answer for sure, but
- * QuaZip was developed using Open Source edition of Qt, so I see no
- * way it could be released under anything except GPL.
- *
- * \anchor faq-non-QIODevice Q. Is there any way to use QuaZipFile in Qt
- * where you are supposed to use normal (non-zipped) file, but not
- * through QIODevice API?
- *
- * A. Usually not. For example, if you are passing file name to some
- * database driver (like SQLite), Qt usually just passes this name down
- * to the 3rd-party library, which is usually does not know anything
- * about QIODevice and therefore there is no way to pass QuaZipFile as
- * normal file. However, if we are talking about some place where you
- * pass file name, and then indirectly use QFile to open it, then it is
- * a good idea to make overloaded method, which accepts QIODevice
- * pointer. Then you would be able to pass QuaZipFile as well as many
- * other nice things such as QBuffer or QProcess.
- **/
--- a/misc/quazip/doc/index.dox	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-/**
- * \mainpage QuaZIP - Qt/C++ wrapper for ZIP/UNZIP package
- *
-\htmlonly
-<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=142688&amp;type=7" style="width:210; height:62; border:none; float:right;" alt="Powered by SourceForge.net" /></a>
-\endhtmlonly
- * \section overview Overview
- * 
- * QuaZIP is a simple C++ wrapper over <a
- * href="http://www.winimage.com/zLibDll/unzip.html">Gilles Vollant's ZIP/UNZIP
- * package</a> that can be used to access ZIP archives. It uses <a
- * href="http://www.trolltech.com/products/qt/index.html">Trolltech's
- * Qt toolkit</a>.
- *
- * If you do not know what Qt is, you have two options:
- * - Just forget about QuaZIP.
- * - Learn more about Qt by downloading it and/or reading excellent <a
- *   href="http://doc.trolltech.com/">official Qt documentation</a>
- *
- * The choice is yours, but if you are really interested in
- * cross-platform (Windows/Linux/BSD/UNIX/Mac/Others) software
- * development, I would definitely recommend you the second choice ^_^
- *
- * QuaZIP allows you to access files inside ZIP archives using QIODevice
- * API, and - yes! - that means that you can also use QTextStream,
- * QDataStream or whatever you would like to use on your zipped files.
- *
- * QuaZIP provides complete abstraction of the ZIP/UNZIP API, for both
- * reading from and writing to ZIP archives.
- *
- * \section platforms Platforms supported
- *
- * QuaZIP has been currently tested with Qt 4.0.0 on the following
- * platforms:
- * - linux-g++
- * - freebsd-g++
- * - hpux-acc
- * - win32-g++ (MinGW)
- * 
- * No testing has been done on other systems. Of course, patches to
- * make it work on any platform that it currently does not work on are
- * always welcome!
- *
- * \section whats-new What is new in this version of QuaZIP?
- *
- * See NEWS file supplied with the distribution.
- *
- * \section getting Getting latest version of QuaZIP
- *
- * Check <a href="http://sourceforge.net/projects/quazip/">QuaZIP
- * project's page at SourceForge.net</a>. Also, you may wish to read
- * latest version documentation available at the <a
- * href="http://quazip.sourceforge.net/">QuaZIP web site</a>.
- *
- * \section Requirements
- *
- * Just <a href="http://www.zlib.org/">zlib</a> and Qt 4. Well, Qt 4
- * depends on zlib anyway.
- *
- * \section building Building, testing and installing
- *
- * \note Instructions given in this section assume that you are
- * using some UNIX dialect, but the build process should be very similar
- * on win32-g++ platform too. Sorry, but other platforms are
- * undocumented. I do not think it is a big deal, though - it is
- * standard usage of the Qt's qmake, so you most probably already know
- * everything that is required.
- *
- * To build it on some UNIX dialect:
-\verbatim
-$ cd /wherever/quazip/source/is/quazip-x.y.z/quazip
-$ qmake [PREFIX=where-to-install]
-$ make
-\endverbatim
- *
- * Make sure that you have Qt 4 installed with all required headers and
- * utilities (not just library) and that you run qmake utility of the Qt
- * 4, not some other version you may have already installed (you may
- * need to type full path to qmake like /usr/local/qt4/bin/qmake).
- *
- * To reconfigure (with another PREFIX, for example), just run qmake
- * with appropriate arguments again.
- *
- * If you need to specify additional include path or libraries, use
- * qmake features (see qmake reference in the Qt documentation). For
- * example:
- *
-\verbatim
-$ qmake LIBS+=-L/usr/local/zlib/lib INCLUDEPATH+=/usr/local/zlib/include
-\endverbatim
- * (note abscence of "-I" before include path)
- *
- * To check if QuaZIP's basic features work ok on your platform, you may
- * wish to compile simple test programs provided in test directory.
- * Look in the sources of the tests to find out about their
- * requirements. Typically, the test looks something like this:
-\verbatim
-$ cd /wherever/quazip/source/is/quazip-x.y.z/test/zip
-$ qmake
-$ make
-$ ./zip
-$ cd ../unzip
-$ cp ../zip/test.zip ./test.zip
-$ mkdir out
-$ qmake
-$ make
-$ ./unzip
-\endverbatim
- *
- * You should see the zip contents with details as the output of the
- * "./unzip". Ignore message saying you should check the file name for
- * testCase() if you do not want to test
- * \link QuaZip::CaseSensitivity locale-aware case-insensitivity\endlink.
- * Otherwise, see the sources. In any case, this message appearing means
- * that everything else was fine. Otherwise, you will get some other error
- * message instead. Investigate it or send bug report including message,
- * platform and QuaZIP version used.
- *
- * To install compiled library:
-\verbatim
-$ make install
-\endverbatim
- *
- * By default, QuaZIP compiles as static library, but you have other
- * options:
- * - Just copy appropriate source files to your project and use them;
- * - Compile QuaZIP as shared library by changing "staticlib" in
- *   quazip/quazip.pro to "dll".
- *
- * Latter is not recommended because future versions of QuaZIP most
- * probably will be binary incompatible.
- *
- * \section using Using
- *
- * See \ref usage "usage page".
- * 
- * \section bugs Bugs
- *
- * QuaZIP is currently at the initial development stage. Therefore,
- * there are may be plenty of bugs and other bad things. Bug reports and
- * patches are always welcome (see "contacts" below).
- *
- * \section contacts Authors and contacts
- *
- * This wrapper has been written by Sergey A. Tachenov, AKA Alqualos.
- * This is my first open source project, so it may suck, but I did not
- * find anything like that, so I just had no other choice but to write
- * it.
- *
- * If you have anything to say to me about QuaZIP library, feel free to
- * do so (read the \ref faq first, though). I can not promise,
- * though, that I fix all the bugs you report in, add any features you
- * want, or respond to your critics, or respond to your feedback at all.
- * I may be busy, I may be tired of working on QuaZIP, I may be even
- * dead already (you never know...). But regardless of this remark, any
- * feedback is always welcome. This may seem like a paradox to you, but
- * you do not have to understand it to write feedback.
- *
- * To report bugs or to post ideas about what should be done, use
- * SourceForge.net's <a
- * href="http://sourceforge.net/tracker/?group_id=142688">trackers</a>.
- * If you want to send me a private message, use my e-mail address
- * laerel at yandex dot ru (but do not you dare to put it somewhere on
- * the Web or wherever).
- *
- * Do not use e-mail to report bugs, please. Reporting bugs and problems
- * with the SourceForge.net's bug report system has that advantage that
- * it is visible to public.
- *
- * \section other-projects My other projects
- *
- * As of this moment, I did not write any other useful open source
- * software (well, I am too lazy to do it) except for one little thing:
- *
- * <a href="http://brededor.narod.ru/progs/arcanum50patch.htm">Arcanum
- * universal cap remover</a>. Arcanum is the old but very good game,
- * which has one stupid limit: your character maximum level is 50, which
- * is too low for many players including me. So I wrote this simple
- * patch to increase this stupid limit to something acceptable.
- *
- * Also, my first Web project, which can be of any interest to you only
- * if you can read Russian and you are crazy ^_- This is a web site with
- * the main topic of it being The Delirium. It is totally meaningless
- * and it was purposely made to be such. Do not ask me why - I do not
- * know either. I just did that. If you are interested, then welcome to
- * <a href="http://brededor.narod.ru/">The Brededor</a>. It does not get
- * updated lately because I have become even lazier than I ever was. But
- * I do not plan to destroy The Brededor no matter what, because I think
- * it is fun.
- *
- * Copyright (C) 2005-2007 Sergey A. Tachenov
- **/
--- a/misc/quazip/doc/usage.dox	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/** \page usage Usage
- * 
- * This page provides general information on QuaZIP usage. See classes
- * QuaZip and QuaZipFile for the detailed documentation on what can
- * QuaZIP do and what can not. Also, reading comments in the zip.h and
- * unzip.h files (taken from the original ZIP/UNZIP package) is always a
- * good idea too. After all, QuaZIP is just a wrapper with a few
- * convenience extensions and reimplementations.
- *
- * QuaZip is a class representing ZIP archive, QuaZipFile represents a
- * file inside archive and subclasses QIODevice as well.
- *
- * \section terminology Terminology
- *
- * "QuaZIP" means whole this library, while "QuaZip" (not case
- * difference) is just one class in it.
- *
- * "ZIP/UNZIP API" means the original API of the Gilles Vollant's
- * ZIP/UNZIP package. I did not alter it in any way to make it easier to
- * port to the future ZIP/UNZIP versions.
- *
- * "ZIP", "ZIP archive" or "ZIP file" means any ZIP archive. Typically
- * this is a plain file with ".zip" (or ".ZIP") file name suffix.
- *
- * "A file inside archive", "a file inside ZIP" or something like that
- * means file either being read or written from/to some ZIP archive.
- *
- * \section error-handling Error handling
- *
- * Almost any call to ZIP/UNZIP API return some error code. Most of the
- * original API's error checking could be done in this wrapper as well,
- * but it would cause unnecessary code bloating without any benefit. So,
- * QuaZIP only checks for situations that ZIP/UNZIP API can not check
- * for. For example, ZIP/UNZIP API has no "ZIP open mode" concept
- * because read and write modes are completely separated. On the other
- * hand, to avoid creating classes like "QuaZipReader", "QuaZipWriter"
- * or something like that, QuaZIP introduces "ZIP open mode" concept
- * instead, thus making it possible to use one class (QuaZip) for both
- * reading and writing. But this leads to additional open mode checks
- * which are not done in ZIP/UNZIP package.
- *
- * Therefore, error checking is two-level (QuaZIP's level and ZIP/UNZIP
- * API level), which sometimes can be confusing, so here are some
- * advices on how the error checking should be properly done:
- *
- * - Both QuaZip and QuaZipFile have getZipError() function, which return
- *   error code of the last ZIP/UNZIP API call. Most function calls
- *   reset error code to UNZ_OK on success and set error code on
- *   failure. Some functions do not reset error code. Most of them are
- *   \c const and do not access ZIP archive in any way. Some, on the
- *   other hand, \em do access ZIP archive, but do not reset or set
- *   error code. For example, QuaZipFile::pos() function. Such functions
- *   are explicitly marked in the documentation.
- * - Most functions have its own way to report errors, by returning a
- *   null string, negative value or \c false. If such a function returns
- *   error value, call getZipError() to get more information about
- *   error. See "zip.h" and "unzip.h" of the ZIP/UNZIP package for error
- *   codes.
- * - If the function returns error-stating value (like \c false), but
- *   getZipError() returns UNZ_OK, it means that you did something
- *   obviously wrong. For example, tried to write in the archive open
- *   for reading or not open at all. You better just do not do that!
- *   Most functions also issue a warning using qWarning() function in
- *   such cases. See documentation for a specific function for details
- *   on when it should not be called.
- *
- * I know that this is somewhat messy, but I could not find a better way
- * to do all the error handling.
- **/
--- a/misc/quazip/ioapi.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/* ioapi.h -- IO base function header for compress/uncompress .zip
-   files using zlib + zip or unzip API
-
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   Modified by Sergey A. Tachenov to integrate with Qt.
-*/
-
-#ifndef _ZLIBIOAPI_H
-#define _ZLIBIOAPI_H
-
-
-#define ZLIB_FILEFUNC_SEEK_CUR (1)
-#define ZLIB_FILEFUNC_SEEK_END (2)
-#define ZLIB_FILEFUNC_SEEK_SET (0)
-
-#define ZLIB_FILEFUNC_MODE_READ      (1)
-#define ZLIB_FILEFUNC_MODE_WRITE     (2)
-#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
-
-#define ZLIB_FILEFUNC_MODE_EXISTING (4)
-#define ZLIB_FILEFUNC_MODE_CREATE   (8)
-
-
-#ifndef ZCALLBACK
-
-#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
-#define ZCALLBACK CALLBACK
-#else
-#define ZCALLBACK
-#endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode));
-typedef uLong  (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
-typedef uLong  (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
-typedef uLong   (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
-typedef int   (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
-typedef int    (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
-typedef int    (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
-
-typedef struct zlib_filefunc_def_s
-{
-    open_file_func      zopen_file;
-    read_file_func      zread_file;
-    write_file_func     zwrite_file;
-    tell_file_func      ztell_file;
-    seek_file_func      zseek_file;
-    close_file_func     zclose_file;
-    testerror_file_func zerror_file;
-    voidpf              opaque;
-} zlib_filefunc_def;
-
-
-
-void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
-
-#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))
-#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))
-#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))
-#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))
-#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))
-#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
--- a/misc/quazip/qioapi.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/* ioapi.c -- IO base function header for compress/uncompress .zip
-   files using zlib + zip or unzip API
-
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   Modified by Sergey A. Tachenov to integrate with Qt.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "zlib.h"
-#include "ioapi.h"
-#include "quazip_global.h"
-#include <QIODevice>
-
-
-/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
-
-#ifndef SEEK_CUR
-#define SEEK_CUR    1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END    2
-#endif
-
-#ifndef SEEK_SET
-#define SEEK_SET    0
-#endif
-
-voidpf ZCALLBACK qiodevice_open_file_func (
-   voidpf opaque UNUSED,
-   voidpf file,
-   int mode)
-{
-    QIODevice *iodevice = reinterpret_cast<QIODevice*>(file);
-    if(iodevice->isSequential())
-        return NULL;
-    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
-        iodevice->open(QIODevice::ReadOnly);
-    else
-    if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
-        iodevice->open(QIODevice::ReadWrite);
-    else
-    if (mode & ZLIB_FILEFUNC_MODE_CREATE)
-        iodevice->open(QIODevice::WriteOnly);
-
-    if(iodevice->isOpen())
-        return iodevice;
-    else
-        return NULL;
-}
-
-
-uLong ZCALLBACK qiodevice_read_file_func (
-   voidpf opaque UNUSED,
-   voidpf stream,
-   void* buf,
-   uLong size)
-{
-    uLong ret;
-    ret = (uLong)((QIODevice*)stream)->read((char*)buf,size);
-    return ret;
-}
-
-
-uLong ZCALLBACK qiodevice_write_file_func (
-   voidpf opaque UNUSED,
-   voidpf stream,
-   const void* buf,
-   uLong size)
-{
-    uLong ret;
-    ret = (uLong)((QIODevice*)stream)->write((char*)buf,size);
-    return ret;
-}
-
-uLong ZCALLBACK qiodevice_tell_file_func (
-   voidpf opaque UNUSED,
-   voidpf stream)
-{
-    uLong ret;
-    ret = ((QIODevice*)stream)->pos();
-    return ret;
-}
-
-int ZCALLBACK qiodevice_seek_file_func (
-   voidpf opaque UNUSED,
-   voidpf stream,
-   uLong offset,
-   int origin)
-{
-    uLong qiodevice_seek_result=0;
-    int ret;
-    switch (origin)
-    {
-    case ZLIB_FILEFUNC_SEEK_CUR :
-        qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset;
-        break;
-    case ZLIB_FILEFUNC_SEEK_END :
-        qiodevice_seek_result = ((QIODevice*)stream)->size() - offset;
-        break;
-    case ZLIB_FILEFUNC_SEEK_SET :
-        qiodevice_seek_result = offset;
-        break;
-    default: return -1;
-    }
-    ret = !((QIODevice*)stream)->seek(qiodevice_seek_result);
-    return ret;
-}
-
-int ZCALLBACK qiodevice_close_file_func (
-   voidpf opaque UNUSED,
-   voidpf stream)
-{
-    ((QIODevice*)stream)->close();
-    return 0;
-}
-
-int ZCALLBACK qiodevice_error_file_func (
-   voidpf opaque UNUSED,
-   voidpf stream)
-{
-    return !((QIODevice*)stream)->errorString().isEmpty();
-}
-
-void fill_qiodevice_filefunc (
-  zlib_filefunc_def* pzlib_filefunc_def)
-{
-    pzlib_filefunc_def->zopen_file = qiodevice_open_file_func;
-    pzlib_filefunc_def->zread_file = qiodevice_read_file_func;
-    pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func;
-    pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func;
-    pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func;
-    pzlib_filefunc_def->zclose_file = qiodevice_close_file_func;
-    pzlib_filefunc_def->zerror_file = qiodevice_error_file_func;
-    pzlib_filefunc_def->opaque = NULL;
-}
--- a/misc/quazip/quaadler32.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#include "quaadler32.h"
-
-#include "zlib.h"
-
-QuaAdler32::QuaAdler32()
-{
-	reset();
-}
-
-quint32 QuaAdler32::calculate(const QByteArray &data)
-{
-	return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() );
-}
-
-void QuaAdler32::reset()
-{
-	checksum = adler32(0L, Z_NULL, 0);
-}
-
-void QuaAdler32::update(const QByteArray &buf)
-{
-	checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() );
-}
-
-quint32 QuaAdler32::value()
-{
-	return checksum;
-}
--- a/misc/quazip/quaadler32.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-#ifndef QUAADLER32_H
-#define QUAADLER32_H
-
-#include <QByteArray>
-
-#include "quachecksum32.h"
-
-/// Adler32 checksum
-/** \class QuaAdler32 quaadler32.h <quazip/quaadler32.h>
- * This class wrappers the adler32 function with the QuaChecksum32 interface.
- * See QuaChecksum32 for more info.
- */
-class QuaAdler32 : public QuaChecksum32
-{
-
-public:
-	QuaAdler32();
-
-	quint32 calculate(const QByteArray &data);
-
-	void reset();
-	void update(const QByteArray &buf);
-	quint32 value();
-
-private:
-	quint32 checksum;
-};
-
-#endif //QUAADLER32_H
--- a/misc/quazip/quachecksum32.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-#ifndef QUACHECKSUM32_H
-#define QUACHECKSUM32_H
-
-#include <QByteArray>
-#include "quazip_global.h"
-
-/// Checksum interface.
-/** \class QuaChecksum32 quachecksum32.h <quazip/quachecksum32.h>
- * This is an interface for 32 bit checksums.
- * Classes implementing this interface can calcunate a certin
- * checksum in a single step:
- * \code
- * QChecksum32 *crc32 = new QuaCrc32(); 
- * rasoult = crc32->calculate(data);
- * \endcode
- * or by streaming the data:
- * \code
- * QChecksum32 *crc32 = new QuaCrc32(); 
- * while(!fileA.atEnd())
- *     crc32->update(fileA.read(bufSize));
- * resoultA = crc32->value();
- * crc32->reset();
- * while(!fileB.atEnd())
- *     crc32->update(fileB.read(bufSize));
- * resoultB = crc32->value();
- * \endcode
- */
-class QUAZIP_EXPORT QuaChecksum32
-{
-
-public:
-	///Calculates the checksum for data.
-	/** \a data source data
-	 * \return data checksum
-	 *
-	 * This function has no efect on the value returned by value().
-	 */
-	virtual quint32 calculate(const QByteArray &data) = 0;
-
-	///Resets the calculation on a checksun for a stream.
-	virtual void reset() = 0;
-
-	///Updates the calculated checksum for the stream
-	/** \a buf next portion of data from the stream
-	 */
-	virtual void update(const QByteArray &buf) = 0;
-
-	///Value of the checksum calculated for the stream passed throw update().
-	/** \return checksum
-	 */
-	virtual quint32 value() = 0;
-};
-
-#endif //QUACHECKSUM32_H
--- a/misc/quazip/quacrc32.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#include "quacrc32.h"
-
-#include "zlib.h"
-
-QuaCrc32::QuaCrc32()
-{
-	reset();
-}
-
-quint32 QuaCrc32::calculate(const QByteArray &data)
-{
-	return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() );
-}
-
-void QuaCrc32::reset()
-{
-	checksum = crc32(0L, Z_NULL, 0);
-}
-
-void QuaCrc32::update(const QByteArray &buf)
-{
-	checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() );
-}
-
-quint32 QuaCrc32::value()
-{
-	return checksum;
-}
--- a/misc/quazip/quacrc32.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#ifndef QUACRC32_H
-#define QUACRC32_H
-
-#include "quachecksum32.h"
-
-///CRC32 checksum
-/** \class QuaCrc32 quacrc32.h <quazip/quacrc32.h>
-* This class wrappers the crc32 function with the QuaChecksum32 interface.
-* See QuaChecksum32 for more info.
-*/
-class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 {
-
-public:
-	QuaCrc32();
-
-	quint32 calculate(const QByteArray &data);
-
-	void reset();
-	void update(const QByteArray &buf);
-	quint32 value();
-
-private:
-	quint32 checksum;
-};
-
-#endif //QUACRC32_H
--- a/misc/quazip/quazip.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,427 +0,0 @@
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- **/
-
-#include <QFile>
-
-#include "quazip.h"
-
-class QuaZipPrivate {
-  friend class QuaZip;
-  private:
-    QTextCodec *fileNameCodec, *commentCodec;
-    QString zipName;
-    QIODevice *ioDevice;
-    QString comment;
-    QuaZip::Mode mode;
-    union {
-      unzFile unzFile_f;
-      zipFile zipFile_f;
-    };
-    bool hasCurrentFile_f;
-    int zipError;
-    inline QuaZipPrivate():
-      fileNameCodec(QTextCodec::codecForLocale()),
-      commentCodec(QTextCodec::codecForLocale()),
-      ioDevice(NULL),
-      mode(QuaZip::mdNotOpen),
-      hasCurrentFile_f(false),
-      zipError(UNZ_OK) {}
-    inline QuaZipPrivate(const QString &zipName):
-      fileNameCodec(QTextCodec::codecForLocale()),
-      commentCodec(QTextCodec::codecForLocale()),
-      zipName(zipName),
-      ioDevice(NULL),
-      mode(QuaZip::mdNotOpen),
-      hasCurrentFile_f(false),
-      zipError(UNZ_OK) {}
-    inline QuaZipPrivate(QIODevice *ioDevice):
-      fileNameCodec(QTextCodec::codecForLocale()),
-      commentCodec(QTextCodec::codecForLocale()),
-      ioDevice(ioDevice),
-      mode(QuaZip::mdNotOpen),
-      hasCurrentFile_f(false),
-      zipError(UNZ_OK) {}
-};
-
-QuaZip::QuaZip():
-  p(new QuaZipPrivate())
-{
-}
-
-QuaZip::QuaZip(const QString& zipName):
-  p(new QuaZipPrivate(zipName))
-{
-}
-
-QuaZip::QuaZip(QIODevice *ioDevice):
-  p(new QuaZipPrivate(ioDevice))
-{
-}
-
-QuaZip::~QuaZip()
-{
-  if(isOpen())
-    close();
-  delete p;
-}
-
-bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi)
-{
-  p->zipError=UNZ_OK;
-  if(isOpen()) {
-    qWarning("QuaZip::open(): ZIP already opened");
-    return false;
-  }
-  QIODevice *ioDevice = p->ioDevice;
-  if (ioDevice == NULL) {
-    if (p->zipName.isEmpty()) {
-      qWarning("QuaZip::open(): set either ZIP file name or IO device first");
-      return false;
-    } else {
-      ioDevice = new QFile(p->zipName);
-    }
-  }
-  switch(mode) {
-    case mdUnzip:
-      p->unzFile_f=unzOpen2(ioDevice, ioApi);
-      if(p->unzFile_f!=NULL) {
-        p->mode=mode;
-        p->ioDevice = ioDevice;
-        return true;
-      } else {
-        p->zipError=UNZ_OPENERROR;
-        if (!p->zipName.isEmpty())
-          delete ioDevice;
-        return false;
-      }
-    case mdCreate:
-    case mdAppend:
-    case mdAdd:
-      p->zipFile_f=zipOpen2(ioDevice,
-          mode==mdCreate?APPEND_STATUS_CREATE:
-          mode==mdAppend?APPEND_STATUS_CREATEAFTER:
-          APPEND_STATUS_ADDINZIP,
-          NULL,
-          ioApi);
-      if(p->zipFile_f!=NULL) {
-        p->mode=mode;
-        p->ioDevice = ioDevice;
-        return true;
-      } else {
-        p->zipError=UNZ_OPENERROR;
-        if (!p->zipName.isEmpty())
-          delete ioDevice;
-        return false;
-      }
-    default:
-      qWarning("QuaZip::open(): unknown mode: %d", (int)mode);
-      if (!p->zipName.isEmpty())
-        delete ioDevice;
-      return false;
-      break;
-  }
-}
-
-void QuaZip::close()
-{
-  p->zipError=UNZ_OK;
-  switch(p->mode) {
-    case mdNotOpen:
-      qWarning("QuaZip::close(): ZIP is not open");
-      return;
-    case mdUnzip:
-      p->zipError=unzClose(p->unzFile_f);
-      break;
-    case mdCreate:
-    case mdAppend:
-    case mdAdd:
-      p->zipError=zipClose(p->zipFile_f, p->commentCodec->fromUnicode(p->comment).constData());
-      break;
-    default:
-      qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode);
-      return;
-  }
-  // opened by name, need to delete the internal IO device
-  if (!p->zipName.isEmpty())
-    delete p->ioDevice;
-  if(p->zipError==UNZ_OK)
-    p->mode=mdNotOpen;
-}
-
-void QuaZip::setZipName(const QString& zipName)
-{
-  if(isOpen()) {
-    qWarning("QuaZip::setZipName(): ZIP is already open!");
-    return;
-  }
-  p->zipName=zipName;
-  p->ioDevice = NULL;
-}
-
-void QuaZip::setIoDevice(QIODevice *ioDevice)
-{
-  if(isOpen()) {
-    qWarning("QuaZip::setIoDevice(): ZIP is already open!");
-    return;
-  }
-  p->ioDevice = ioDevice;
-  p->zipName = QString();
-}
-
-int QuaZip::getEntriesCount()const
-{
-  QuaZip *fakeThis=(QuaZip*)this; // non-const
-  fakeThis->p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode");
-    return -1;
-  }
-  unz_global_info globalInfo;
-  if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK)
-    return p->zipError;
-  return (int)globalInfo.number_entry;
-}
-
-QString QuaZip::getComment()const
-{
-  QuaZip *fakeThis=(QuaZip*)this; // non-const
-  fakeThis->p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode");
-    return QString();
-  }
-  unz_global_info globalInfo;
-  QByteArray comment;
-  if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK)
-    return QString();
-  comment.resize(globalInfo.size_comment);
-  if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0)
-    return QString();
-  fakeThis->p->zipError = UNZ_OK;
-  return p->commentCodec->toUnicode(comment);
-}
-
-bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs)
-{
-  p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode");
-    return false;
-  }
-  if(fileName.isEmpty()) {
-    p->hasCurrentFile_f=false;
-    return true;
-  }
-  // Unicode-aware reimplementation of the unzLocateFile function
-  if(p->unzFile_f==NULL) {
-    p->zipError=UNZ_PARAMERROR;
-    return false;
-  }
-  if(fileName.length()>MAX_FILE_NAME_LENGTH) {
-    p->zipError=UNZ_PARAMERROR;
-    return false;
-  }
-  bool sens;
-  if(cs==csDefault) {
-#ifdef Q_WS_WIN
-    sens=false;
-#else
-    sens=true;
-#endif
-  } else sens=cs==csSensitive;
-  QString lower, current;
-  if(!sens) lower=fileName.toLower();
-  p->hasCurrentFile_f=false;
-  for(bool more=goToFirstFile(); more; more=goToNextFile()) {
-    current=getCurrentFileName();
-    if(current.isEmpty()) return false;
-    if(sens) {
-      if(current==fileName) break;
-    } else {
-      if(current.toLower()==lower) break;
-    }
-  }
-  return p->hasCurrentFile_f;
-}
-
-bool QuaZip::goToFirstFile()
-{
-  p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
-    return false;
-  }
-  p->zipError=unzGoToFirstFile(p->unzFile_f);
-  p->hasCurrentFile_f=p->zipError==UNZ_OK;
-  return p->hasCurrentFile_f;
-}
-
-bool QuaZip::goToNextFile()
-{
-  p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode");
-    return false;
-  }
-  p->zipError=unzGoToNextFile(p->unzFile_f);
-  p->hasCurrentFile_f=p->zipError==UNZ_OK;
-  if(p->zipError==UNZ_END_OF_LIST_OF_FILE)
-    p->zipError=UNZ_OK;
-  return p->hasCurrentFile_f;
-}
-
-bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const
-{
-  QuaZip *fakeThis=(QuaZip*)this; // non-const
-  fakeThis->p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode");
-    return false;
-  }
-  unz_file_info info_z;
-  QByteArray fileName;
-  QByteArray extra;
-  QByteArray comment;
-  if(info==NULL) return false;
-  if(!isOpen()||!hasCurrentFile()) return false;
-  if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK)
-    return false;
-  fileName.resize(info_z.size_filename);
-  extra.resize(info_z.size_file_extra);
-  comment.resize(info_z.size_file_comment);
-  if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL,
-      fileName.data(), fileName.size(),
-      extra.data(), extra.size(),
-      comment.data(), comment.size()))!=UNZ_OK)
-    return false;
-  info->versionCreated=info_z.version;
-  info->versionNeeded=info_z.version_needed;
-  info->flags=info_z.flag;
-  info->method=info_z.compression_method;
-  info->crc=info_z.crc;
-  info->compressedSize=info_z.compressed_size;
-  info->uncompressedSize=info_z.uncompressed_size;
-  info->diskNumberStart=info_z.disk_num_start;
-  info->internalAttr=info_z.internal_fa;
-  info->externalAttr=info_z.external_fa;
-  info->name=p->fileNameCodec->toUnicode(fileName);
-  info->comment=p->commentCodec->toUnicode(comment);
-  info->extra=extra;
-  info->dateTime=QDateTime(
-      QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday),
-      QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec));
-  return true;
-}
-
-QString QuaZip::getCurrentFileName()const
-{
-  QuaZip *fakeThis=(QuaZip*)this; // non-const
-  fakeThis->p->zipError=UNZ_OK;
-  if(p->mode!=mdUnzip) {
-    qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode");
-    return QString();
-  }
-  if(!isOpen()||!hasCurrentFile()) return QString();
-  QByteArray fileName(MAX_FILE_NAME_LENGTH, 0);
-  if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(),
-      NULL, 0, NULL, 0))!=UNZ_OK)
-    return QString();
-  return p->fileNameCodec->toUnicode(fileName.constData());
-}
-
-void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec)
-{
-  p->fileNameCodec=fileNameCodec;
-}
-
-void QuaZip::setFileNameCodec(const char *fileNameCodecName)
-{
-  p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName);
-}
-
-QTextCodec *QuaZip::getFileNameCodec()const
-{
-  return p->fileNameCodec;
-}
-
-void QuaZip::setCommentCodec(QTextCodec *commentCodec)
-{
-  p->commentCodec=commentCodec;
-}
-
-void QuaZip::setCommentCodec(const char *commentCodecName)
-{
-  p->commentCodec=QTextCodec::codecForName(commentCodecName);
-}
-
-QTextCodec *QuaZip::getCommentCodec()const
-{
-  return p->commentCodec;
-}
-
-QString QuaZip::getZipName() const
-{
-  return p->zipName;
-}
-
-QIODevice *QuaZip::getIoDevice() const
-{
-  if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice
-    return NULL;
-  return p->ioDevice;
-}
-
-QuaZip::Mode QuaZip::getMode()const
-{
-  return p->mode;
-}
-
-bool QuaZip::isOpen()const
-{
-  return p->mode!=mdNotOpen;
-}
-
-int QuaZip::getZipError() const
-{
-  return p->zipError;
-}
-
-void QuaZip::setComment(const QString& comment)
-{
-  p->comment=comment;
-}
-
-bool QuaZip::hasCurrentFile()const
-{
-  return p->hasCurrentFile_f;
-}
-
-unzFile QuaZip::getUnzFile()
-{
-  return p->unzFile_f;
-}
-
-zipFile QuaZip::getZipFile()
-{
-  return p->zipFile_f;
-}
--- a/misc/quazip/quazip.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,359 +0,0 @@
-#ifndef QUA_ZIP_H
-#define QUA_ZIP_H
-
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- **/
-
-#include <QString>
-#include <QTextCodec>
-
-#include "zip.h"
-#include "unzip.h"
-
-#include "quazip_global.h"
-#include "quazipfileinfo.h"
-
-// just in case it will be defined in the later versions of the ZIP/UNZIP
-#ifndef UNZ_OPENERROR
-// define additional error code
-#define UNZ_OPENERROR -1000
-#endif
-
-class QuaZipPrivate;
-
-/// ZIP archive.
-/** \class QuaZip quazip.h <quazip/quazip.h>
- * This class implements basic interface to the ZIP archive. It can be
- * used to read table contents of the ZIP archive and retreiving
- * information about the files inside it.
- *
- * You can also use this class to open files inside archive by passing
- * pointer to the instance of this class to the constructor of the
- * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*)
- * for the possible pitfalls.
- *
- * This class is indended to provide interface to the ZIP subpackage of
- * the ZIP/UNZIP package as well as to the UNZIP subpackage. But
- * currently it supports only UNZIP.
- *
- * The use of this class is simple - just create instance using
- * constructor, then set ZIP archive file name using setFile() function
- * (if you did not passed the name to the constructor), then open() and
- * then use different functions to work with it! Well, if you are
- * paranoid, you may also wish to call close before destructing the
- * instance, to check for errors on close.
- *
- * You may also use getUnzFile() and getZipFile() functions to get the
- * ZIP archive handle and use it with ZIP/UNZIP package API directly.
- *
- * This class supports localized file names inside ZIP archive, but you
- * have to set up proper codec with setCodec() function. By default,
- * locale codec will be used, which is probably ok for UNIX systems, but
- * will almost certainly fail with ZIP archives created in Windows. This
- * is because Windows ZIP programs have strange habit of using DOS
- * encoding for file names in ZIP archives. For example, ZIP archive
- * with cyrillic names created in Windows will have file names in \c
- * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one
- * function is not much trouble, but for true platform independency it
- * would be nice to have some mechanism for file name encoding auto
- * detection using locale information. Does anyone know a good way to do
- * it?
- **/
-class QUAZIP_EXPORT QuaZip {
-  friend class QuaZipPrivate;
-  public:
-    /// Useful constants.
-    enum Constants {
-      MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from
-                                 \c UNZ_MAXFILENAMEINZIP constant in
-                                 unzip.c. */
-    };
-    /// Open mode of the ZIP file.
-    enum Mode {
-      mdNotOpen, ///< ZIP file is not open. This is the initial mode.
-      mdUnzip, ///< ZIP file is open for reading files inside it.
-      mdCreate, ///< ZIP file was created with open() call.
-      mdAppend, /**< ZIP file was opened in append mode. This refers to
-                  * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package
-                  * and means that zip is appended to some existing file
-                  * what is useful when that file contains
-                  * self-extractor code. This is obviously \em not what
-                  * you whant to use to add files to the existing ZIP
-                  * archive.
-                  **/
-      mdAdd ///< ZIP file was opened for adding files in the archive.
-    };
-    /// Case sensitivity for the file names.
-    /** This is what you specify when accessing files in the archive.
-     * Works perfectly fine with any characters thanks to Qt's great
-     * unicode support. This is different from ZIP/UNZIP API, where
-     * only US-ASCII characters was supported.
-     **/
-    enum CaseSensitivity {
-      csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows.
-      csSensitive=1, ///< Case sensitive.
-      csInsensitive=2 ///< Case insensitive.
-    };
-  private:
-    QuaZipPrivate *p;
-    // not (and will not be) implemented
-    QuaZip(const QuaZip& that);
-    // not (and will not be) implemented
-    QuaZip& operator=(const QuaZip& that);
-  public:
-    /// Constructs QuaZip object.
-    /** Call setName() before opening constructed object. */
-    QuaZip();
-    /// Constructs QuaZip object associated with ZIP file \a zipName.
-    QuaZip(const QString& zipName);
-    /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice.
-    /** The IO device must be seekable, otherwise an error will occur when opening. */
-    QuaZip(QIODevice *ioDevice);
-    /// Destroys QuaZip object.
-    /** Calls close() if necessary. */
-    ~QuaZip();
-    /// Opens ZIP file.
-    /**
-     * Argument \a mode specifies open mode of the ZIP archive. See Mode
-     * for details. Note that there is zipOpen2() function in the
-     * ZIP/UNZIP API which accepts \a globalcomment argument, but it
-     * does not use it anywhere, so this open() function does not have this
-     * argument. See setComment() if you need to set global comment.
-     *
-     * If the ZIP file is accessed via explicitly set QIODevice, then
-     * this device is opened in the necessary mode. If the device was
-     * already opened by some other means, then the behaviour is defined by
-     * the device implementation, but generally it is not a very good
-     * idea. For example, QFile will at least issue a warning.
-     *
-     * \return \c true if successful, \c false otherwise.
-     *
-     * \note ZIP/UNZIP API open calls do not return error code - they
-     * just return \c NULL indicating an error. But to make things
-     * easier, quazip.h header defines additional error code \c
-     * UNZ_ERROROPEN and getZipError() will return it if the open call
-     * of the ZIP/UNZIP API returns \c NULL.
-     *
-     * Argument \a ioApi specifies IO function set for ZIP/UNZIP
-     * package to use. See unzip.h, zip.h and ioapi.h for details. Note
-     * that IO API for QuaZip is different from the original package.
-     * The file path argument was changed to be of type \c voidpf, and
-     * QuaZip passes a QIODevice pointer there. This QIODevice is either
-     * set explicitly via setIoDevice() or the QuaZip(QIODevice*)
-     * constructor, or it is created internally when opening the archive
-     * by its file name. The default API (qioapi.cpp) just delegates
-     * everything to the QIODevice API. Not only this allows to use a
-     * QIODevice instead of file name, but also has a nice side effect
-     * of raising the file size limit from 2G to 4G.
-     *
-     * In short: just forget about the \a ioApi argument and you'll be
-     * fine.
-     **/
-    bool open(Mode mode, zlib_filefunc_def *ioApi =NULL);
-    /// Closes ZIP file.
-    /** Call getZipError() to determine if the close was successful. The
-     * underlying QIODevice is also closed, regardless of whether it was
-     * set explicitly or not. */
-    void close();
-    /// Sets the codec used to encode/decode file names inside archive.
-    /** This is necessary to access files in the ZIP archive created
-     * under Windows with non-latin characters in file names. For
-     * example, file names with cyrillic letters will be in \c IBM866
-     * encoding.
-     **/
-    void setFileNameCodec(QTextCodec *fileNameCodec);
-    /// Sets the codec used to encode/decode file names inside archive.
-    /** \overload
-     * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName));
-     **/
-    void setFileNameCodec(const char *fileNameCodecName);
-    /// Returns the codec used to encode/decode comments inside archive.
-    QTextCodec* getFileNameCodec() const;
-    /// Sets the codec used to encode/decode comments inside archive.
-    /** This codec defaults to locale codec, which is probably ok.
-     **/
-    void setCommentCodec(QTextCodec *commentCodec);
-    /// Sets the codec used to encode/decode comments inside archive.
-    /** \overload
-     * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName));
-     **/
-    void setCommentCodec(const char *commentCodecName);
-    /// Returns the codec used to encode/decode comments inside archive.
-    QTextCodec* getCommentCodec() const;
-    /// Returns the name of the ZIP file.
-    /** Returns null string if no ZIP file name has been set, for
-     * example when the QuaZip instance is set up to use a QIODevice
-     * instead.
-     * \sa setZipName(), setIoDevice(), getIoDevice()
-     **/
-    QString getZipName() const;
-    /// Sets the name of the ZIP file.
-    /** Does nothing if the ZIP file is open.
-     *
-     * Does not reset error code returned by getZipError().
-     * \sa setIoDevice(), getIoDevice(), getZipName()
-     **/
-    void setZipName(const QString& zipName);
-    /// Returns the device representing this ZIP file.
-    /** Returns null string if no device has been set explicitly, for
-     * example when opening a ZIP file by name.
-     * \sa setIoDevice(), getZipName(), setZipName()
-     **/
-    QIODevice *getIoDevice() const;
-    /// Sets the device representing the ZIP file.
-    /** Does nothing if the ZIP file is open.
-     *
-     * Does not reset error code returned by getZipError().
-     * \sa getIoDevice(), getZipName(), setZipName()
-     **/
-    void setIoDevice(QIODevice *ioDevice);
-    /// Returns the mode in which ZIP file was opened.
-    Mode getMode() const;
-    /// Returns \c true if ZIP file is open, \c false otherwise.
-    bool isOpen() const;
-    /// Returns the error code of the last operation.
-    /** Returns \c UNZ_OK if the last operation was successful.
-     *
-     * Error code resets to \c UNZ_OK every time you call any function
-     * that accesses something inside ZIP archive, even if it is \c
-     * const (like getEntriesCount()). open() and close() calls reset
-     * error code too. See documentation for the specific functions for
-     * details on error detection.
-     **/
-    int getZipError() const;
-    /// Returns number of the entries in the ZIP central directory.
-    /** Returns negative error code in the case of error. The same error
-     * code will be returned by subsequent getZipError() call.
-     **/
-    int getEntriesCount() const;
-    /// Returns global comment in the ZIP file.
-    QString getComment() const;
-    /// Sets global comment in the ZIP file.
-    /** Comment will be written to the archive on close operation.
-     *
-     * \sa open()
-     **/
-    void setComment(const QString& comment);
-    /// Sets the current file to the first file in the archive.
-    /** Returns \c true on success, \c false otherwise. Call
-     * getZipError() to get the error code.
-     **/
-    bool goToFirstFile();
-    /// Sets the current file to the next file in the archive.
-    /** Returns \c true on success, \c false otherwise. Call
-     * getZipError() to determine if there was an error.
-     *
-     * Should be used only in QuaZip::mdUnzip mode.
-     *
-     * \note If the end of file was reached, getZipError() will return
-     * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make
-     * things like this easier:
-     * \code
-     * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
-     *   // do something
-     * }
-     * if(zip.getZipError()==UNZ_OK) {
-     *   // ok, there was no error
-     * }
-     * \endcode
-     **/
-    bool goToNextFile();
-    /// Sets current file by its name.
-    /** Returns \c true if successful, \c false otherwise. Argument \a
-     * cs specifies case sensitivity of the file name. Call
-     * getZipError() in the case of a failure to get error code.
-     *
-     * This is not a wrapper to unzLocateFile() function. That is
-     * because I had to implement locale-specific case-insensitive
-     * comparison.
-     *
-     * Here are the differences from the original implementation:
-     *
-     * - If the file was not found, error code is \c UNZ_OK, not \c
-     *   UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()).
-     * - If this function fails, it unsets the current file rather than
-     *   resetting it back to what it was before the call.
-     *
-     * If \a fileName is null string then this function unsets the
-     * current file and return \c true. Note that you should close the
-     * file first if it is open! See
-     * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details.
-     *
-     * Should be used only in QuaZip::mdUnzip mode.
-     *
-     * \sa setFileNameCodec(), CaseSensitivity
-     **/
-    bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault);
-    /// Returns \c true if the current file has been set.
-    bool hasCurrentFile() const;
-    /// Retrieves information about the current file.
-    /** Fills the structure pointed by \a info. Returns \c true on
-     * success, \c false otherwise. In the latter case structure pointed
-     * by \a info remains untouched. If there was an error,
-     * getZipError() returns error code.
-     *
-     * Should be used only in QuaZip::mdUnzip mode.
-     *
-     * Does nothing and returns \c false in any of the following cases.
-     * - ZIP is not open;
-     * - ZIP does not have current file;
-     * - \a info is \c NULL;
-     *
-     * In all these cases getZipError() returns \c UNZ_OK since there
-     * is no ZIP/UNZIP API call.
-     **/
-    bool getCurrentFileInfo(QuaZipFileInfo* info)const;
-    /// Returns the current file name.
-    /** Equivalent to calling getCurrentFileInfo() and then getting \c
-     * name field of the QuaZipFileInfo structure, but faster and more
-     * convenient.
-     *
-     * Should be used only in QuaZip::mdUnzip mode.
-     **/
-    QString getCurrentFileName()const;
-    /// Returns \c unzFile handle.
-    /** You can use this handle to directly call UNZIP part of the
-     * ZIP/UNZIP package functions (see unzip.h).
-     *
-     * \warning When using the handle returned by this function, please
-     * keep in mind that QuaZip class is unable to detect any changes
-     * you make in the ZIP file state (e. g. changing current file, or
-     * closing the handle). So please do not do anything with this
-     * handle that is possible to do with the functions of this class.
-     * Or at least return the handle in the original state before
-     * calling some another function of this class (including implicit
-     * destructor calls and calls from the QuaZipFile objects that refer
-     * to this QuaZip instance!). So if you have changed the current
-     * file in the ZIP archive - then change it back or you may
-     * experience some strange behavior or even crashes.
-     **/
-    unzFile getUnzFile();
-    /// Returns \c zipFile handle.
-    /** You can use this handle to directly call ZIP part of the
-     * ZIP/UNZIP package functions (see zip.h). Warnings about the
-     * getUnzFile() function also apply to this function.
-     **/
-    zipFile getZipFile();
-};
-
-#endif
--- a/misc/quazip/quazip.pri	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-INCLUDEPATH += $$PWD
-DEPENDPATH += $$PWD
-HEADERS += $$PWD/crypt.h \
-           $$PWD/ioapi.h \
-           $$PWD/JlCompress.h \
-           $$PWD/quaadler32.h \
-           $$PWD/quachecksum32.h \
-           $$PWD/quacrc32.h \
-           $$PWD/quazip.h \
-           $$PWD/quazipfile.h \
-           $$PWD/quazipfileinfo.h \
-           $$PWD/quazipnewinfo.h \
-           $$PWD/unzip.h \
-           $$PWD/zip.h
-SOURCES += $$PWD/qioapi.cpp \
-           $$PWD/JlCompress.cpp \
-           $$PWD/quaadler32.cpp \
-           $$PWD/quacrc32.cpp \
-           $$PWD/quazip.cpp \
-           $$PWD/quazipfile.cpp \
-           $$PWD/quazipnewinfo.cpp \
-           $$PWD/unzip.c \
-           $$PWD/zip.c
--- a/misc/quazip/quazip.pro	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-TEMPLATE = lib
-CONFIG += qt warn_on
-QT -= gui
-DEPENDPATH += .
-INCLUDEPATH += .
-
-# Input
-HEADERS += \
-    crypt.h\
-    ioapi.h\
-    JlCompress.h\
-    quaadler32.h\
-    quachecksum32.h\
-    quacrc32.h\
-    quazip.h\
-    quazipfile.h\
-    quazipfileinfo.h\
-    quazipnewinfo.h\
-    quazip_global.h\
-    unzip.h\
-    zip.h\
-
-SOURCES += *.c *.cpp
-
-unix:!symbian {
-    headers.path=$$PREFIX/include/quazip
-    headers.files=$$HEADERS
-    target.path=$$PREFIX/lib
-    INSTALLS += headers target
-
-	OBJECTS_DIR=.obj
-	MOC_DIR=.moc
-	
-	LIBS += -lz
-}
-
-win32 {
-    headers.path=$$PREFIX/include/quazip
-    headers.files=$$HEADERS
-    target.path=$$PREFIX/lib
-    INSTALLS += headers target
-
-    *-g++*: LIBS += -lz.dll
-    *-msvc*: LIBS += -lzlib
-    *-msvc*: QMAKE_LFLAGS += /IMPLIB:$$DESTDIR\\quazip.lib
-}
-
-
-symbian {
-
-    # Note, on Symbian you may run into troubles with LGPL.
-    # The point is, if your application uses some version of QuaZip,
-    # and a newer binary compatible version of QuaZip is released, then
-    # the users of your application must be able to relink it with the
-    # new QuaZip version. For example, to take advantage of some QuaZip
-    # bug fixes.
-
-    # This is probably best achieved by building QuaZip as a static
-    # library and providing linkable object files of your application,
-    # so users can relink it.
-
-    CONFIG += staticlib
-    CONFIG += debug_and_release
-
-    LIBS += -lezip
-
-    #Export headers to SDK Epoc32/include directory
-    exportheaders.sources = $$HEADERS
-    exportheaders.path = quazip
-    for(header, exportheaders.sources) {
-        BLD_INF_RULES.prj_exports += "$$header $$exportheaders.path/$$basename(header)"
-    }
-}
-
-
-
-DEFINES += QUAZIP_BUILD
--- a/misc/quazip/quazip_global.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/**
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- */
-
-#ifndef QUAZIP_GLOBAL_H
-#define QUAZIP_GLOBAL_H
-
-#include <QtCore/qglobal.h>
-/**
- * When building the library with MSVC, QUAZIP_BUILD must be defined.
- * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc.
- */
-
-#define QUAZIP_EXPORT
-
-#ifdef __GNUC__
-#define UNUSED __attribute__((__unused__))
-#else
-#define UNUSED
-#endif
-
-#endif // QUAZIP_GLOBAL_H
--- a/misc/quazip/quazipfile.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,428 +0,0 @@
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- **/
-
-#include "quazipfile.h"
-
-using namespace std;
-
-class QuaZipFilePrivate {
-  friend class QuaZipFile;
-  private:
-    QuaZipFile *q;
-    QuaZip *zip;
-    QString fileName;
-    QuaZip::CaseSensitivity caseSensitivity;
-    bool raw;
-    qint64 writePos;
-    // these two are for writing raw files
-    ulong uncompressedSize;
-    quint32 crc;
-    bool internal;
-    int zipError;
-    inline void resetZipError() const {setZipError(UNZ_OK);}
-    // const, but sets zipError!
-    void setZipError(int zipError) const;
-    inline QuaZipFilePrivate(QuaZipFile *q):
-      q(q), zip(NULL), internal(true), zipError(UNZ_OK) {}
-    inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName):
-      q(q), internal(true), zipError(UNZ_OK)
-      {
-        zip=new QuaZip(zipName);
-      }
-    inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName,
-        QuaZip::CaseSensitivity cs):
-      q(q), internal(true), zipError(UNZ_OK)
-      {
-        zip=new QuaZip(zipName);
-        this->fileName=fileName;
-        this->caseSensitivity=cs;
-      }
-    inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip):
-      q(q), zip(zip), internal(false), zipError(UNZ_OK) {}
-    inline ~QuaZipFilePrivate()
-    {
-      if (internal)
-        delete zip;
-    }
-};
-
-QuaZipFile::QuaZipFile():
-  p(new QuaZipFilePrivate(this))
-{
-}
-
-QuaZipFile::QuaZipFile(QObject *parent):
-  QIODevice(parent),
-  p(new QuaZipFilePrivate(this))
-{
-}
-
-QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent):
-  QIODevice(parent),
-  p(new QuaZipFilePrivate(this, zipName))
-{
-}
-
-QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName,
-    QuaZip::CaseSensitivity cs, QObject *parent):
-  QIODevice(parent),
-  p(new QuaZipFilePrivate(this, zipName, fileName, cs))
-{
-}
-
-QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent):
-  QIODevice(parent),
-  p(new QuaZipFilePrivate(this, zip))
-{
-}
-
-QuaZipFile::~QuaZipFile()
-{
-  if (isOpen())
-    close();
-  delete p;
-}
-
-QString QuaZipFile::getZipName() const
-{
-  return p->zip==NULL ? QString() : p->zip->getZipName();
-}
-
-QString QuaZipFile::getActualFileName()const
-{
-  p->setZipError(UNZ_OK);
-  if (p->zip == NULL || (openMode() & WriteOnly))
-    return QString();
-  QString name=p->zip->getCurrentFileName();
-  if(name.isNull())
-    p->setZipError(p->zip->getZipError());
-  return name;
-}
-
-void QuaZipFile::setZipName(const QString& zipName)
-{
-  if(isOpen()) {
-    qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name");
-    return;
-  }
-  if(p->zip!=NULL && p->internal)
-    delete p->zip;
-  p->zip=new QuaZip(zipName);
-  p->internal=true;
-}
-
-void QuaZipFile::setZip(QuaZip *zip)
-{
-  if(isOpen()) {
-    qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP");
-    return;
-  }
-  if(p->zip!=NULL && p->internal)
-    delete p->zip;
-  p->zip=zip;
-  p->fileName=QString();
-  p->internal=false;
-}
-
-void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs)
-{
-  if(p->zip==NULL) {
-    qWarning("QuaZipFile::setFileName(): call setZipName() first");
-    return;
-  }
-  if(!p->internal) {
-    qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip");
-    return;
-  }
-  if(isOpen()) {
-    qWarning("QuaZipFile::setFileName(): can not set file name for already opened file");
-    return;
-  }
-  p->fileName=fileName;
-  p->caseSensitivity=cs;
-}
-
-void QuaZipFilePrivate::setZipError(int zipError) const
-{
-  QuaZipFilePrivate *fakeThis = const_cast<QuaZipFilePrivate*>(this); // non-const
-  fakeThis->zipError=zipError;
-  if(zipError==UNZ_OK)
-    q->setErrorString(QString());
-  else
-    q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError));
-}
-
-bool QuaZipFile::open(OpenMode mode)
-{
-  return open(mode, NULL);
-}
-
-bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password)
-{
-  p->resetZipError();
-  if(isOpen()) {
-    qWarning("QuaZipFile::open(): already opened");
-    return false;
-  }
-  if(mode&Unbuffered) {
-    qWarning("QuaZipFile::open(): Unbuffered mode is not supported");
-    return false;
-  }
-  if((mode&ReadOnly)&&!(mode&WriteOnly)) {
-    if(p->internal) {
-      if(!p->zip->open(QuaZip::mdUnzip)) {
-        p->setZipError(p->zip->getZipError());
-        return false;
-      }
-      if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) {
-        p->setZipError(p->zip->getZipError());
-        p->zip->close();
-        return false;
-      }
-    } else {
-      if(p->zip==NULL) {
-        qWarning("QuaZipFile::open(): zip is NULL");
-        return false;
-      }
-      if(p->zip->getMode()!=QuaZip::mdUnzip) {
-        qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
-            (int)mode, (int)p->zip->getMode());
-        return false;
-      }
-      if(!p->zip->hasCurrentFile()) {
-        qWarning("QuaZipFile::open(): zip does not have current file");
-        return false;
-      }
-    }
-    p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password));
-    if(p->zipError==UNZ_OK) {
-      setOpenMode(mode);
-      p->raw=raw;
-      return true;
-    } else
-      return false;
-  }
-  qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
-  return false;
-}
-
-bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info,
-    const char *password, quint32 crc,
-    int method, int level, bool raw,
-    int windowBits, int memLevel, int strategy)
-{
-  zip_fileinfo info_z;
-  p->resetZipError();
-  if(isOpen()) {
-    qWarning("QuaZipFile::open(): already opened");
-    return false;
-  }
-  if((mode&WriteOnly)&&!(mode&ReadOnly)) {
-    if(p->internal) {
-      qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach");
-      return false;
-    }
-    if(p->zip==NULL) {
-      qWarning("QuaZipFile::open(): zip is NULL");
-      return false;
-    }
-    if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) {
-      qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d",
-          (int)mode, (int)p->zip->getMode());
-      return false;
-    }
-    info_z.tmz_date.tm_year=info.dateTime.date().year();
-    info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1;
-    info_z.tmz_date.tm_mday=info.dateTime.date().day();
-    info_z.tmz_date.tm_hour=info.dateTime.time().hour();
-    info_z.tmz_date.tm_min=info.dateTime.time().minute();
-    info_z.tmz_date.tm_sec=info.dateTime.time().second();
-    info_z.dosDate = 0;
-    info_z.internal_fa=(uLong)info.internalAttr;
-    info_z.external_fa=(uLong)info.externalAttr;
-    p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(),
-          p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z,
-          info.extraLocal.constData(), info.extraLocal.length(),
-          info.extraGlobal.constData(), info.extraGlobal.length(),
-          p->zip->getCommentCodec()->fromUnicode(info.comment).constData(),
-          method, level, (int)raw,
-          windowBits, memLevel, strategy,
-          password, (uLong)crc));
-    if(p->zipError==UNZ_OK) {
-      p->writePos=0;
-      setOpenMode(mode);
-      p->raw=raw;
-      if(raw) {
-        p->crc=crc;
-        p->uncompressedSize=info.uncompressedSize;
-      }
-      return true;
-    } else
-      return false;
-  }
-  qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode);
-  return false;
-}
-
-bool QuaZipFile::isSequential()const
-{
-  return true;
-}
-
-qint64 QuaZipFile::pos()const
-{
-  if(p->zip==NULL) {
-    qWarning("QuaZipFile::pos(): call setZipName() or setZip() first");
-    return -1;
-  }
-  if(!isOpen()) {
-    qWarning("QuaZipFile::pos(): file is not open");
-    return -1;
-  }
-  if(openMode()&ReadOnly)
-    return unztell(p->zip->getUnzFile());
-  else
-    return p->writePos;
-}
-
-bool QuaZipFile::atEnd()const
-{
-  if(p->zip==NULL) {
-    qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first");
-    return false;
-  }
-  if(!isOpen()) {
-    qWarning("QuaZipFile::atEnd(): file is not open");
-    return false;
-  }
-  if(openMode()&ReadOnly)
-    return unzeof(p->zip->getUnzFile())==1;
-  else
-    return true;
-}
-
-qint64 QuaZipFile::size()const
-{
-  if(!isOpen()) {
-    qWarning("QuaZipFile::atEnd(): file is not open");
-    return -1;
-  }
-  if(openMode()&ReadOnly)
-    return p->raw?csize():usize();
-  else
-    return p->writePos;
-}
-
-qint64 QuaZipFile::csize()const
-{
-  unz_file_info info_z;
-  p->setZipError(UNZ_OK);
-  if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
-  p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
-  if(p->zipError!=UNZ_OK)
-    return -1;
-  return info_z.compressed_size;
-}
-
-qint64 QuaZipFile::usize()const
-{
-  unz_file_info info_z;
-  p->setZipError(UNZ_OK);
-  if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1;
-  p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0));
-  if(p->zipError!=UNZ_OK)
-    return -1;
-  return info_z.uncompressed_size;
-}
-
-bool QuaZipFile::getFileInfo(QuaZipFileInfo *info)
-{
-  if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false;
-  p->zip->getCurrentFileInfo(info);
-  p->setZipError(p->zip->getZipError());
-  return p->zipError==UNZ_OK;
-}
-
-void QuaZipFile::close()
-{
-  p->resetZipError();
-  if(p->zip==NULL||!p->zip->isOpen()) return;
-  if(!isOpen()) {
-    qWarning("QuaZipFile::close(): file isn't open");
-    return;
-  }
-  if(openMode()&ReadOnly)
-    p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile()));
-  else if(openMode()&WriteOnly)
-    if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc));
-    else p->setZipError(zipCloseFileInZip(p->zip->getZipFile()));
-  else {
-    qWarning("Wrong open mode: %d", (int)openMode());
-    return;
-  }
-  if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen);
-  else return;
-  if(p->internal) {
-    p->zip->close();
-    p->setZipError(p->zip->getZipError());
-  }
-}
-
-qint64 QuaZipFile::readData(char *data, qint64 maxSize)
-{
-  p->setZipError(UNZ_OK);
-  qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize);
-  if(bytesRead<0) p->setZipError((int)bytesRead);
-  return bytesRead;
-}
-
-qint64 QuaZipFile::writeData(const char* data, qint64 maxSize)
-{
-  p->setZipError(ZIP_OK);
-  p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize));
-  if(p->zipError!=ZIP_OK) return -1;
-  else {
-    p->writePos+=maxSize;
-    return maxSize;
-  }
-}
-
-QString QuaZipFile::getFileName() const
-{
-  return p->fileName;
-}
-
-QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const
-{
-  return p->caseSensitivity;
-}
-
-bool QuaZipFile::isRaw() const
-{
-  return p->raw;
-}
-
-int QuaZipFile::getZipError() const
-{
-  return p->zipError;
-}
--- a/misc/quazip/quazipfile.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,433 +0,0 @@
-#ifndef QUA_ZIPFILE_H
-#define QUA_ZIPFILE_H
-
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- **/
-
-#include <QIODevice>
-
-#include "quazip_global.h"
-#include "quazip.h"
-#include "quazipnewinfo.h"
-
-class QuaZipFilePrivate;
-
-/// A file inside ZIP archive.
-/** \class QuaZipFile quazipfile.h <quazip/quazipfile.h>
- * This is the most interesting class. Not only it provides C++
- * interface to the ZIP/UNZIP package, but also integrates it with Qt by
- * subclassing QIODevice. This makes possible to access files inside ZIP
- * archive using QTextStream or QDataStream, for example. Actually, this
- * is the main purpose of the whole QuaZIP library.
- *
- * You can either use existing QuaZip instance to create instance of
- * this class or pass ZIP archive file name to this class, in which case
- * it will create internal QuaZip object. See constructors' descriptions
- * for details. Writing is only possible with the existing instance.
- *
- * Note that due to the underlying library's limitation it is not
- * possible to use multiple QuaZipFile instances to open several files
- * in the same archive at the same time. If you need to write to
- * multiple files in parallel, then you should write to temporary files
- * first, then pack them all at once when you have finished writing. If
- * you need to read multiple files inside the same archive in parallel,
- * you should extract them all into a temporary directory first.
- *
- * \section quazipfile-sequential Sequential or random-access?
- *
- * At the first thought, QuaZipFile has fixed size, the start and the
- * end and should be therefore considered random-access device. But
- * there is one major obstacle to making it random-access: ZIP/UNZIP API
- * does not support seek() operation and the only way to implement it is
- * through reopening the file and re-reading to the required position,
- * but this is prohibitively slow.
- *
- * Therefore, QuaZipFile is considered to be a sequential device. This
- * has advantage of availability of the ungetChar() operation (QIODevice
- * does not implement it properly for non-sequential devices unless they
- * support seek()). Disadvantage is a somewhat strange behaviour of the
- * size() and pos() functions. This should be kept in mind while using
- * this class.
- *
- **/
-class QUAZIP_EXPORT QuaZipFile: public QIODevice {
-  friend class QuaZipFilePrivate;
-  Q_OBJECT
-  private:
-    QuaZipFilePrivate *p;
-    // these are not supported nor implemented
-    QuaZipFile(const QuaZipFile& that);
-    QuaZipFile& operator=(const QuaZipFile& that);
-  protected:
-    /// Implementation of the QIODevice::readData().
-    qint64 readData(char *data, qint64 maxSize);
-    /// Implementation of the QIODevice::writeData().
-    qint64 writeData(const char *data, qint64 maxSize);
-  public:
-    /// Constructs a QuaZipFile instance.
-    /** You should use setZipName() and setFileName() or setZip() before
-     * trying to call open() on the constructed object.
-     **/
-    QuaZipFile();
-    /// Constructs a QuaZipFile instance.
-    /** \a parent argument specifies this object's parent object.
-     *
-     * You should use setZipName() and setFileName() or setZip() before
-     * trying to call open() on the constructed object.
-     **/
-    QuaZipFile(QObject *parent);
-    /// Constructs a QuaZipFile instance.
-    /** \a parent argument specifies this object's parent object and \a
-     * zipName specifies ZIP archive file name.
-     *
-     * You should use setFileName() before trying to call open() on the
-     * constructed object.
-     *
-     * QuaZipFile constructed by this constructor can be used for read
-     * only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
-     **/
-    QuaZipFile(const QString& zipName, QObject *parent =NULL);
-    /// Constructs a QuaZipFile instance.
-    /** \a parent argument specifies this object's parent object, \a
-     * zipName specifies ZIP archive file name and \a fileName and \a cs
-     * specify a name of the file to open inside archive.
-     *
-     * QuaZipFile constructed by this constructor can be used for read
-     * only access. Use QuaZipFile(QuaZip*,QObject*) for writing.
-     *
-     * \sa QuaZip::setCurrentFile()
-     **/
-    QuaZipFile(const QString& zipName, const QString& fileName,
-        QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL);
-    /// Constructs a QuaZipFile instance.
-    /** \a parent argument specifies this object's parent object.
-     *
-     * \a zip is the pointer to the existing QuaZip object. This
-     * QuaZipFile object then can be used to read current file in the
-     * \a zip or to write to the file inside it.
-     *
-     * \warning Using this constructor for reading current file can be
-     * tricky. Let's take the following example:
-     * \code
-     * QuaZip zip("archive.zip");
-     * zip.open(QuaZip::mdUnzip);
-     * zip.setCurrentFile("file-in-archive");
-     * QuaZipFile file(&zip);
-     * file.open(QIODevice::ReadOnly);
-     * // ok, now we can read from the file
-     * file.read(somewhere, some);
-     * zip.setCurrentFile("another-file-in-archive"); // oops...
-     * QuaZipFile anotherFile(&zip);
-     * anotherFile.open(QIODevice::ReadOnly);
-     * anotherFile.read(somewhere, some); // this is still ok...
-     * file.read(somewhere, some); // and this is NOT
-     * \endcode
-     * So, what exactly happens here? When we change current file in the
-     * \c zip archive, \c file that references it becomes invalid
-     * (actually, as far as I understand ZIP/UNZIP sources, it becomes
-     * closed, but QuaZipFile has no means to detect it).
-     *
-     * Summary: do not close \c zip object or change its current file as
-     * long as QuaZipFile is open. Even better - use another constructors
-     * which create internal QuaZip instances, one per object, and
-     * therefore do not cause unnecessary trouble. This constructor may
-     * be useful, though, if you already have a QuaZip instance and do
-     * not want to access several files at once. Good example:
-     * \code
-     * QuaZip zip("archive.zip");
-     * zip.open(QuaZip::mdUnzip);
-     * // first, we need some information about archive itself
-     * QByteArray comment=zip.getComment();
-     * // and now we are going to access files inside it
-     * QuaZipFile file(&zip);
-     * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) {
-     *   file.open(QIODevice::ReadOnly);
-     *   // do something cool with file here
-     *   file.close(); // do not forget to close!
-     * }
-     * zip.close();
-     * \endcode
-     **/
-    QuaZipFile(QuaZip *zip, QObject *parent =NULL);
-    /// Destroys a QuaZipFile instance.
-    /** Closes file if open, destructs internal QuaZip object (if it
-     * exists and \em is internal, of course).
-     **/
-    virtual ~QuaZipFile();
-    /// Returns the ZIP archive file name.
-    /** If this object was created by passing QuaZip pointer to the
-     * constructor, this function will return that QuaZip's file name
-     * (or null string if that object does not have file name yet).
-     *
-     * Otherwise, returns associated ZIP archive file name or null
-     * string if there are no name set yet.
-     *
-     * \sa setZipName() getFileName()
-     **/
-    QString getZipName()const;
-    /// Returns a pointer to the associated QuaZip object.
-    /** Returns \c NULL if there is no associated QuaZip or it is
-     * internal (so you will not mess with it).
-     **/
-    QuaZip* getZip()const;
-    /// Returns file name.
-    /** This function returns file name you passed to this object either
-     * by using
-     * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
-     * or by calling setFileName(). Real name of the file may differ in
-     * case if you used case-insensitivity.
-     *
-     * Returns null string if there is no file name set yet. This is the
-     * case when this QuaZipFile operates on the existing QuaZip object
-     * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used).
-     * 
-     * \sa getActualFileName
-     **/
-    QString getFileName() const;
-    /// Returns case sensitivity of the file name.
-    /** This function returns case sensitivity argument you passed to
-     * this object either by using
-     * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*)
-     * or by calling setFileName().
-     *
-     * Returns unpredictable value if getFileName() returns null string
-     * (this is the case when you did not used setFileName() or
-     * constructor above).
-     *
-     * \sa getFileName
-     **/
-    QuaZip::CaseSensitivity getCaseSensitivity() const;
-    /// Returns the actual file name in the archive.
-    /** This is \em not a ZIP archive file name, but a name of file inside
-     * archive. It is not necessary the same name that you have passed
-     * to the
-     * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*),
-     * setFileName() or QuaZip::setCurrentFile() - this is the real file
-     * name inside archive, so it may differ in case if the file name
-     * search was case-insensitive.
-     *
-     * Equivalent to calling getCurrentFileName() on the associated
-     * QuaZip object. Returns null string if there is no associated
-     * QuaZip object or if it does not have a current file yet. And this
-     * is the case if you called setFileName() but did not open the
-     * file yet. So this is perfectly fine:
-     * \code
-     * QuaZipFile file("somezip.zip");
-     * file.setFileName("somefile");
-     * QString name=file.getName(); // name=="somefile"
-     * QString actual=file.getActualFileName(); // actual is null string
-     * file.open(QIODevice::ReadOnly);
-     * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows
-     * \endcode
-     *
-     * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity
-     **/
-    QString getActualFileName()const;
-    /// Sets the ZIP archive file name.
-    /** Automatically creates internal QuaZip object and destroys
-     * previously created internal QuaZip object, if any.
-     *
-     * Will do nothing if this file is already open. You must close() it
-     * first.
-     **/
-    void setZipName(const QString& zipName);
-    /// Returns \c true if the file was opened in raw mode.
-    /** If the file is not open, the returned value is undefined.
-     *
-     * \sa open(OpenMode,int*,int*,bool,const char*)
-     **/
-    bool isRaw() const;
-    /// Binds to the existing QuaZip instance.
-    /** This function destroys internal QuaZip object, if any, and makes
-     * this QuaZipFile to use current file in the \a zip object for any
-     * further operations. See QuaZipFile(QuaZip*,QObject*) for the
-     * possible pitfalls.
-     *
-     * Will do nothing if the file is currently open. You must close()
-     * it first.
-     **/
-    void setZip(QuaZip *zip);
-    /// Sets the file name.
-    /** Will do nothing if at least one of the following conditions is
-     * met:
-     * - ZIP name has not been set yet (getZipName() returns null
-     *   string).
-     * - This QuaZipFile is associated with external QuaZip. In this
-     *   case you should call that QuaZip's setCurrentFile() function
-     *   instead!
-     * - File is already open so setting the name is meaningless.
-     *
-     * \sa QuaZip::setCurrentFile
-     **/
-    void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault);
-    /// Opens a file for reading.
-    /** Returns \c true on success, \c false otherwise.
-     * Call getZipError() to get error code.
-     *
-     * \note Since ZIP/UNZIP API provides buffered reading only,
-     * QuaZipFile does not support unbuffered reading. So do not pass
-     * QIODevice::Unbuffered flag in \a mode, or open will fail.
-     **/
-    virtual bool open(OpenMode mode);
-    /// Opens a file for reading.
-    /** \overload
-     * Argument \a password specifies a password to decrypt the file. If
-     * it is NULL then this function behaves just like open(OpenMode).
-     **/
-    inline bool open(OpenMode mode, const char *password)
-    {return open(mode, NULL, NULL, false, password);}
-    /// Opens a file for reading.
-    /** \overload
-     * Argument \a password specifies a password to decrypt the file.
-     *
-     * An integers pointed by \a method and \a level will receive codes
-     * of the compression method and level used. See unzip.h.
-     *
-     * If raw is \c true then no decompression is performed.
-     *
-     * \a method should not be \c NULL. \a level can be \c NULL if you
-     * don't want to know the compression level.
-     **/
-    bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL);
-    /// Opens a file for writing.
-    /** \a info argument specifies information about file. It should at
-     * least specify a correct file name. Also, it is a good idea to
-     * specify correct timestamp (by default, current time will be
-     * used). See QuaZipNewInfo.
-     *
-     * Arguments \a password and \a crc provide necessary information
-     * for crypting. Note that you should specify both of them if you
-     * need crypting. If you do not, pass \c NULL as password, but you
-     * still need to specify \a crc if you are going to use raw mode
-     * (see below).
-     *
-     * Arguments \a method and \a level specify compression method and
-     * level.
-     *
-     * If \a raw is \c true, no compression is performed. In this case,
-     * \a crc and uncompressedSize field of the \a info are required.
-     *
-     * Arguments \a windowBits, \a memLevel, \a strategy provide zlib
-     * algorithms tuning. See deflateInit2() in zlib.
-     **/
-    bool open(OpenMode mode, const QuaZipNewInfo& info,
-        const char *password =NULL, quint32 crc =0,
-        int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false,
-        int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY);
-    /// Returns \c true, but \ref quazipfile-sequential "beware"!
-    virtual bool isSequential()const;
-    /// Returns current position in the file.
-    /** Implementation of the QIODevice::pos(). When reading, this
-     * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is
-     * unable to keep track of the ungetChar() calls (which is
-     * non-virtual and therefore is dangerous to reimplement). So if you
-     * are using ungetChar() feature of the QIODevice, this function
-     * reports incorrect value until you get back characters which you
-     * ungot.
-     *
-     * When writing, pos() returns number of bytes already written
-     * (uncompressed unless you use raw mode).
-     *
-     * \note Although
-     * \ref quazipfile-sequential "QuaZipFile is a sequential device"
-     * and therefore pos() should always return zero, it does not,
-     * because it would be misguiding. Keep this in mind.
-     *
-     * This function returns -1 if the file or archive is not open.
-     *
-     * Error code returned by getZipError() is not affected by this
-     * function call.
-     **/
-    virtual qint64 pos()const;
-    /// Returns \c true if the end of file was reached.
-    /** This function returns \c false in the case of error. This means
-     * that you called this function on either not open file, or a file
-     * in the not open archive or even on a QuaZipFile instance that
-     * does not even have QuaZip instance associated. Do not do that
-     * because there is no means to determine whether \c false is
-     * returned because of error or because end of file was reached.
-     * Well, on the other side you may interpret \c false return value
-     * as "there is no file open to check for end of file and there is
-     * no end of file therefore".
-     *
-     * When writing, this function always returns \c true (because you
-     * are always writing to the end of file).
-     *
-     * Error code returned by getZipError() is not affected by this
-     * function call.
-     **/
-    virtual bool atEnd()const;
-    /// Returns file size.
-    /** This function returns csize() if the file is open for reading in
-     * raw mode, usize() if it is open for reading in normal mode and
-     * pos() if it is open for writing.
-     *
-     * Returns -1 on error, call getZipError() to get error code.
-     *
-     * \note This function returns file size despite that
-     * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device",
-     * for which size() should return bytesAvailable() instead. But its
-     * name would be very misguiding otherwise, so just keep in mind
-     * this inconsistence.
-     **/
-    virtual qint64 size()const;
-    /// Returns compressed file size.
-    /** Equivalent to calling getFileInfo() and then getting
-     * compressedSize field, but more convenient and faster.
-     *
-     * File must be open for reading before calling this function.
-     *
-     * Returns -1 on error, call getZipError() to get error code.
-     **/
-    qint64 csize()const;
-    /// Returns uncompressed file size.
-    /** Equivalent to calling getFileInfo() and then getting
-     * uncompressedSize field, but more convenient and faster. See
-     * getFileInfo() for a warning.
-     *
-     * File must be open for reading before calling this function.
-     *
-     * Returns -1 on error, call getZipError() to get error code.
-     **/
-    qint64 usize()const;
-    /// Gets information about current file.
-    /** This function does the same thing as calling
-     * QuaZip::getCurrentFileInfo() on the associated QuaZip object,
-     * but you can not call getCurrentFileInfo() if the associated
-     * QuaZip is internal (because you do not have access to it), while
-     * you still can call this function in that case.
-     *
-     * File must be open for reading before calling this function.
-     *
-     * Returns \c false in the case of an error.
-     **/
-    bool getFileInfo(QuaZipFileInfo *info);
-    /// Closes the file.
-    /** Call getZipError() to determine if the close was successful.
-     **/
-    virtual void close();
-    /// Returns the error code returned by the last ZIP/UNZIP API call.
-    int getZipError() const;
-};
-
-#endif
--- a/misc/quazip/quazipfileinfo.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-#ifndef QUA_ZIPFILEINFO_H
-#define QUA_ZIPFILEINFO_H
-
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- **/
-
-#include <QByteArray>
-#include <QDateTime>
-
-#include "quazip_global.h"
-
-/// Information about a file inside archive.
-/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to
- * fill this structure. */
-struct QUAZIP_EXPORT QuaZipFileInfo {
-  /// File name.
-  QString name;
-  /// Version created by.
-  quint16 versionCreated;
-  /// Version needed to extract.
-  quint16 versionNeeded;
-  /// General purpose flags.
-  quint16 flags;
-  /// Compression method.
-  quint16 method;
-  /// Last modification date and time.
-  QDateTime dateTime;
-  /// CRC.
-  quint32 crc;
-  /// Compressed file size.
-  quint32 compressedSize;
-  /// Uncompressed file size.
-  quint32 uncompressedSize;
-  /// Disk number start.
-  quint16 diskNumberStart;
-  /// Internal file attributes.
-  quint16 internalAttr;
-  /// External file attributes.
-  quint32 externalAttr;
-  /// Comment.
-  QString comment;
-  /// Extra field.
-  QByteArray extra;
-};
-
-#endif
--- a/misc/quazip/quazipnewinfo.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
-*/
-
-#include <QFileInfo>
-
-#include "quazipnewinfo.h"
-
-
-QuaZipNewInfo::QuaZipNewInfo(const QString& name):
-  name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0)
-{
-}
-
-QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file):
-  name(name), internalAttr(0), externalAttr(0)
-{
-  QFileInfo info(file);
-  QDateTime lm = info.lastModified();
-  if (!info.exists())
-    dateTime = QDateTime::currentDateTime();
-  else
-    dateTime = lm;
-}
-
-void QuaZipNewInfo::setFileDateTime(const QString& file)
-{
-  QFileInfo info(file);
-  QDateTime lm = info.lastModified();
-  if (info.exists())
-    dateTime = lm;
-}
--- a/misc/quazip/quazipnewinfo.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-#ifndef QUA_ZIPNEWINFO_H
-#define QUA_ZIPNEWINFO_H
-
-/*
-Copyright (C) 2005-2011 Sergey A. Tachenov
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-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 Lesser
-General Public License for more details.
-
-You should have received a copy of the GNU Lesser 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
-
-See COPYING file for the full LGPL text.
-
-Original ZIP package is copyrighted by Gilles Vollant, see
-quazip/(un)zip.h files for details, basically it's zlib license.
- **/
-
-#include <QDateTime>
-#include <QString>
-
-#include "quazip_global.h"
-
-/// Information about a file to be created.
-/** This structure holds information about a file to be created inside
- * ZIP archive. At least name should be set to something correct before
- * passing this structure to
- * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool).
- **/
-struct QUAZIP_EXPORT QuaZipNewInfo {
-  /// File name.
-  /** This field holds file name inside archive, including path relative
-   * to archive root.
-   **/
-  QString name;
-  /// File timestamp.
-  /** This is the last file modification date and time. Will be stored
-   * in the archive central directory. It is a good practice to set it
-   * to the source file timestamp instead of archive creating time. Use
-   * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&).
-   **/
-  QDateTime dateTime;
-  /// File internal attributes.
-  quint16 internalAttr;
-  /// File external attributes.
-  quint32 externalAttr;
-  /// File comment.
-  /** Will be encoded using QuaZip::getCommentCodec().
-   **/
-  QString comment;
-  /// File local extra field.
-  QByteArray extraLocal;
-  /// File global extra field.
-  QByteArray extraGlobal;
-  /// Uncompressed file size.
-  /** This is only needed if you are using raw file zipping mode, i. e.
-   * adding precompressed file in the zip archive.
-   **/
-  ulong uncompressedSize;
-  /// Constructs QuaZipNewInfo instance.
-  /** Initializes name with \a name, dateTime with current date and
-   * time. Attributes are initialized with zeros, comment and extra
-   * field with null values.
-   **/
-  QuaZipNewInfo(const QString& name);
-  /// Constructs QuaZipNewInfo instance.
-  /** Initializes name with \a name and dateTime with timestamp of the
-   * file named \a file. If the \a file does not exists or its timestamp
-   * is inaccessible (e. g. you do not have read permission for the
-   * directory file in), uses current date and time. Attributes are
-   * initialized with zeros, comment and extra field with null values.
-   * 
-   * \sa setFileDateTime()
-   **/
-  QuaZipNewInfo(const QString& name, const QString& file);
-  /// Sets the file timestamp from the existing file.
-  /** Use this function to set the file timestamp from the existing
-   * file. Use it like this:
-   * \code
-   * QuaZipFile zipFile(&zip);
-   * QFile file("file-to-add");
-   * file.open(QIODevice::ReadOnly);
-   * QuaZipNewInfo info("file-name-in-archive");
-   * info.setFileDateTime("file-to-add"); // take the timestamp from file
-   * zipFile.open(QIODevice::WriteOnly, info);
-   * \endcode
-   *
-   * This function does not change dateTime if some error occured (e. g.
-   * file is inaccessible).
-   **/
-  void setFileDateTime(const QString& file);
-};
-
-#endif
--- a/misc/quazip/unzip.c	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1603 +0,0 @@
-/* unzip.c -- IO for uncompress .zip files using zlib
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   Read unzip.h for more info
-
-   Modified by Sergey A. Tachenov to integrate with Qt.
-*/
-
-/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
-compatibility with older software. The following is from the original crypt.c. Code
-woven in by Terry Thorsen 1/2003.
-*/
-/*
-  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
-
-  See the accompanying file LICENSE, version 2000-Apr-09 or later
-  (the contents of which are also included in zip.h) for terms of use.
-  If, for some reason, all these files are missing, the Info-ZIP license
-  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
-*/
-/*
-  crypt.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]
-
-  The encryption/decryption parts of this source code (as opposed to the
-  non-echoing password parts) were originally written in Europe.  The
-  whole source package can be freely distributed, including from the USA.
-  (Prior to January 2000, re-export from the US was a violation of US law.)
- */
-
-/*
-  This encryption code is a direct transcription of the algorithm from
-  Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
-  file (appnote.txt) is distributed with the PKZIP program (even in the
-  version without encryption capabilities).
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "zlib.h"
-#include "unzip.h"
-
-#ifdef STDC
-#  include <stddef.h>
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#ifdef NO_ERRNO_H
-    extern int errno;
-#else
-#   include <errno.h>
-#endif
-
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-
-#ifndef CASESENSITIVITYDEFAULT_NO
-#  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
-#    define CASESENSITIVITYDEFAULT_NO
-#  endif
-#endif
-
-
-#ifndef UNZ_BUFSIZE
-#define UNZ_BUFSIZE (16384)
-#endif
-
-#ifndef UNZ_MAXFILENAMEINZIP
-#define UNZ_MAXFILENAMEINZIP (256)
-#endif
-
-#ifndef ALLOC
-# define ALLOC(size) (malloc(size))
-#endif
-#ifndef TRYFREE
-# define TRYFREE(p) {if (p) free(p);}
-#endif
-
-#define SIZECENTRALDIRITEM (0x2e)
-#define SIZEZIPLOCALHEADER (0x1e)
-
-
-
-
-const char unz_copyright[] =
-   " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
-
-/* unz_file_info_interntal contain internal info about a file in zipfile*/
-typedef struct unz_file_info_internal_s
-{
-    uLong offset_curfile;/* relative offset of local header 4 bytes */
-} unz_file_info_internal;
-
-
-/* file_in_zip_read_info_s contain internal information about a file in zipfile,
-    when reading and decompress it */
-typedef struct
-{
-    char  *read_buffer;         /* internal buffer for compressed data */
-    z_stream stream;            /* zLib stream structure for inflate */
-
-    uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
-    uLong stream_initialised;   /* flag set if stream structure is initialised*/
-
-    uLong offset_local_extrafield;/* offset of the local extra field */
-    uInt  size_local_extrafield;/* size of the local extra field */
-    uLong pos_local_extrafield;   /* position in the local extra field in read*/
-
-    uLong crc32;                /* crc32 of all data uncompressed */
-    uLong crc32_wait;           /* crc32 we must obtain after decompress all */
-    uLong rest_read_compressed; /* number of byte to be decompressed */
-    uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
-    zlib_filefunc_def z_filefunc;
-    voidpf filestream;        /* io structore of the zipfile */
-    uLong compression_method;   /* compression method (0==store) */
-    uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
-    int   raw;
-} file_in_zip_read_info_s;
-
-
-/* unz_s contain internal information about the zipfile
-*/
-typedef struct
-{
-    zlib_filefunc_def z_filefunc;
-    voidpf filestream;        /* io structore of the zipfile */
-    unz_global_info gi;       /* public global information */
-    uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
-    uLong num_file;             /* number of the current file in the zipfile*/
-    uLong pos_in_central_dir;   /* pos of the current file in the central dir*/
-    uLong current_file_ok;      /* flag about the usability of the current file*/
-    uLong central_pos;          /* position of the beginning of the central dir*/
-
-    uLong size_central_dir;     /* size of the central directory  */
-    uLong offset_central_dir;   /* offset of start of central directory with
-                                   respect to the starting disk number */
-
-    unz_file_info cur_file_info; /* public info about the current file in zip*/
-    unz_file_info_internal cur_file_info_internal; /* private info about it*/
-    file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
-                                        file if we are decompressing it */
-    int encrypted;
-#    ifndef NOUNCRYPT
-    unsigned long keys[3];     /* keys defining the pseudo-random sequence */
-    const unsigned long* pcrc_32_tab;
-#    endif
-} unz_s;
-
-
-#ifndef NOUNCRYPT
-#include "crypt.h"
-#endif
-
-/* ===========================================================================
-     Read a byte from a gz_stream; update next_in and avail_in. Return EOF
-   for end of file.
-   IN assertion: the stream s has been sucessfully opened for reading.
-*/
-
-
-local int unzlocal_getByte OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream,
-    int *pi));
-
-local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    int *pi;
-{
-    unsigned char c;
-    int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);
-    if (err==1)
-    {
-        *pi = (int)c;
-        return UNZ_OK;
-    }
-    else
-    {
-        if (ZERROR(*pzlib_filefunc_def,filestream))
-            return UNZ_ERRNO;
-        else
-            return UNZ_EOF;
-    }
-}
-
-
-/* ===========================================================================
-   Reads a long in LSB order from the given gz_stream. Sets
-*/
-local int unzlocal_getShort OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream,
-    uLong *pX));
-
-local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    uLong *pX;
-{
-    uLong x ;
-    int i;
-    int err;
-
-    err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x = (uLong)i;
-
-    if (err==UNZ_OK)
-        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<8;
-
-    if (err==UNZ_OK)
-        *pX = x;
-    else
-        *pX = 0;
-    return err;
-}
-
-local int unzlocal_getLong OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream,
-    uLong *pX));
-
-local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    uLong *pX;
-{
-    uLong x ;
-    int i;
-    int err;
-
-    err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x = (uLong)i;
-
-    if (err==UNZ_OK)
-        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<8;
-
-    if (err==UNZ_OK)
-        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<16;
-
-    if (err==UNZ_OK)
-        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<24;
-
-    if (err==UNZ_OK)
-        *pX = x;
-    else
-        *pX = 0;
-    return err;
-}
-
-
-/* My own strcmpi / strcasecmp */
-local int strcmpcasenosensitive_internal (fileName1,fileName2)
-    const char* fileName1;
-    const char* fileName2;
-{
-    for (;;)
-    {
-        char c1=*(fileName1++);
-        char c2=*(fileName2++);
-        if ((c1>='a') && (c1<='z'))
-            c1 -= 0x20;
-        if ((c2>='a') && (c2<='z'))
-            c2 -= 0x20;
-        if (c1=='\0')
-            return ((c2=='\0') ? 0 : -1);
-        if (c2=='\0')
-            return 1;
-        if (c1<c2)
-            return -1;
-        if (c1>c2)
-            return 1;
-    }
-}
-
-
-#ifdef  CASESENSITIVITYDEFAULT_NO
-#define CASESENSITIVITYDEFAULTVALUE 2
-#else
-#define CASESENSITIVITYDEFAULTVALUE 1
-#endif
-
-#ifndef STRCMPCASENOSENTIVEFUNCTION
-#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
-#endif
-
-/*
-   Compare two filename (fileName1,fileName2).
-   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
-   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
-                                                                or strcasecmp)
-   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
-        (like 1 on Unix, 2 on Windows)
-
-*/
-extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
-    const char* fileName1;
-    const char* fileName2;
-    int iCaseSensitivity;
-{
-    if (iCaseSensitivity==0)
-        iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
-
-    if (iCaseSensitivity==1)
-        return strcmp(fileName1,fileName2);
-
-    return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
-}
-
-#ifndef BUFREADCOMMENT
-#define BUFREADCOMMENT (0x400)
-#endif
-
-/*
-  Locate the Central directory of a zipfile (at the end, just before
-    the global comment)
-*/
-local uLong unzlocal_SearchCentralDir OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream));
-
-local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-{
-    unsigned char* buf;
-    uLong uSizeFile;
-    uLong uBackRead;
-    uLong uMaxBack=0xffff; /* maximum size of global comment */
-    uLong uPosFound=0;
-
-    if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
-        return 0;
-
-
-    uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
-
-    if (uMaxBack>uSizeFile)
-        uMaxBack = uSizeFile;
-
-    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
-    if (buf==NULL)
-        return 0;
-
-    uBackRead = 4;
-    while (uBackRead<uMaxBack)
-    {
-        uLong uReadSize,uReadPos ;
-        int i;
-        if (uBackRead+BUFREADCOMMENT>uMaxBack)
-            uBackRead = uMaxBack;
-        else
-            uBackRead+=BUFREADCOMMENT;
-        uReadPos = uSizeFile-uBackRead ;
-
-        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
-                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
-        if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
-            break;
-
-        if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
-            break;
-
-        for (i=(int)uReadSize-3; (i--)>0;)
-            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
-                ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
-            {
-                uPosFound = uReadPos+i;
-                break;
-            }
-
-        if (uPosFound!=0)
-            break;
-    }
-    TRYFREE(buf);
-    return uPosFound;
-}
-
-/*
-  Open a Zip file. path contain the full pathname (by example,
-     on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
-     "zlib/zlib114.zip".
-     If the zipfile cannot be opened (file doesn't exist or in not valid), the
-       return value is NULL.
-     Else, the return value is a unzFile Handle, usable with other function
-       of this unzip package.
-*/
-extern unzFile ZEXPORT unzOpen2 (file, pzlib_filefunc_def)
-    voidpf file;
-    zlib_filefunc_def* pzlib_filefunc_def;
-{
-    unz_s us;
-    unz_s *s;
-    uLong central_pos,uL;
-
-    uLong number_disk;          /* number of the current dist, used for
-                                   spaning ZIP, unsupported, always 0*/
-    uLong number_disk_with_CD;  /* number the the disk with central dir, used
-                                   for spaning ZIP, unsupported, always 0*/
-    uLong number_entry_CD;      /* total number of entries in
-                                   the central dir
-                                   (same than number_entry on nospan) */
-
-    int err=UNZ_OK;
-
-    if (unz_copyright[0]!=' ')
-        return NULL;
-
-    if (pzlib_filefunc_def==NULL)
-        fill_qiodevice_filefunc(&us.z_filefunc);
-    else
-        us.z_filefunc = *pzlib_filefunc_def;
-
-    us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque,
-                                                 file,
-                                                 ZLIB_FILEFUNC_MODE_READ |
-                                                 ZLIB_FILEFUNC_MODE_EXISTING);
-    if (us.filestream==NULL)
-        return NULL;
-
-    central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream);
-    if (central_pos==0)
-        err=UNZ_ERRNO;
-
-    if (ZSEEK(us.z_filefunc, us.filestream,
-                                      central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
-        err=UNZ_ERRNO;
-
-    /* the signature, already checked */
-    if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    /* number of this disk */
-    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    /* number of the disk with the start of the central directory */
-    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    /* total number of entries in the central dir on this disk */
-    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    /* total number of entries in the central dir */
-    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if ((number_entry_CD!=us.gi.number_entry) ||
-        (number_disk_with_CD!=0) ||
-        (number_disk!=0))
-        err=UNZ_BADZIPFILE;
-
-    /* size of the central directory */
-    if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    /* offset of start of central directory with respect to the
-          starting disk number */
-    if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    /* zipfile comment length */
-    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
-        (err==UNZ_OK))
-        err=UNZ_BADZIPFILE;
-
-    if (err!=UNZ_OK)
-    {
-        ZCLOSE(us.z_filefunc, us.filestream);
-        return NULL;
-    }
-
-    us.byte_before_the_zipfile = central_pos -
-                            (us.offset_central_dir+us.size_central_dir);
-    us.central_pos = central_pos;
-    us.pfile_in_zip_read = NULL;
-    us.encrypted = 0;
-
-
-    s=(unz_s*)ALLOC(sizeof(unz_s));
-    *s=us;
-    unzGoToFirstFile((unzFile)s);
-    return (unzFile)s;
-}
-
-
-extern unzFile ZEXPORT unzOpen (file)
-    voidpf file;
-{
-    return unzOpen2(file, NULL);
-}
-
-/*
-  Close a ZipFile opened with unzipOpen.
-  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
-    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
-  return UNZ_OK if there is no problem. */
-extern int ZEXPORT unzClose (file)
-    unzFile file;
-{
-    unz_s* s;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-
-    if (s->pfile_in_zip_read!=NULL)
-        unzCloseCurrentFile(file);
-
-    ZCLOSE(s->z_filefunc, s->filestream);
-    TRYFREE(s);
-    return UNZ_OK;
-}
-
-
-/*
-  Write info about the ZipFile in the *pglobal_info structure.
-  No preparation of the structure is needed
-  return UNZ_OK if there is no problem. */
-extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
-    unzFile file;
-    unz_global_info *pglobal_info;
-{
-    unz_s* s;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    *pglobal_info=s->gi;
-    return UNZ_OK;
-}
-
-
-/*
-   Translate date/time from Dos format to tm_unz (readable more easilty)
-*/
-local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
-    uLong ulDosDate;
-    tm_unz* ptm;
-{
-    uLong uDate;
-    uDate = (uLong)(ulDosDate>>16);
-    ptm->tm_mday = (uInt)(uDate&0x1f) ;
-    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;
-    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
-
-    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
-    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;
-    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;
-}
-
-/*
-  Get Info about the current file in the zipfile, with internal only info
-*/
-local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
-                                                  unz_file_info *pfile_info,
-                                                  unz_file_info_internal
-                                                  *pfile_info_internal,
-                                                  char *szFileName,
-                                                  uLong fileNameBufferSize,
-                                                  void *extraField,
-                                                  uLong extraFieldBufferSize,
-                                                  char *szComment,
-                                                  uLong commentBufferSize));
-
-local int unzlocal_GetCurrentFileInfoInternal (file,
-                                              pfile_info,
-                                              pfile_info_internal,
-                                              szFileName, fileNameBufferSize,
-                                              extraField, extraFieldBufferSize,
-                                              szComment,  commentBufferSize)
-    unzFile file;
-    unz_file_info *pfile_info;
-    unz_file_info_internal *pfile_info_internal;
-    char *szFileName;
-    uLong fileNameBufferSize;
-    void *extraField;
-    uLong extraFieldBufferSize;
-    char *szComment;
-    uLong commentBufferSize;
-{
-    unz_s* s;
-    unz_file_info file_info;
-    unz_file_info_internal file_info_internal;
-    int err=UNZ_OK;
-    uLong uMagic;
-    uLong uSeek=0;
-
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    if (ZSEEK(s->z_filefunc, s->filestream,
-              s->pos_in_central_dir+s->byte_before_the_zipfile,
-              ZLIB_FILEFUNC_SEEK_SET)!=0)
-        err=UNZ_ERRNO;
-
-
-    /* we check the magic */
-    if (err==UNZ_OK) {
-        if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
-            err=UNZ_ERRNO;
-        else if (uMagic!=0x02014b50)
-            err=UNZ_BADZIPFILE;
-    }
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    uSeek+=file_info.size_filename;
-    if ((err==UNZ_OK) && (szFileName!=NULL))
-    {
-        uLong uSizeRead ;
-        if (file_info.size_filename<fileNameBufferSize)
-        {
-            *(szFileName+file_info.size_filename)='\0';
-            uSizeRead = file_info.size_filename;
-        }
-        else
-            uSizeRead = fileNameBufferSize;
-
-        if ((file_info.size_filename>0) && (fileNameBufferSize>0))
-            if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
-                err=UNZ_ERRNO;
-        uSeek -= uSizeRead;
-    }
-
-
-    if ((err==UNZ_OK) && (extraField!=NULL))
-    {
-        uLong uSizeRead ;
-        if (file_info.size_file_extra<extraFieldBufferSize)
-            uSizeRead = file_info.size_file_extra;
-        else
-            uSizeRead = extraFieldBufferSize;
-
-        if (uSeek!=0) {
-            if (ZSEEK(s->z_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
-                uSeek=0;
-            else
-                err=UNZ_ERRNO;
-        }
-        if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
-            if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)
-                err=UNZ_ERRNO;
-        uSeek += file_info.size_file_extra - uSizeRead;
-    }
-    else
-        uSeek+=file_info.size_file_extra;
-
-
-    if ((err==UNZ_OK) && (szComment!=NULL))
-    {
-        uLong uSizeRead ;
-        if (file_info.size_file_comment<commentBufferSize)
-        {
-            *(szComment+file_info.size_file_comment)='\0';
-            uSizeRead = file_info.size_file_comment;
-        }
-        else
-            uSizeRead = commentBufferSize;
-
-        if (uSeek!=0) {
-            if (ZSEEK(s->z_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
-                uSeek=0;
-            else
-                err=UNZ_ERRNO;
-        }
-        if ((file_info.size_file_comment>0) && (commentBufferSize>0))
-            if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
-                err=UNZ_ERRNO;
-        uSeek+=file_info.size_file_comment - uSizeRead;
-    }
-    else
-        uSeek+=file_info.size_file_comment;
-
-    if ((err==UNZ_OK) && (pfile_info!=NULL))
-        *pfile_info=file_info;
-
-    if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
-        *pfile_info_internal=file_info_internal;
-
-    return err;
-}
-
-
-
-/*
-  Write info about the ZipFile in the *pglobal_info structure.
-  No preparation of the structure is needed
-  return UNZ_OK if there is no problem.
-*/
-extern int ZEXPORT unzGetCurrentFileInfo (file,
-                                          pfile_info,
-                                          szFileName, fileNameBufferSize,
-                                          extraField, extraFieldBufferSize,
-                                          szComment,  commentBufferSize)
-    unzFile file;
-    unz_file_info *pfile_info;
-    char *szFileName;
-    uLong fileNameBufferSize;
-    void *extraField;
-    uLong extraFieldBufferSize;
-    char *szComment;
-    uLong commentBufferSize;
-{
-    return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
-                                                szFileName,fileNameBufferSize,
-                                                extraField,extraFieldBufferSize,
-                                                szComment,commentBufferSize);
-}
-
-/*
-  Set the current file of the zipfile to the first file.
-  return UNZ_OK if there is no problem
-*/
-extern int ZEXPORT unzGoToFirstFile (file)
-    unzFile file;
-{
-    int err=UNZ_OK;
-    unz_s* s;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    s->pos_in_central_dir=s->offset_central_dir;
-    s->num_file=0;
-    err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
-                                             &s->cur_file_info_internal,
-                                             NULL,0,NULL,0,NULL,0);
-    s->current_file_ok = (err == UNZ_OK);
-    return err;
-}
-
-/*
-  Set the current file of the zipfile to the next file.
-  return UNZ_OK if there is no problem
-  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
-*/
-extern int ZEXPORT unzGoToNextFile (file)
-    unzFile file;
-{
-    unz_s* s;
-    int err;
-
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    if (!s->current_file_ok)
-        return UNZ_END_OF_LIST_OF_FILE;
-    if (s->gi.number_entry != 0xffff)    /* 2^16 files overflow hack */
-      if (s->num_file+1==s->gi.number_entry)
-        return UNZ_END_OF_LIST_OF_FILE;
-
-    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
-            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
-    s->num_file++;
-    err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
-                                               &s->cur_file_info_internal,
-                                               NULL,0,NULL,0,NULL,0);
-    s->current_file_ok = (err == UNZ_OK);
-    return err;
-}
-
-
-/*
-  Try locate the file szFileName in the zipfile.
-  For the iCaseSensitivity signification, see unzipStringFileNameCompare
-
-  return value :
-  UNZ_OK if the file is found. It becomes the current file.
-  UNZ_END_OF_LIST_OF_FILE if the file is not found
-*/
-extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
-    unzFile file;
-    const char *szFileName;
-    int iCaseSensitivity;
-{
-    unz_s* s;
-    int err;
-
-    /* We remember the 'current' position in the file so that we can jump
-     * back there if we fail.
-     */
-    unz_file_info cur_file_infoSaved;
-    unz_file_info_internal cur_file_info_internalSaved;
-    uLong num_fileSaved;
-    uLong pos_in_central_dirSaved;
-
-
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-
-    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
-        return UNZ_PARAMERROR;
-
-    s=(unz_s*)file;
-    if (!s->current_file_ok)
-        return UNZ_END_OF_LIST_OF_FILE;
-
-    /* Save the current state */
-    num_fileSaved = s->num_file;
-    pos_in_central_dirSaved = s->pos_in_central_dir;
-    cur_file_infoSaved = s->cur_file_info;
-    cur_file_info_internalSaved = s->cur_file_info_internal;
-
-    err = unzGoToFirstFile(file);
-
-    while (err == UNZ_OK)
-    {
-        char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
-        err = unzGetCurrentFileInfo(file,NULL,
-                                    szCurrentFileName,sizeof(szCurrentFileName)-1,
-                                    NULL,0,NULL,0);
-        if (err == UNZ_OK)
-        {
-            if (unzStringFileNameCompare(szCurrentFileName,
-                                            szFileName,iCaseSensitivity)==0)
-                return UNZ_OK;
-            err = unzGoToNextFile(file);
-        }
-    }
-
-    /* We failed, so restore the state of the 'current file' to where we
-     * were.
-     */
-    s->num_file = num_fileSaved ;
-    s->pos_in_central_dir = pos_in_central_dirSaved ;
-    s->cur_file_info = cur_file_infoSaved;
-    s->cur_file_info_internal = cur_file_info_internalSaved;
-    return err;
-}
-
-
-/*
-///////////////////////////////////////////
-// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
-// I need random access
-//
-// Further optimization could be realized by adding an ability
-// to cache the directory in memory. The goal being a single
-// comprehensive file read to put the file I need in a memory.
-*/
-
-/*
-typedef struct unz_file_pos_s
-{
-    uLong pos_in_zip_directory;   // offset in file
-    uLong num_of_file;            // # of file
-} unz_file_pos;
-*/
-
-extern int ZEXPORT unzGetFilePos(file, file_pos)
-    unzFile file;
-    unz_file_pos* file_pos;
-{
-    unz_s* s;
-
-    if (file==NULL || file_pos==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    if (!s->current_file_ok)
-        return UNZ_END_OF_LIST_OF_FILE;
-
-    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
-    file_pos->num_of_file           = s->num_file;
-
-    return UNZ_OK;
-}
-
-extern int ZEXPORT unzGoToFilePos(file, file_pos)
-    unzFile file;
-    unz_file_pos* file_pos;
-{
-    unz_s* s;
-    int err;
-
-    if (file==NULL || file_pos==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-
-    /* jump to the right spot */
-    s->pos_in_central_dir = file_pos->pos_in_zip_directory;
-    s->num_file           = file_pos->num_of_file;
-
-    /* set the current file */
-    err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
-                                               &s->cur_file_info_internal,
-                                               NULL,0,NULL,0,NULL,0);
-    /* return results */
-    s->current_file_ok = (err == UNZ_OK);
-    return err;
-}
-
-/*
-// Unzip Helper Functions - should be here?
-///////////////////////////////////////////
-*/
-
-/*
-  Read the local header of the current zipfile
-  Check the coherency of the local header and info in the end of central
-        directory about this file
-  store in *piSizeVar the size of extra info in local header
-        (filename and size of extra field data)
-*/
-local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
-                                                    poffset_local_extrafield,
-                                                    psize_local_extrafield)
-    unz_s* s;
-    uInt* piSizeVar;
-    uLong *poffset_local_extrafield;
-    uInt  *psize_local_extrafield;
-{
-    uLong uMagic,uData,uFlags;
-    uLong size_filename;
-    uLong size_extra_field;
-    int err=UNZ_OK;
-
-    *piSizeVar = 0;
-    *poffset_local_extrafield = 0;
-    *psize_local_extrafield = 0;
-
-    if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
-                                s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
-        return UNZ_ERRNO;
-
-
-    if (err==UNZ_OK) {
-        if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
-            err=UNZ_ERRNO;
-        else if (uMagic!=0x04034b50)
-            err=UNZ_BADZIPFILE;
-    }
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
-        err=UNZ_ERRNO;
-/*
-    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
-        err=UNZ_BADZIPFILE;
-*/
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
-        err=UNZ_ERRNO;
-    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
-        err=UNZ_BADZIPFILE;
-
-    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
-                         (s->cur_file_info.compression_method!=Z_DEFLATED))
-        err=UNZ_BADZIPFILE;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
-        err=UNZ_ERRNO;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
-        err=UNZ_ERRNO;
-    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
-                              ((uFlags & 8)==0))
-        err=UNZ_BADZIPFILE;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
-        err=UNZ_ERRNO;
-    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
-                              ((uFlags & 8)==0))
-        err=UNZ_BADZIPFILE;
-
-    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
-        err=UNZ_ERRNO;
-    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
-                              ((uFlags & 8)==0))
-        err=UNZ_BADZIPFILE;
-
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
-        err=UNZ_ERRNO;
-    else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
-        err=UNZ_BADZIPFILE;
-
-    *piSizeVar += (uInt)size_filename;
-
-    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
-        err=UNZ_ERRNO;
-    *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
-                                    SIZEZIPLOCALHEADER + size_filename;
-    *psize_local_extrafield = (uInt)size_extra_field;
-
-    *piSizeVar += (uInt)size_extra_field;
-
-    return err;
-}
-
-/*
-  Open for reading data the current file in the zipfile.
-  If there is no error and the file is opened, the return value is UNZ_OK.
-*/
-extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)
-    unzFile file;
-    int* method;
-    int* level;
-    int raw;
-    const char* password;
-{
-    int err=UNZ_OK;
-    uInt iSizeVar;
-    unz_s* s;
-    file_in_zip_read_info_s* pfile_in_zip_read_info;
-    uLong offset_local_extrafield;  /* offset of the local extra field */
-    uInt  size_local_extrafield;    /* size of the local extra field */
-#    ifndef NOUNCRYPT
-    char source[12];
-#    else
-    if (password != NULL)
-        return UNZ_PARAMERROR;
-#    endif
-
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    if (!s->current_file_ok)
-        return UNZ_PARAMERROR;
-
-    if (s->pfile_in_zip_read != NULL)
-        unzCloseCurrentFile(file);
-
-    if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
-                &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
-        return UNZ_BADZIPFILE;
-
-    pfile_in_zip_read_info = (file_in_zip_read_info_s*)
-                                        ALLOC(sizeof(file_in_zip_read_info_s));
-    if (pfile_in_zip_read_info==NULL)
-        return UNZ_INTERNALERROR;
-
-    pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
-    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
-    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
-    pfile_in_zip_read_info->pos_local_extrafield=0;
-    pfile_in_zip_read_info->raw=raw;
-
-    if (pfile_in_zip_read_info->read_buffer==NULL)
-    {
-        TRYFREE(pfile_in_zip_read_info);
-        return UNZ_INTERNALERROR;
-    }
-
-    pfile_in_zip_read_info->stream_initialised=0;
-
-    if (method!=NULL)
-        *method = (int)s->cur_file_info.compression_method;
-
-    if (level!=NULL)
-    {
-        *level = 6;
-        switch (s->cur_file_info.flag & 0x06)
-        {
-          case 6 : *level = 1; break;
-          case 4 : *level = 2; break;
-          case 2 : *level = 9; break;
-        }
-    }
-
-    if ((s->cur_file_info.compression_method!=0) &&
-        (s->cur_file_info.compression_method!=Z_DEFLATED))
-        err=UNZ_BADZIPFILE;
-
-    pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
-    pfile_in_zip_read_info->crc32=0;
-    pfile_in_zip_read_info->compression_method =
-            s->cur_file_info.compression_method;
-    pfile_in_zip_read_info->filestream=s->filestream;
-    pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
-    pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
-
-    pfile_in_zip_read_info->stream.total_out = 0;
-
-    if ((s->cur_file_info.compression_method==Z_DEFLATED) &&
-        (!raw))
-    {
-      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
-      pfile_in_zip_read_info->stream.zfree = (free_func)0;
-      pfile_in_zip_read_info->stream.opaque = (voidpf)0;
-      pfile_in_zip_read_info->stream.next_in = (voidpf)0;
-      pfile_in_zip_read_info->stream.avail_in = 0;
-
-      err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
-      if (err == Z_OK)
-        pfile_in_zip_read_info->stream_initialised=1;
-      else
-      {
-        TRYFREE(pfile_in_zip_read_info);
-        return err;
-      }
-        /* windowBits is passed < 0 to tell that there is no zlib header.
-         * Note that in this case inflate *requires* an extra "dummy" byte
-         * after the compressed stream in order to complete decompression and
-         * return Z_STREAM_END.
-         * In unzip, i don't wait absolutely Z_STREAM_END because I known the
-         * size of both compressed and uncompressed data
-         */
-    }
-    pfile_in_zip_read_info->rest_read_compressed =
-            s->cur_file_info.compressed_size ;
-    pfile_in_zip_read_info->rest_read_uncompressed =
-            s->cur_file_info.uncompressed_size ;
-
-
-    pfile_in_zip_read_info->pos_in_zipfile =
-            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
-              iSizeVar;
-
-    pfile_in_zip_read_info->stream.avail_in = (uInt)0;
-
-    s->pfile_in_zip_read = pfile_in_zip_read_info;
-
-#    ifndef NOUNCRYPT
-    if (password != NULL)
-    {
-        int i;
-        s->pcrc_32_tab = get_crc_table();
-        init_keys(password,s->keys,s->pcrc_32_tab);
-        if (ZSEEK(s->z_filefunc, s->filestream,
-                  s->pfile_in_zip_read->pos_in_zipfile +
-                     s->pfile_in_zip_read->byte_before_the_zipfile,
-                  SEEK_SET)!=0)
-            return UNZ_INTERNALERROR;
-        if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12)
-            return UNZ_INTERNALERROR;
-
-        for (i = 0; i<12; i++)
-            zdecode(s->keys,s->pcrc_32_tab,source[i]);
-
-        s->pfile_in_zip_read->pos_in_zipfile+=12;
-        s->encrypted=1;
-    }
-#    endif
-
-
-    return UNZ_OK;
-}
-
-extern int ZEXPORT unzOpenCurrentFile (file)
-    unzFile file;
-{
-    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
-}
-
-extern int ZEXPORT unzOpenCurrentFilePassword (file, password)
-    unzFile file;
-    const char* password;
-{
-    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
-}
-
-extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw)
-    unzFile file;
-    int* method;
-    int* level;
-    int raw;
-{
-    return unzOpenCurrentFile3(file, method, level, raw, NULL);
-}
-
-/*
-  Read bytes from the current file.
-  buf contain buffer where data must be copied
-  len the size of buf.
-
-  return the number of byte copied if somes bytes are copied
-  return 0 if the end of file was reached
-  return <0 with error code if there is an error
-    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
-*/
-extern int ZEXPORT unzReadCurrentFile  (file, buf, len)
-    unzFile file;
-    voidp buf;
-    unsigned len;
-{
-    int err=UNZ_OK;
-    uInt iRead = 0;
-    unz_s* s;
-    file_in_zip_read_info_s* pfile_in_zip_read_info;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    pfile_in_zip_read_info=s->pfile_in_zip_read;
-
-    if (pfile_in_zip_read_info==NULL)
-        return UNZ_PARAMERROR;
-
-
-    if ((pfile_in_zip_read_info->read_buffer == NULL))
-        return UNZ_END_OF_LIST_OF_FILE;
-    if (len==0)
-        return 0;
-
-    pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
-
-    pfile_in_zip_read_info->stream.avail_out = (uInt)len;
-
-    if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
-        (!(pfile_in_zip_read_info->raw)))
-        pfile_in_zip_read_info->stream.avail_out =
-            (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
-
-    if ((len>pfile_in_zip_read_info->rest_read_compressed+
-           pfile_in_zip_read_info->stream.avail_in) &&
-         (pfile_in_zip_read_info->raw))
-        pfile_in_zip_read_info->stream.avail_out =
-            (uInt)pfile_in_zip_read_info->rest_read_compressed+
-            pfile_in_zip_read_info->stream.avail_in;
-
-    while (pfile_in_zip_read_info->stream.avail_out>0)
-    {
-        if ((pfile_in_zip_read_info->stream.avail_in==0) &&
-            (pfile_in_zip_read_info->rest_read_compressed>0))
-        {
-            uInt uReadThis = UNZ_BUFSIZE;
-            if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
-                uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
-            if (uReadThis == 0)
-                return UNZ_EOF;
-            if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
-                      pfile_in_zip_read_info->filestream,
-                      pfile_in_zip_read_info->pos_in_zipfile +
-                         pfile_in_zip_read_info->byte_before_the_zipfile,
-                         ZLIB_FILEFUNC_SEEK_SET)!=0)
-                return UNZ_ERRNO;
-            if (ZREAD(pfile_in_zip_read_info->z_filefunc,
-                      pfile_in_zip_read_info->filestream,
-                      pfile_in_zip_read_info->read_buffer,
-                      uReadThis)!=uReadThis)
-                return UNZ_ERRNO;
-
-
-#            ifndef NOUNCRYPT
-            if(s->encrypted)
-            {
-                uInt i;
-                for(i=0;i<uReadThis;i++)
-                  pfile_in_zip_read_info->read_buffer[i] =
-                      zdecode(s->keys,s->pcrc_32_tab,
-                              pfile_in_zip_read_info->read_buffer[i]);
-            }
-#            endif
-
-
-            pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
-
-            pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
-
-            pfile_in_zip_read_info->stream.next_in =
-                (Bytef*)pfile_in_zip_read_info->read_buffer;
-            pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
-        }
-
-        if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
-        {
-            uInt uDoCopy,i ;
-
-            if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
-                (pfile_in_zip_read_info->rest_read_compressed == 0))
-                return (iRead==0) ? UNZ_EOF : iRead;
-
-            if (pfile_in_zip_read_info->stream.avail_out <
-                            pfile_in_zip_read_info->stream.avail_in)
-                uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
-            else
-                uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
-
-            for (i=0;i<uDoCopy;i++)
-                *(pfile_in_zip_read_info->stream.next_out+i) =
-                        *(pfile_in_zip_read_info->stream.next_in+i);
-
-            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
-                                pfile_in_zip_read_info->stream.next_out,
-                                uDoCopy);
-            pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
-            pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
-            pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
-            pfile_in_zip_read_info->stream.next_out += uDoCopy;
-            pfile_in_zip_read_info->stream.next_in += uDoCopy;
-            pfile_in_zip_read_info->stream.total_out += uDoCopy;
-            iRead += uDoCopy;
-        }
-        else
-        {
-            uLong uTotalOutBefore,uTotalOutAfter;
-            const Bytef *bufBefore;
-            uLong uOutThis;
-            int flush=Z_SYNC_FLUSH;
-
-            uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
-            bufBefore = pfile_in_zip_read_info->stream.next_out;
-
-            /*
-            if ((pfile_in_zip_read_info->rest_read_uncompressed ==
-                     pfile_in_zip_read_info->stream.avail_out) &&
-                (pfile_in_zip_read_info->rest_read_compressed == 0))
-                flush = Z_FINISH;
-            */
-            err=inflate(&pfile_in_zip_read_info->stream,flush);
-
-            if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
-              err = Z_DATA_ERROR;
-
-            uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
-            uOutThis = uTotalOutAfter-uTotalOutBefore;
-
-            pfile_in_zip_read_info->crc32 =
-                crc32(pfile_in_zip_read_info->crc32,bufBefore,
-                        (uInt)(uOutThis));
-
-            pfile_in_zip_read_info->rest_read_uncompressed -=
-                uOutThis;
-
-            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
-
-            if (err==Z_STREAM_END)
-                return (iRead==0) ? UNZ_EOF : iRead;
-            if (err!=Z_OK)
-                break;
-        }
-    }
-
-    if (err==Z_OK)
-        return iRead;
-    return err;
-}
-
-
-/*
-  Give the current position in uncompressed data
-*/
-extern z_off_t ZEXPORT unztell (file)
-    unzFile file;
-{
-    unz_s* s;
-    file_in_zip_read_info_s* pfile_in_zip_read_info;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    pfile_in_zip_read_info=s->pfile_in_zip_read;
-
-    if (pfile_in_zip_read_info==NULL)
-        return UNZ_PARAMERROR;
-
-    return (z_off_t)pfile_in_zip_read_info->stream.total_out;
-}
-
-
-/*
-  return 1 if the end of file was reached, 0 elsewhere
-*/
-extern int ZEXPORT unzeof (file)
-    unzFile file;
-{
-    unz_s* s;
-    file_in_zip_read_info_s* pfile_in_zip_read_info;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    pfile_in_zip_read_info=s->pfile_in_zip_read;
-
-    if (pfile_in_zip_read_info==NULL)
-        return UNZ_PARAMERROR;
-
-    if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
-        return 1;
-    else
-        return 0;
-}
-
-
-
-/*
-  Read extra field from the current file (opened by unzOpenCurrentFile)
-  This is the local-header version of the extra field (sometimes, there is
-    more info in the local-header version than in the central-header)
-
-  if buf==NULL, it return the size of the local extra field that can be read
-
-  if buf!=NULL, len is the size of the buffer, the extra header is copied in
-    buf.
-  the return value is the number of bytes copied in buf, or (if <0)
-    the error code
-*/
-extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
-    unzFile file;
-    voidp buf;
-    unsigned len;
-{
-    unz_s* s;
-    file_in_zip_read_info_s* pfile_in_zip_read_info;
-    uInt read_now;
-    uLong size_to_read;
-
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    pfile_in_zip_read_info=s->pfile_in_zip_read;
-
-    if (pfile_in_zip_read_info==NULL)
-        return UNZ_PARAMERROR;
-
-    size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
-                pfile_in_zip_read_info->pos_local_extrafield);
-
-    if (buf==NULL)
-        return (int)size_to_read;
-
-    if (len>size_to_read)
-        read_now = (uInt)size_to_read;
-    else
-        read_now = (uInt)len ;
-
-    if (read_now==0)
-        return 0;
-
-    if (ZSEEK(pfile_in_zip_read_info->z_filefunc,
-              pfile_in_zip_read_info->filestream,
-              pfile_in_zip_read_info->offset_local_extrafield +
-              pfile_in_zip_read_info->pos_local_extrafield,
-              ZLIB_FILEFUNC_SEEK_SET)!=0)
-        return UNZ_ERRNO;
-
-    if (ZREAD(pfile_in_zip_read_info->z_filefunc,
-              pfile_in_zip_read_info->filestream,
-              buf,read_now)!=read_now)
-        return UNZ_ERRNO;
-
-    return (int)read_now;
-}
-
-/*
-  Close the file in zip opened with unzipOpenCurrentFile
-  Return UNZ_CRCERROR if all the file was read but the CRC is not good
-*/
-extern int ZEXPORT unzCloseCurrentFile (file)
-    unzFile file;
-{
-    int err=UNZ_OK;
-
-    unz_s* s;
-    file_in_zip_read_info_s* pfile_in_zip_read_info;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    pfile_in_zip_read_info=s->pfile_in_zip_read;
-
-    if (pfile_in_zip_read_info==NULL)
-        return UNZ_PARAMERROR;
-
-
-    if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
-        (!pfile_in_zip_read_info->raw))
-    {
-        if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
-            err=UNZ_CRCERROR;
-    }
-
-
-    TRYFREE(pfile_in_zip_read_info->read_buffer);
-    pfile_in_zip_read_info->read_buffer = NULL;
-    if (pfile_in_zip_read_info->stream_initialised)
-        inflateEnd(&pfile_in_zip_read_info->stream);
-
-    pfile_in_zip_read_info->stream_initialised = 0;
-    TRYFREE(pfile_in_zip_read_info);
-
-    s->pfile_in_zip_read=NULL;
-
-    return err;
-}
-
-
-/*
-  Get the global comment string of the ZipFile, in the szComment buffer.
-  uSizeBuf is the size of the szComment buffer.
-  return the number of byte copied or an error code <0
-*/
-extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
-    unzFile file;
-    char *szComment;
-    uLong uSizeBuf;
-{
-    unz_s* s;
-    uLong uReadThis ;
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-
-    uReadThis = uSizeBuf;
-    if (uReadThis>s->gi.size_comment)
-        uReadThis = s->gi.size_comment;
-
-    if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
-        return UNZ_ERRNO;
-
-    if (uReadThis>0)
-    {
-      *szComment='\0';
-      if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
-        return UNZ_ERRNO;
-    }
-
-    if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
-        *(szComment+s->gi.size_comment)='\0';
-    return (int)uReadThis;
-}
-
-/* Additions by RX '2004 */
-extern uLong ZEXPORT unzGetOffset (file)
-    unzFile file;
-{
-    unz_s* s;
-
-    if (file==NULL)
-          return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-    if (!s->current_file_ok)
-      return 0;
-    if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
-      if (s->num_file==s->gi.number_entry)
-         return 0;
-    return s->pos_in_central_dir;
-}
-
-extern int ZEXPORT unzSetOffset (file, pos)
-        unzFile file;
-        uLong pos;
-{
-    unz_s* s;
-    int err;
-
-    if (file==NULL)
-        return UNZ_PARAMERROR;
-    s=(unz_s*)file;
-
-    s->pos_in_central_dir = pos;
-    s->num_file = s->gi.number_entry;      /* hack */
-    err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
-                                              &s->cur_file_info_internal,
-                                              NULL,0,NULL,0,NULL,0);
-    s->current_file_ok = (err == UNZ_OK);
-    return err;
-}
--- a/misc/quazip/unzip.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-/* unzip.h -- IO for uncompress .zip files using zlib
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
-     WinZip, InfoZip tools and compatible.
-
-   Multi volume ZipFile (span) are not supported.
-   Encryption compatible with pkzip 2.04g only supported
-   Old compressions used by old PKZip 1.x are not supported
-
-
-   I WAIT FEEDBACK at mail info@winimage.com
-   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
-
-   Condition of use and distribution are the same than zlib :
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-   Modified by Sergey A. Tachenov to integrate with Qt.
-
-
-*/
-
-/* for more info about .ZIP format, see
-      http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
-      http://www.info-zip.org/pub/infozip/doc/
-   PkWare has also a specification at :
-      ftp://ftp.pkware.com/probdesc.zip
-*/
-
-#ifndef _unz_H
-#define _unz_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _ZLIB_H
-#include "zlib.h"
-#endif
-
-#ifndef _ZLIBIOAPI_H
-#include "ioapi.h"
-#endif
-
-#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
-/* like the STRICT of WIN32, we define a pointer that cannot be converted
-    from (void*) without cast */
-typedef struct TagunzFile__ { int unused; } unzFile__;
-typedef unzFile__ *unzFile;
-#else
-typedef voidp unzFile;
-#endif
-
-
-#define UNZ_OK                          (0)
-#define UNZ_END_OF_LIST_OF_FILE         (-100)
-#define UNZ_ERRNO                       (Z_ERRNO)
-#define UNZ_EOF                         (0)
-#define UNZ_PARAMERROR                  (-102)
-#define UNZ_BADZIPFILE                  (-103)
-#define UNZ_INTERNALERROR               (-104)
-#define UNZ_CRCERROR                    (-105)
-
-/* tm_unz contain date/time info */
-typedef struct tm_unz_s
-{
-    uInt tm_sec;            /* seconds after the minute - [0,59] */
-    uInt tm_min;            /* minutes after the hour - [0,59] */
-    uInt tm_hour;           /* hours since midnight - [0,23] */
-    uInt tm_mday;           /* day of the month - [1,31] */
-    uInt tm_mon;            /* months since January - [0,11] */
-    uInt tm_year;           /* years - [1980..2044] */
-} tm_unz;
-
-/* unz_global_info structure contain global data about the ZIPfile
-   These data comes from the end of central dir */
-typedef struct unz_global_info_s
-{
-    uLong number_entry;         /* total number of entries in
-                       the central dir on this disk */
-    uLong size_comment;         /* size of the global comment of the zipfile */
-} unz_global_info;
-
-
-/* unz_file_info contain information about a file in the zipfile */
-typedef struct unz_file_info_s
-{
-    uLong version;              /* version made by                 2 bytes */
-    uLong version_needed;       /* version needed to extract       2 bytes */
-    uLong flag;                 /* general purpose bit flag        2 bytes */
-    uLong compression_method;   /* compression method              2 bytes */
-    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
-    uLong crc;                  /* crc-32                          4 bytes */
-    uLong compressed_size;      /* compressed size                 4 bytes */
-    uLong uncompressed_size;    /* uncompressed size               4 bytes */
-    uLong size_filename;        /* filename length                 2 bytes */
-    uLong size_file_extra;      /* extra field length              2 bytes */
-    uLong size_file_comment;    /* file comment length             2 bytes */
-
-    uLong disk_num_start;       /* disk number start               2 bytes */
-    uLong internal_fa;          /* internal file attributes        2 bytes */
-    uLong external_fa;          /* external file attributes        4 bytes */
-
-    tm_unz tmu_date;
-} unz_file_info;
-
-extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
-                                                 const char* fileName2,
-                                                 int iCaseSensitivity));
-/*
-   Compare two filename (fileName1,fileName2).
-   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
-   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
-                                or strcasecmp)
-   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
-    (like 1 on Unix, 2 on Windows)
-*/
-
-
-extern unzFile ZEXPORT unzOpen OF((voidpf file));
-/*
-  Open a Zip file. path contain whatever zopen_file from the IO API
-  accepts. For Qt implementation it is a pointer to QIODevice, for
-  fopen() implementation it's a file name.
-     If the zipfile cannot be opened (file don't exist or in not valid), the
-       return value is NULL.
-     Else, the return value is a unzFile Handle, usable with other function
-       of this unzip package.
-*/
-
-extern unzFile ZEXPORT unzOpen2 OF((voidpf file,
-                                    zlib_filefunc_def* pzlib_filefunc_def));
-/*
-   Open a Zip file, like unzOpen, but provide a set of file low level API
-      for read/write the zip file (see ioapi.h)
-*/
-
-extern int ZEXPORT unzClose OF((unzFile file));
-/*
-  Close a ZipFile opened with unzipOpen.
-  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
-    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
-  return UNZ_OK if there is no problem. */
-
-extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
-                                        unz_global_info *pglobal_info));
-/*
-  Write info about the ZipFile in the *pglobal_info structure.
-  No preparation of the structure is needed
-  return UNZ_OK if there is no problem. */
-
-
-extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
-                                           char *szComment,
-                                           uLong uSizeBuf));
-/*
-  Get the global comment string of the ZipFile, in the szComment buffer.
-  uSizeBuf is the size of the szComment buffer.
-  return the number of byte copied or an error code <0
-*/
-
-
-/***************************************************************************/
-/* Unzip package allow you browse the directory of the zipfile */
-
-extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
-/*
-  Set the current file of the zipfile to the first file.
-  return UNZ_OK if there is no problem
-*/
-
-extern int ZEXPORT unzGoToNextFile OF((unzFile file));
-/*
-  Set the current file of the zipfile to the next file.
-  return UNZ_OK if there is no problem
-  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
-*/
-
-extern int ZEXPORT unzLocateFile OF((unzFile file,
-                     const char *szFileName,
-                     int iCaseSensitivity));
-/*
-  Try locate the file szFileName in the zipfile.
-  For the iCaseSensitivity signification, see unzStringFileNameCompare
-
-  return value :
-  UNZ_OK if the file is found. It becomes the current file.
-  UNZ_END_OF_LIST_OF_FILE if the file is not found
-*/
-
-
-/* ****************************************** */
-/* Ryan supplied functions */
-/* unz_file_info contain information about a file in the zipfile */
-typedef struct unz_file_pos_s
-{
-    uLong pos_in_zip_directory;   /* offset in zip file directory */
-    uLong num_of_file;            /* # of file */
-} unz_file_pos;
-
-extern int ZEXPORT unzGetFilePos(
-    unzFile file,
-    unz_file_pos* file_pos);
-
-extern int ZEXPORT unzGoToFilePos(
-    unzFile file,
-    unz_file_pos* file_pos);
-
-/* ****************************************** */
-
-extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
-                         unz_file_info *pfile_info,
-                         char *szFileName,
-                         uLong fileNameBufferSize,
-                         void *extraField,
-                         uLong extraFieldBufferSize,
-                         char *szComment,
-                         uLong commentBufferSize));
-/*
-  Get Info about the current file
-  if pfile_info!=NULL, the *pfile_info structure will contain somes info about
-        the current file
-  if szFileName!=NULL, the filemane string will be copied in szFileName
-            (fileNameBufferSize is the size of the buffer)
-  if extraField!=NULL, the extra field information will be copied in extraField
-            (extraFieldBufferSize is the size of the buffer).
-            This is the Central-header version of the extra field
-  if szComment!=NULL, the comment string of the file will be copied in szComment
-            (commentBufferSize is the size of the buffer)
-*/
-
-/***************************************************************************/
-/* for reading the content of the current zipfile, you can open it, read data
-   from it, and close it (you can close it before reading all the file)
-   */
-
-extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
-/*
-  Open for reading data the current file in the zipfile.
-  If there is no error, the return value is UNZ_OK.
-*/
-
-extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
-                                                  const char* password));
-/*
-  Open for reading data the current file in the zipfile.
-  password is a crypting password
-  If there is no error, the return value is UNZ_OK.
-*/
-
-extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
-                                           int* method,
-                                           int* level,
-                                           int raw));
-/*
-  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
-    if raw==1
-  *method will receive method of compression, *level will receive level of
-     compression
-  note : you can set level parameter as NULL (if you did not want known level,
-         but you CANNOT set method parameter as NULL
-*/
-
-extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
-                                           int* method,
-                                           int* level,
-                                           int raw,
-                                           const char* password));
-/*
-  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
-    if raw==1
-  *method will receive method of compression, *level will receive level of
-     compression
-  note : you can set level parameter as NULL (if you did not want known level,
-         but you CANNOT set method parameter as NULL
-*/
-
-
-extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
-/*
-  Close the file in zip opened with unzOpenCurrentFile
-  Return UNZ_CRCERROR if all the file was read but the CRC is not good
-*/
-
-extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
-                      voidp buf,
-                      unsigned len));
-/*
-  Read bytes from the current file (opened by unzOpenCurrentFile)
-  buf contain buffer where data must be copied
-  len the size of buf.
-
-  return the number of byte copied if somes bytes are copied
-  return 0 if the end of file was reached
-  return <0 with error code if there is an error
-    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
-*/
-
-extern z_off_t ZEXPORT unztell OF((unzFile file));
-/*
-  Give the current position in uncompressed data
-*/
-
-extern int ZEXPORT unzeof OF((unzFile file));
-/*
-  return 1 if the end of file was reached, 0 elsewhere
-*/
-
-extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
-                                             voidp buf,
-                                             unsigned len));
-/*
-  Read extra field from the current file (opened by unzOpenCurrentFile)
-  This is the local-header version of the extra field (sometimes, there is
-    more info in the local-header version than in the central-header)
-
-  if buf==NULL, it return the size of the local extra field
-
-  if buf!=NULL, len is the size of the buffer, the extra header is copied in
-    buf.
-  the return value is the number of bytes copied in buf, or (if <0)
-    the error code
-*/
-
-/***************************************************************************/
-
-/* Get the current file offset */
-extern uLong ZEXPORT unzGetOffset (unzFile file);
-
-/* Set the current file offset */
-extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _unz_H */
--- a/misc/quazip/zconf.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,332 +0,0 @@
-/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-2005 Jean-loup Gailly.
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/* @(#) $Id$ */
-
-#ifndef ZCONF_H
-#define ZCONF_H
-
-/*
- * If you *really* need a unique prefix for all types and library functions,
- * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
- */
-#ifdef Z_PREFIX
-#  define deflateInit_          z_deflateInit_
-#  define deflate               z_deflate
-#  define deflateEnd            z_deflateEnd
-#  define inflateInit_          z_inflateInit_
-#  define inflate               z_inflate
-#  define inflateEnd            z_inflateEnd
-#  define deflateInit2_         z_deflateInit2_
-#  define deflateSetDictionary  z_deflateSetDictionary
-#  define deflateCopy           z_deflateCopy
-#  define deflateReset          z_deflateReset
-#  define deflateParams         z_deflateParams
-#  define deflateBound          z_deflateBound
-#  define deflatePrime          z_deflatePrime
-#  define inflateInit2_         z_inflateInit2_
-#  define inflateSetDictionary  z_inflateSetDictionary
-#  define inflateSync           z_inflateSync
-#  define inflateSyncPoint      z_inflateSyncPoint
-#  define inflateCopy           z_inflateCopy
-#  define inflateReset          z_inflateReset
-#  define inflateBack           z_inflateBack
-#  define inflateBackEnd        z_inflateBackEnd
-#  define compress              z_compress
-#  define compress2             z_compress2
-#  define compressBound         z_compressBound
-#  define uncompress            z_uncompress
-#  define adler32               z_adler32
-#  define crc32                 z_crc32
-#  define get_crc_table         z_get_crc_table
-#  define zError                z_zError
-
-#  define alloc_func            z_alloc_func
-#  define free_func             z_free_func
-#  define in_func               z_in_func
-#  define out_func              z_out_func
-#  define Byte                  z_Byte
-#  define uInt                  z_uInt
-#  define uLong                 z_uLong
-#  define Bytef                 z_Bytef
-#  define charf                 z_charf
-#  define intf                  z_intf
-#  define uIntf                 z_uIntf
-#  define uLongf                z_uLongf
-#  define voidpf                z_voidpf
-#  define voidp                 z_voidp
-#endif
-
-#if defined(__MSDOS__) && !defined(MSDOS)
-#  define MSDOS
-#endif
-#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
-#  define OS2
-#endif
-#if defined(_WINDOWS) && !defined(WINDOWS)
-#  define WINDOWS
-#endif
-#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
-#  ifndef WIN32
-#    define WIN32
-#  endif
-#endif
-#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
-#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
-#    ifndef SYS16BIT
-#      define SYS16BIT
-#    endif
-#  endif
-#endif
-
-/*
- * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
- * than 64k bytes at a time (needed on systems with 16-bit int).
- */
-#ifdef SYS16BIT
-#  define MAXSEG_64K
-#endif
-#ifdef MSDOS
-#  define UNALIGNED_OK
-#endif
-
-#ifdef __STDC_VERSION__
-#  ifndef STDC
-#    define STDC
-#  endif
-#  if __STDC_VERSION__ >= 199901L
-#    ifndef STDC99
-#      define STDC99
-#    endif
-#  endif
-#endif
-#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
-#  define STDC
-#endif
-#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
-#  define STDC
-#endif
-#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
-#  define STDC
-#endif
-#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
-#  define STDC
-#endif
-
-#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
-#  define STDC
-#endif
-
-#ifndef STDC
-#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
-#    define const       /* note: need a more gentle solution here */
-#  endif
-#endif
-
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
-#  define NO_DUMMY_DECL
-#endif
-
-/* Maximum value for memLevel in deflateInit2 */
-#ifndef MAX_MEM_LEVEL
-#  ifdef MAXSEG_64K
-#    define MAX_MEM_LEVEL 8
-#  else
-#    define MAX_MEM_LEVEL 9
-#  endif
-#endif
-
-/* Maximum value for windowBits in deflateInit2 and inflateInit2.
- * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
- * created by gzip. (Files created by minigzip can still be extracted by
- * gzip.)
- */
-#ifndef MAX_WBITS
-#  define MAX_WBITS   15 /* 32K LZ77 window */
-#endif
-
-/* The memory requirements for deflate are (in bytes):
-            (1 << (windowBits+2)) +  (1 << (memLevel+9))
- that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
- plus a few kilobytes for small objects. For example, if you want to reduce
- the default memory requirements from 256K to 128K, compile with
-     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
- Of course this will generally degrade compression (there's no free lunch).
-
-   The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
- for small objects.
-*/
-
-                        /* Type declarations */
-
-#ifndef OF /* function prototypes */
-#  ifdef STDC
-#    define OF(args)  args
-#  else
-#    define OF(args)  ()
-#  endif
-#endif
-
-/* The following definitions for FAR are needed only for MSDOS mixed
- * model programming (small or medium model with some far allocations).
- * This was tested only with MSC; for other MSDOS compilers you may have
- * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
- * just define FAR to be empty.
- */
-#ifdef SYS16BIT
-#  if defined(M_I86SM) || defined(M_I86MM)
-     /* MSC small or medium model */
-#    define SMALL_MEDIUM
-#    ifdef _MSC_VER
-#      define FAR _far
-#    else
-#      define FAR far
-#    endif
-#  endif
-#  if (defined(__SMALL__) || defined(__MEDIUM__))
-     /* Turbo C small or medium model */
-#    define SMALL_MEDIUM
-#    ifdef __BORLANDC__
-#      define FAR _far
-#    else
-#      define FAR far
-#    endif
-#  endif
-#endif
-
-#if defined(WINDOWS) || defined(WIN32)
-   /* If building or using zlib as a DLL, define ZLIB_DLL.
-    * This is not mandatory, but it offers a little performance increase.
-    */
-#  ifdef ZLIB_DLL
-#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
-#      ifdef ZLIB_INTERNAL
-#        define ZEXTERN extern __declspec(dllexport)
-#      else
-#        define ZEXTERN extern __declspec(dllimport)
-#      endif
-#    endif
-#  endif  /* ZLIB_DLL */
-   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
-    * define ZLIB_WINAPI.
-    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
-    */
-#  ifdef ZLIB_WINAPI
-#    ifdef FAR
-#      undef FAR
-#    endif
-#    include <windows.h>
-     /* No need for _export, use ZLIB.DEF instead. */
-     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
-#    define ZEXPORT WINAPI
-#    ifdef WIN32
-#      define ZEXPORTVA WINAPIV
-#    else
-#      define ZEXPORTVA FAR CDECL
-#    endif
-#  endif
-#endif
-
-#if defined (__BEOS__)
-#  ifdef ZLIB_DLL
-#    ifdef ZLIB_INTERNAL
-#      define ZEXPORT   __declspec(dllexport)
-#      define ZEXPORTVA __declspec(dllexport)
-#    else
-#      define ZEXPORT   __declspec(dllimport)
-#      define ZEXPORTVA __declspec(dllimport)
-#    endif
-#  endif
-#endif
-
-#ifndef ZEXTERN
-#  define ZEXTERN extern
-#endif
-#ifndef ZEXPORT
-#  define ZEXPORT
-#endif
-#ifndef ZEXPORTVA
-#  define ZEXPORTVA
-#endif
-
-#ifndef FAR
-#  define FAR
-#endif
-
-#if !defined(__MACTYPES__)
-typedef unsigned char  Byte;  /* 8 bits */
-#endif
-typedef unsigned int   uInt;  /* 16 bits or more */
-typedef unsigned long  uLong; /* 32 bits or more */
-
-#ifdef SMALL_MEDIUM
-   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
-#  define Bytef Byte FAR
-#else
-   typedef Byte  FAR Bytef;
-#endif
-typedef char  FAR charf;
-typedef int   FAR intf;
-typedef uInt  FAR uIntf;
-typedef uLong FAR uLongf;
-
-#ifdef STDC
-   typedef void const *voidpc;
-   typedef void FAR   *voidpf;
-   typedef void       *voidp;
-#else
-   typedef Byte const *voidpc;
-   typedef Byte FAR   *voidpf;
-   typedef Byte       *voidp;
-#endif
-
-#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
-#  include <sys/types.h> /* for off_t */
-#  include <unistd.h>    /* for SEEK_* and off_t */
-#  ifdef VMS
-#    include <unixio.h>   /* for off_t */
-#  endif
-#  define z_off_t off_t
-#endif
-#ifndef SEEK_SET
-#  define SEEK_SET        0       /* Seek from beginning of file.  */
-#  define SEEK_CUR        1       /* Seek from current position.  */
-#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
-#endif
-#ifndef z_off_t
-#  define z_off_t long
-#endif
-
-#if defined(__OS400__)
-#  define NO_vsnprintf
-#endif
-
-#if defined(__MVS__)
-#  define NO_vsnprintf
-#  ifdef FAR
-#    undef FAR
-#  endif
-#endif
-
-/* MVS linker does not support external names larger than 8 bytes */
-#if defined(__MVS__)
-#   pragma map(deflateInit_,"DEIN")
-#   pragma map(deflateInit2_,"DEIN2")
-#   pragma map(deflateEnd,"DEEND")
-#   pragma map(deflateBound,"DEBND")
-#   pragma map(inflateInit_,"ININ")
-#   pragma map(inflateInit2_,"ININ2")
-#   pragma map(inflateEnd,"INEND")
-#   pragma map(inflateSync,"INSY")
-#   pragma map(inflateSetDictionary,"INSEDI")
-#   pragma map(compressBound,"CMBND")
-#   pragma map(inflate_table,"INTABL")
-#   pragma map(inflate_fast,"INFA")
-#   pragma map(inflate_copyright,"INCOPY")
-#endif
-
-#endif /* ZCONF_H */
--- a/misc/quazip/zip.c	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1243 +0,0 @@
-/* zip.c -- IO on .zip files using zlib
-   Version 1.01e, February 12th, 2005
-
-   27 Dec 2004 Rolf Kalbermatter
-   Modification to zipOpen2 to support globalComment retrieval.
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   Read zip.h for more info
-
-   Modified by Sergey A. Tachenov to integrate with Qt.
-*/
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "zlib.h"
-#include "zip.h"
-#include "quazip_global.h"
-
-#ifdef STDC
-#  include <stddef.h>
-#  include <string.h>
-#  include <stdlib.h>
-#endif
-#ifdef NO_ERRNO_H
-    extern int errno;
-#else
-#   include <errno.h>
-#endif
-
-
-#ifndef local
-#  define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
-
-#ifndef VERSIONMADEBY
-# define VERSIONMADEBY   (0x031e) /* best for standard pkware crypt */
-#endif
-
-#ifndef Z_BUFSIZE
-#define Z_BUFSIZE (16384)
-#endif
-
-#ifndef Z_MAXFILENAMEINZIP
-#define Z_MAXFILENAMEINZIP (256)
-#endif
-
-#ifndef ALLOC
-# define ALLOC(size) (malloc(size))
-#endif
-#ifndef TRYFREE
-# define TRYFREE(p) {if (p) free(p);}
-#endif
-
-/*
-#define SIZECENTRALDIRITEM (0x2e)
-#define SIZEZIPLOCALHEADER (0x1e)
-*/
-
-/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
-
-#ifndef SEEK_CUR
-#define SEEK_CUR    1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END    2
-#endif
-
-#ifndef SEEK_SET
-#define SEEK_SET    0
-#endif
-
-#ifndef DEF_MEM_LEVEL
-#if MAX_MEM_LEVEL >= 8
-#  define DEF_MEM_LEVEL 8
-#else
-#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#endif
-#endif
-const char zip_copyright[] =
-   " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
-
-
-#define SIZEDATA_INDATABLOCK (4096-(4*4))
-
-#define LOCALHEADERMAGIC    (0x04034b50)
-#define DESCRIPTORHEADERMAGIC    (0x08074b50)
-#define CENTRALHEADERMAGIC  (0x02014b50)
-#define ENDHEADERMAGIC      (0x06054b50)
-
-#define FLAG_LOCALHEADER_OFFSET (0x06)
-#define CRC_LOCALHEADER_OFFSET  (0x0e)
-
-#define SIZECENTRALHEADER (0x2e) /* 46 */
-
-typedef struct linkedlist_datablock_internal_s
-{
-  struct linkedlist_datablock_internal_s* next_datablock;
-  uLong  avail_in_this_block;
-  uLong  filled_in_this_block;
-  uLong  unused; /* for future use and alignement */
-  unsigned char data[SIZEDATA_INDATABLOCK];
-} linkedlist_datablock_internal;
-
-typedef struct linkedlist_data_s
-{
-    linkedlist_datablock_internal* first_block;
-    linkedlist_datablock_internal* last_block;
-} linkedlist_data;
-
-
-typedef struct
-{
-    z_stream stream;            /* zLib stream structure for inflate */
-    int  stream_initialised;    /* 1 is stream is initialised */
-    uInt pos_in_buffered_data;  /* last written byte in buffered_data */
-
-    uLong pos_local_header;     /* offset of the local header of the file
-                                     currenty writing */
-    char* central_header;       /* central header data for the current file */
-    uLong size_centralheader;   /* size of the central header for cur file */
-    uLong flag;                 /* flag of the file currently writing */
-
-    int  method;                /* compression method of file currenty wr.*/
-    int  raw;                   /* 1 for directly writing raw data */
-    Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
-    uLong dosDate;
-    uLong crc32;
-    int  encrypt;
-#ifndef NOCRYPT
-    unsigned long keys[3];     /* keys defining the pseudo-random sequence */
-    const unsigned long* pcrc_32_tab;
-    int crypt_header_size;
-#endif
-} curfile_info;
-
-typedef struct
-{
-    zlib_filefunc_def z_filefunc;
-    voidpf filestream;        /* io structore of the zipfile */
-    linkedlist_data central_dir;/* datablock with central dir in construction*/
-    int  in_opened_file_inzip;  /* 1 if a file in the zip is currently writ.*/
-    curfile_info ci;            /* info on the file curretly writing */
-
-    uLong begin_pos;            /* position of the beginning of the zipfile */
-    uLong add_position_when_writting_offset;
-    uLong number_entry;
-#ifndef NO_ADDFILEINEXISTINGZIP
-    char *globalcomment;
-#endif
-} zip_internal;
-
-
-
-#ifndef NOCRYPT
-#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
-#include "crypt.h"
-#endif
-
-local linkedlist_datablock_internal* allocate_new_datablock()
-{
-    linkedlist_datablock_internal* ldi;
-    ldi = (linkedlist_datablock_internal*)
-                 ALLOC(sizeof(linkedlist_datablock_internal));
-    if (ldi!=NULL)
-    {
-        ldi->next_datablock = NULL ;
-        ldi->filled_in_this_block = 0 ;
-        ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
-    }
-    return ldi;
-}
-
-local void free_datablock(ldi)
-    linkedlist_datablock_internal* ldi;
-{
-    while (ldi!=NULL)
-    {
-        linkedlist_datablock_internal* ldinext = ldi->next_datablock;
-        TRYFREE(ldi);
-        ldi = ldinext;
-    }
-}
-
-local void init_linkedlist(ll)
-    linkedlist_data* ll;
-{
-    ll->first_block = ll->last_block = NULL;
-}
-
-#if 0 // unused
-local void free_linkedlist(ll)
-    linkedlist_data* ll;
-{
-    free_datablock(ll->first_block);
-    ll->first_block = ll->last_block = NULL;
-}
-#endif
-
-local int add_data_in_datablock(ll,buf,len)
-    linkedlist_data* ll;
-    const void* buf;
-    uLong len;
-{
-    linkedlist_datablock_internal* ldi;
-    const unsigned char* from_copy;
-
-    if (ll==NULL)
-        return ZIP_INTERNALERROR;
-
-    if (ll->last_block == NULL)
-    {
-        ll->first_block = ll->last_block = allocate_new_datablock();
-        if (ll->first_block == NULL)
-            return ZIP_INTERNALERROR;
-    }
-
-    ldi = ll->last_block;
-    from_copy = (unsigned char*)buf;
-
-    while (len>0)
-    {
-        uInt copy_this;
-        uInt i;
-        unsigned char* to_copy;
-
-        if (ldi->avail_in_this_block==0)
-        {
-            ldi->next_datablock = allocate_new_datablock();
-            if (ldi->next_datablock == NULL)
-                return ZIP_INTERNALERROR;
-            ldi = ldi->next_datablock ;
-            ll->last_block = ldi;
-        }
-
-        if (ldi->avail_in_this_block < len)
-            copy_this = (uInt)ldi->avail_in_this_block;
-        else
-            copy_this = (uInt)len;
-
-        to_copy = &(ldi->data[ldi->filled_in_this_block]);
-
-        for (i=0;i<copy_this;i++)
-            *(to_copy+i)=*(from_copy+i);
-
-        ldi->filled_in_this_block += copy_this;
-        ldi->avail_in_this_block -= copy_this;
-        from_copy += copy_this ;
-        len -= copy_this;
-    }
-    return ZIP_OK;
-}
-
-
-
-/****************************************************************************/
-
-#ifndef NO_ADDFILEINEXISTINGZIP
-/* ===========================================================================
-   Inputs a long in LSB order to the given file
-   nbByte == 1, 2 or 4 (byte, short or long)
-*/
-
-local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def,
-                                voidpf filestream, uLong x, int nbByte));
-local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    uLong x;
-    int nbByte;
-{
-    unsigned char buf[4];
-    int n;
-    for (n = 0; n < nbByte; n++)
-    {
-        buf[n] = (unsigned char)(x & 0xff);
-        x >>= 8;
-    }
-    if (x != 0)
-      {     /* data overflow - hack for ZIP64 (X Roche) */
-      for (n = 0; n < nbByte; n++)
-        {
-          buf[n] = 0xff;
-        }
-      }
-
-    if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
-        return ZIP_ERRNO;
-    else
-        return ZIP_OK;
-}
-
-local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
-local void ziplocal_putValue_inmemory (dest, x, nbByte)
-    void* dest;
-    uLong x;
-    int nbByte;
-{
-    unsigned char* buf=(unsigned char*)dest;
-    int n;
-    for (n = 0; n < nbByte; n++) {
-        buf[n] = (unsigned char)(x & 0xff);
-        x >>= 8;
-    }
-
-    if (x != 0)
-    {     /* data overflow - hack for ZIP64 */
-       for (n = 0; n < nbByte; n++)
-       {
-          buf[n] = 0xff;
-       }
-    }
-}
-
-/****************************************************************************/
-
-
-local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
-    const tm_zip* ptm;
-    uLong dosDate UNUSED;
-{
-    uLong year = (uLong)ptm->tm_year;
-    if (year>1980)
-        year-=1980;
-    else if (year>80)
-        year-=80;
-    return
-      (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
-        ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
-}
-
-
-/****************************************************************************/
-
-local int ziplocal_getByte OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream,
-    int *pi));
-
-local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    int *pi;
-{
-    unsigned char c;
-    int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);
-    if (err==1)
-    {
-        *pi = (int)c;
-        return ZIP_OK;
-    }
-    else
-    {
-        if (ZERROR(*pzlib_filefunc_def,filestream))
-            return ZIP_ERRNO;
-        else
-            return ZIP_EOF;
-    }
-}
-
-
-/* ===========================================================================
-   Reads a long in LSB order from the given gz_stream. Sets
-*/
-local int ziplocal_getShort OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream,
-    uLong *pX));
-
-local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    uLong *pX;
-{
-    uLong x ;
-    int i;
-    int err;
-
-    err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x = (uLong)i;
-
-    if (err==ZIP_OK)
-        err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<8;
-
-    if (err==ZIP_OK)
-        *pX = x;
-    else
-        *pX = 0;
-    return err;
-}
-
-local int ziplocal_getLong OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream,
-    uLong *pX));
-
-local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-    uLong *pX;
-{
-    uLong x ;
-    int i;
-    int err;
-
-    err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x = (uLong)i;
-
-    if (err==ZIP_OK)
-        err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<8;
-
-    if (err==ZIP_OK)
-        err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<16;
-
-    if (err==ZIP_OK)
-        err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
-    x += ((uLong)i)<<24;
-
-    if (err==ZIP_OK)
-        *pX = x;
-    else
-        *pX = 0;
-    return err;
-}
-
-#ifndef BUFREADCOMMENT
-#define BUFREADCOMMENT (0x400)
-#endif
-/*
-  Locate the Central directory of a zipfile (at the end, just before
-    the global comment)
-*/
-local uLong ziplocal_SearchCentralDir OF((
-    const zlib_filefunc_def* pzlib_filefunc_def,
-    voidpf filestream));
-
-local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream)
-    const zlib_filefunc_def* pzlib_filefunc_def;
-    voidpf filestream;
-{
-    unsigned char* buf;
-    uLong uSizeFile;
-    uLong uBackRead;
-    uLong uMaxBack=0xffff; /* maximum size of global comment */
-    uLong uPosFound=0;
-
-    if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
-        return 0;
-
-
-    uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
-
-    if (uMaxBack>uSizeFile)
-        uMaxBack = uSizeFile;
-
-    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
-    if (buf==NULL)
-        return 0;
-
-    uBackRead = 4;
-    while (uBackRead<uMaxBack)
-    {
-        uLong uReadSize,uReadPos ;
-        int i;
-        if (uBackRead+BUFREADCOMMENT>uMaxBack)
-            uBackRead = uMaxBack;
-        else
-            uBackRead+=BUFREADCOMMENT;
-        uReadPos = uSizeFile-uBackRead ;
-
-        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
-                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
-        if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
-            break;
-
-        if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
-            break;
-
-        for (i=(int)uReadSize-3; (i--)>0;)
-            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
-                ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
-            {
-                uPosFound = uReadPos+i;
-                break;
-            }
-
-        if (uPosFound!=0)
-            break;
-    }
-    TRYFREE(buf);
-    return uPosFound;
-}
-#endif /* !NO_ADDFILEINEXISTINGZIP*/
-
-/************************************************************/
-extern zipFile ZEXPORT zipOpen2 (file, append, globalcomment, pzlib_filefunc_def)
-    voidpf file;
-    int append;
-    zipcharpc* globalcomment;
-    zlib_filefunc_def* pzlib_filefunc_def;
-{
-    zip_internal ziinit;
-    zip_internal* zi;
-    int err=ZIP_OK;
-
-
-    if (pzlib_filefunc_def==NULL)
-        fill_qiodevice_filefunc(&ziinit.z_filefunc);
-    else
-        ziinit.z_filefunc = *pzlib_filefunc_def;
-
-    ziinit.filestream = (*(ziinit.z_filefunc.zopen_file))
-                 (ziinit.z_filefunc.opaque,
-                  file,
-                  (append == APPEND_STATUS_CREATE) ?
-                  (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
-                    (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
-
-    if (ziinit.filestream == NULL)
-        return NULL;
-    ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream);
-    ziinit.in_opened_file_inzip = 0;
-    ziinit.ci.stream_initialised = 0;
-    ziinit.number_entry = 0;
-    ziinit.add_position_when_writting_offset = 0;
-    init_linkedlist(&(ziinit.central_dir));
-
-
-    zi = (zip_internal*)ALLOC(sizeof(zip_internal));
-    if (zi==NULL)
-    {
-        ZCLOSE(ziinit.z_filefunc,ziinit.filestream);
-        return NULL;
-    }
-
-    /* now we add file in a zipfile */
-#    ifndef NO_ADDFILEINEXISTINGZIP
-    ziinit.globalcomment = NULL;
-    if (append == APPEND_STATUS_ADDINZIP)
-    {
-        uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
-
-        uLong size_central_dir;     /* size of the central directory  */
-        uLong offset_central_dir;   /* offset of start of central directory */
-        uLong central_pos,uL;
-
-        uLong number_disk;          /* number of the current dist, used for
-                                    spaning ZIP, unsupported, always 0*/
-        uLong number_disk_with_CD;  /* number the the disk with central dir, used
-                                    for spaning ZIP, unsupported, always 0*/
-        uLong number_entry;
-        uLong number_entry_CD;      /* total number of entries in
-                                    the central dir
-                                    (same than number_entry on nospan) */
-        uLong size_comment;
-
-        central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream);
-        if (central_pos==0)
-            err=ZIP_ERRNO;
-
-        if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
-                                        central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
-            err=ZIP_ERRNO;
-
-        /* the signature, already checked */
-        if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        /* number of this disk */
-        if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        /* number of the disk with the start of the central directory */
-        if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        /* total number of entries in the central dir on this disk */
-        if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        /* total number of entries in the central dir */
-        if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        if ((number_entry_CD!=number_entry) ||
-            (number_disk_with_CD!=0) ||
-            (number_disk!=0))
-            err=ZIP_BADZIPFILE;
-
-        /* size of the central directory */
-        if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        /* offset of start of central directory with respect to the
-            starting disk number */
-        if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        /* zipfile global comment length */
-        if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK)
-            err=ZIP_ERRNO;
-
-        if ((central_pos<offset_central_dir+size_central_dir) &&
-            (err==ZIP_OK))
-            err=ZIP_BADZIPFILE;
-
-        if (err!=ZIP_OK)
-        {
-            ZCLOSE(ziinit.z_filefunc, ziinit.filestream);
-            return NULL;
-        }
-
-        if (size_comment>0)
-        {
-            ziinit.globalcomment = ALLOC(size_comment+1);
-            if (ziinit.globalcomment)
-            {
-               size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment);
-               ziinit.globalcomment[size_comment]=0;
-            }
-        }
-
-        byte_before_the_zipfile = central_pos -
-                                (offset_central_dir+size_central_dir);
-        ziinit.add_position_when_writting_offset = byte_before_the_zipfile;
-
-        {
-            uLong size_central_dir_to_read = size_central_dir;
-            size_t buf_size = SIZEDATA_INDATABLOCK;
-            void* buf_read = (void*)ALLOC(buf_size);
-            if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
-                  offset_central_dir + byte_before_the_zipfile,
-                  ZLIB_FILEFUNC_SEEK_SET) != 0)
-                  err=ZIP_ERRNO;
-
-            while ((size_central_dir_to_read>0) && (err==ZIP_OK))
-            {
-                uLong read_this = SIZEDATA_INDATABLOCK;
-                if (read_this > size_central_dir_to_read)
-                    read_this = size_central_dir_to_read;
-                if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this)
-                    err=ZIP_ERRNO;
-
-                if (err==ZIP_OK)
-                    err = add_data_in_datablock(&ziinit.central_dir,buf_read,
-                                                (uLong)read_this);
-                size_central_dir_to_read-=read_this;
-            }
-            TRYFREE(buf_read);
-        }
-        ziinit.begin_pos = byte_before_the_zipfile;
-        ziinit.number_entry = number_entry_CD;
-
-        if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
-                  offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
-            err=ZIP_ERRNO;
-    }
-
-    if (globalcomment)
-    {
-      *globalcomment = ziinit.globalcomment;
-    }
-#    endif /* !NO_ADDFILEINEXISTINGZIP*/
-
-    if (err != ZIP_OK)
-    {
-#    ifndef NO_ADDFILEINEXISTINGZIP
-        TRYFREE(ziinit.globalcomment);
-#    endif /* !NO_ADDFILEINEXISTINGZIP*/
-        TRYFREE(zi);
-        return NULL;
-    }
-    else
-    {
-        *zi = ziinit;
-        return (zipFile)zi;
-    }
-}
-
-extern zipFile ZEXPORT zipOpen (file, append)
-    voidpf file;
-    int append;
-{
-    return zipOpen2(file,append,NULL,NULL);
-}
-
-extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
-                                         extrafield_local, size_extrafield_local,
-                                         extrafield_global, size_extrafield_global,
-                                         comment, method, level, raw,
-                                         windowBits, memLevel, strategy,
-                                         password, crcForCrypting)
-    zipFile file;
-    const char* filename;
-    const zip_fileinfo* zipfi;
-    const void* extrafield_local;
-    uInt size_extrafield_local;
-    const void* extrafield_global;
-    uInt size_extrafield_global;
-    const char* comment;
-    int method;
-    int level;
-    int raw;
-    int windowBits;
-    int memLevel;
-    int strategy;
-    const char* password;
-    uLong crcForCrypting;
-{
-    zip_internal* zi;
-    uInt size_filename;
-    uInt size_comment;
-    uInt i;
-    int err = ZIP_OK;
-
-#    ifdef NOCRYPT
-    if (password != NULL)
-        return ZIP_PARAMERROR;
-#    endif
-
-    if (file == NULL)
-        return ZIP_PARAMERROR;
-    if ((method!=0) && (method!=Z_DEFLATED))
-        return ZIP_PARAMERROR;
-
-    zi = (zip_internal*)file;
-
-    if (zi->in_opened_file_inzip == 1)
-    {
-        err = zipCloseFileInZip (file);
-        if (err != ZIP_OK)
-            return err;
-    }
-
-
-    if (filename==NULL)
-        filename="-";
-
-    if (comment==NULL)
-        size_comment = 0;
-    else
-        size_comment = (uInt)strlen(comment);
-
-    size_filename = (uInt)strlen(filename);
-
-    if (zipfi == NULL)
-        zi->ci.dosDate = 0;
-    else
-    {
-        if (zipfi->dosDate != 0)
-            zi->ci.dosDate = zipfi->dosDate;
-        else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
-    }
-
-    zi->ci.flag = 0;
-    if ((level==8) || (level==9))
-      zi->ci.flag |= 2;
-    if ((level==2))
-      zi->ci.flag |= 4;
-    if ((level==1))
-      zi->ci.flag |= 6;
-    if (password != NULL)
-    {
-      zi->ci.flag |= 1;
-    }
-    zi->ci.flag |= 8;
-    zi->ci.crc32 = 0;
-    zi->ci.method = method;
-    zi->ci.encrypt = 0;
-    zi->ci.stream_initialised = 0;
-    zi->ci.pos_in_buffered_data = 0;
-    zi->ci.raw = raw;
-    zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ;
-    zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
-                                      size_extrafield_global + size_comment;
-    zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
-
-    ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
-    /* version info */
-    ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
-    ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
-    ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
-    ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
-    ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
-
-    if (zipfi==NULL)
-        ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
-    else
-        ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
-
-    if (zipfi==NULL)
-        ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
-    else
-        ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
-
-    ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4);
-
-    for (i=0;i<size_filename;i++)
-        *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
-
-    for (i=0;i<size_extrafield_global;i++)
-        *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
-              *(((const char*)extrafield_global)+i);
-
-    for (i=0;i<size_comment;i++)
-        *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
-              size_extrafield_global+i) = *(comment+i);
-    if (zi->ci.central_header == NULL)
-        return ZIP_INTERNALERROR;
-
-    /* write the local header */
-    err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4);
-
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
-
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
-
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
-
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
-
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
-
-    if (err==ZIP_OK)
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2);
-
-    if ((err==ZIP_OK) && (size_filename>0))
-        if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
-                err = ZIP_ERRNO;
-
-    if ((err==ZIP_OK) && (size_extrafield_local>0))
-        if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local)
-                                                                           !=size_extrafield_local)
-                err = ZIP_ERRNO;
-
-    zi->ci.stream.avail_in = (uInt)0;
-    zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
-    zi->ci.stream.next_out = zi->ci.buffered_data;
-    zi->ci.stream.total_in = 0;
-    zi->ci.stream.total_out = 0;
-
-    if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
-    {
-        zi->ci.stream.zalloc = (alloc_func)0;
-        zi->ci.stream.zfree = (free_func)0;
-        zi->ci.stream.opaque = (voidpf)0;
-
-        if (windowBits>0)
-            windowBits = -windowBits;
-
-        err = deflateInit2(&zi->ci.stream, level,
-               Z_DEFLATED, windowBits, memLevel, strategy);
-
-        if (err==Z_OK)
-            zi->ci.stream_initialised = 1;
-    }
-#    ifndef NOCRYPT
-    zi->ci.crypt_header_size = 0;
-    if ((err==Z_OK) && (password != NULL))
-    {
-        unsigned char bufHead[RAND_HEAD_LEN];
-        unsigned int sizeHead;
-        zi->ci.encrypt = 1;
-        zi->ci.pcrc_32_tab = get_crc_table();
-        /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
-
-        crcForCrypting = (uLong)zi->ci.dosDate << 16; // ATTANTION! Without this row, you don't unpack your password protected archive in other app.
-
-        sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
-        zi->ci.crypt_header_size = sizeHead;
-
-        if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
-                err = ZIP_ERRNO;
-    }
-#    endif
-
-    if (err==Z_OK)
-        zi->in_opened_file_inzip = 1;
-    return err;
-}
-
-extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi,
-                                        extrafield_local, size_extrafield_local,
-                                        extrafield_global, size_extrafield_global,
-                                        comment, method, level, raw)
-    zipFile file;
-    const char* filename;
-    const zip_fileinfo* zipfi;
-    const void* extrafield_local;
-    uInt size_extrafield_local;
-    const void* extrafield_global;
-    uInt size_extrafield_global;
-    const char* comment;
-    int method;
-    int level;
-    int raw;
-{
-    return zipOpenNewFileInZip3 (file, filename, zipfi,
-                                 extrafield_local, size_extrafield_local,
-                                 extrafield_global, size_extrafield_global,
-                                 comment, method, level, raw,
-                                 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
-                                 NULL, 0);
-}
-
-extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
-                                        extrafield_local, size_extrafield_local,
-                                        extrafield_global, size_extrafield_global,
-                                        comment, method, level)
-    zipFile file;
-    const char* filename;
-    const zip_fileinfo* zipfi;
-    const void* extrafield_local;
-    uInt size_extrafield_local;
-    const void* extrafield_global;
-    uInt size_extrafield_global;
-    const char* comment;
-    int method;
-    int level;
-{
-    return zipOpenNewFileInZip2 (file, filename, zipfi,
-                                 extrafield_local, size_extrafield_local,
-                                 extrafield_global, size_extrafield_global,
-                                 comment, method, level, 0);
-}
-
-local int zipFlushWriteBuffer(zi)
-  zip_internal* zi;
-{
-    int err=ZIP_OK;
-
-    if (zi->ci.encrypt != 0)
-    {
-#ifndef NOCRYPT
-        uInt i;
-        int t;
-        for (i=0;i<zi->ci.pos_in_buffered_data;i++)
-            zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab,
-                                       zi->ci.buffered_data[i],t);
-#endif
-    }
-    if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data)
-                                                                    !=zi->ci.pos_in_buffered_data)
-      err = ZIP_ERRNO;
-    zi->ci.pos_in_buffered_data = 0;
-    return err;
-}
-
-extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
-    zipFile file;
-    const void* buf;
-    unsigned len;
-{
-    zip_internal* zi;
-    int err=ZIP_OK;
-
-    if (file == NULL)
-        return ZIP_PARAMERROR;
-    zi = (zip_internal*)file;
-
-    if (zi->in_opened_file_inzip == 0)
-        return ZIP_PARAMERROR;
-
-    zi->ci.stream.next_in = (void*)buf;
-    zi->ci.stream.avail_in = len;
-    zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
-
-    while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
-    {
-        if (zi->ci.stream.avail_out == 0)
-        {
-            if (zipFlushWriteBuffer(zi) == ZIP_ERRNO)
-                err = ZIP_ERRNO;
-            zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
-            zi->ci.stream.next_out = zi->ci.buffered_data;
-        }
-
-
-        if(err != ZIP_OK)
-            break;
-
-        if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
-        {
-            uLong uTotalOutBefore = zi->ci.stream.total_out;
-            err=deflate(&zi->ci.stream,  Z_NO_FLUSH);
-            zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
-
-        }
-        else
-        {
-            uInt copy_this,i;
-            if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
-                copy_this = zi->ci.stream.avail_in;
-            else
-                copy_this = zi->ci.stream.avail_out;
-            for (i=0;i<copy_this;i++)
-                *(((char*)zi->ci.stream.next_out)+i) =
-                    *(((const char*)zi->ci.stream.next_in)+i);
-            {
-                zi->ci.stream.avail_in -= copy_this;
-                zi->ci.stream.avail_out-= copy_this;
-                zi->ci.stream.next_in+= copy_this;
-                zi->ci.stream.next_out+= copy_this;
-                zi->ci.stream.total_in+= copy_this;
-                zi->ci.stream.total_out+= copy_this;
-                zi->ci.pos_in_buffered_data += copy_this;
-            }
-        }
-    }
-
-    return err;
-}
-
-extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32)
-    zipFile file;
-    uLong uncompressed_size;
-    uLong crc32;
-{
-    zip_internal* zi;
-    uLong compressed_size;
-    int err=ZIP_OK;
-
-    if (file == NULL)
-        return ZIP_PARAMERROR;
-    zi = (zip_internal*)file;
-
-    if (zi->in_opened_file_inzip == 0)
-        return ZIP_PARAMERROR;
-    zi->ci.stream.avail_in = 0;
-
-    if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
-        while (err==ZIP_OK)
-    {
-        uLong uTotalOutBefore;
-        if (zi->ci.stream.avail_out == 0)
-        {
-            if (zipFlushWriteBuffer(zi) == ZIP_ERRNO)
-                err = ZIP_ERRNO;
-            zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
-            zi->ci.stream.next_out = zi->ci.buffered_data;
-        }
-        uTotalOutBefore = zi->ci.stream.total_out;
-        err=deflate(&zi->ci.stream,  Z_FINISH);
-        zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
-    }
-
-    if (err==Z_STREAM_END)
-        err=ZIP_OK; /* this is normal */
-
-    if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
-        if (zipFlushWriteBuffer(zi)==ZIP_ERRNO)
-            err = ZIP_ERRNO;
-
-    if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
-    {
-        err=deflateEnd(&zi->ci.stream);
-        zi->ci.stream_initialised = 0;
-    }
-
-    if (!zi->ci.raw)
-    {
-        crc32 = (uLong)zi->ci.crc32;
-        uncompressed_size = (uLong)zi->ci.stream.total_in;
-    }
-    compressed_size = (uLong)zi->ci.stream.total_out;
-#    ifndef NOCRYPT
-    compressed_size += zi->ci.crypt_header_size;
-#    endif
-
-    ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
-    ziplocal_putValue_inmemory(zi->ci.central_header+20,
-                                compressed_size,4); /*compr size*/
-    if (zi->ci.stream.data_type == Z_ASCII)
-        ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
-    ziplocal_putValue_inmemory(zi->ci.central_header+24,
-                                uncompressed_size,4); /*uncompr size*/
-
-    if (err==ZIP_OK)
-        err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
-                                       (uLong)zi->ci.size_centralheader);
-    free(zi->ci.central_header);
-
-    if (err==ZIP_OK)
-    {
-        uLong cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream);
-        if (ZSEEK(zi->z_filefunc,zi->filestream,
-                  zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
-            err = ZIP_ERRNO;
-
-        if (err==ZIP_OK)
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
-
-        if (err==ZIP_OK) /* compressed size, unknown */
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
-
-        if (err==ZIP_OK) /* uncompressed size, unknown */
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
-
-        if (ZSEEK(zi->z_filefunc,zi->filestream,
-                  cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
-            err = ZIP_ERRNO;
-
-        /* Write local Descriptor after file data */
-        if (err==ZIP_OK)
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4);
-
-        if (err==ZIP_OK)
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
-
-        if (err==ZIP_OK) /* compressed size, unknown */
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
-
-        if (err==ZIP_OK) /* uncompressed size, unknown */
-            err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
-
-
-    }
-
-    zi->number_entry ++;
-    zi->in_opened_file_inzip = 0;
-
-    return err;
-}
-
-extern int ZEXPORT zipCloseFileInZip (file)
-    zipFile file;
-{
-    return zipCloseFileInZipRaw (file,0,0);
-}
-
-extern int ZEXPORT zipClose (file, global_comment)
-    zipFile file;
-    const char* global_comment;
-{
-    zip_internal* zi;
-    int err = 0;
-    uLong size_centraldir = 0;
-    uLong centraldir_pos_inzip;
-    uInt size_global_comment;
-    if (file == NULL)
-        return ZIP_PARAMERROR;
-    zi = (zip_internal*)file;
-
-    if (zi->in_opened_file_inzip == 1)
-    {
-        err = zipCloseFileInZip (file);
-    }
-
-#ifndef NO_ADDFILEINEXISTINGZIP
-    if (global_comment==NULL)
-        global_comment = zi->globalcomment;
-#endif
-    if (global_comment==NULL)
-        size_global_comment = 0;
-    else
-        size_global_comment = (uInt)strlen(global_comment);
-
-    centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream);
-    if (err==ZIP_OK)
-    {
-        linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
-        while (ldi!=NULL)
-        {
-            if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
-                if (ZWRITE(zi->z_filefunc,zi->filestream,
-                           ldi->data,ldi->filled_in_this_block)
-                              !=ldi->filled_in_this_block )
-                    err = ZIP_ERRNO;
-
-            size_centraldir += ldi->filled_in_this_block;
-            ldi = ldi->next_datablock;
-        }
-    }
-    free_datablock(zi->central_dir.first_block);
-
-    if (err==ZIP_OK) /* Magic End */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
-
-    if (err==ZIP_OK) /* number of this disk */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
-
-    if (err==ZIP_OK) /* number of the disk with the start of the central directory */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
-
-    if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
-
-    if (err==ZIP_OK) /* total number of entries in the central dir */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
-
-    if (err==ZIP_OK) /* size of the central directory */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
-
-    if (err==ZIP_OK) /* offset of start of central directory with respect to the
-                            starting disk number */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,
-                                (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
-
-    if (err==ZIP_OK) /* zipfile comment length */
-        err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
-
-    if ((err==ZIP_OK) && (size_global_comment>0))
-        if (ZWRITE(zi->z_filefunc,zi->filestream,
-                   global_comment,size_global_comment) != size_global_comment)
-                err = ZIP_ERRNO;
-
-    if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0)
-        if (err == ZIP_OK)
-            err = ZIP_ERRNO;
-
-#ifndef NO_ADDFILEINEXISTINGZIP
-    TRYFREE(zi->globalcomment);
-#endif
-    TRYFREE(zi);
-
-    return err;
-}
--- a/misc/quazip/zip.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/* zip.h -- IO for compress .zip files using zlib
-   Version 1.01e, February 12th, 2005
-
-   Copyright (C) 1998-2005 Gilles Vollant
-
-   This unzip package allow creates .ZIP file, compatible with PKZip 2.04g
-     WinZip, InfoZip tools and compatible.
-   Multi volume ZipFile (span) are not supported.
-   Encryption compatible with pkzip 2.04g only supported
-   Old compressions used by old PKZip 1.x are not supported
-
-  For uncompress .zip file, look at unzip.h
-
-
-   I WAIT FEEDBACK at mail info@winimage.com
-   Visit also http://www.winimage.com/zLibDll/unzip.html for evolution
-
-   Condition of use and distribution are the same than zlib :
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-   Modified by Sergey A. Tachenov to integrate with Qt.
-
-
-*/
-
-/* for more info about .ZIP format, see
-      http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip
-      http://www.info-zip.org/pub/infozip/doc/
-   PkWare has also a specification at :
-      ftp://ftp.pkware.com/probdesc.zip
-*/
-
-#ifndef _zip_H
-#define _zip_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _ZLIB_H
-#include "zlib.h"
-#endif
-
-#ifndef _ZLIBIOAPI_H
-#include "ioapi.h"
-#endif
-
-#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
-/* like the STRICT of WIN32, we define a pointer that cannot be converted
-    from (void*) without cast */
-typedef struct TagzipFile__ { int unused; } zipFile__;
-typedef zipFile__ *zipFile;
-#else
-typedef voidp zipFile;
-#endif
-
-#define ZIP_OK                          (0)
-#define ZIP_EOF                         (0)
-#define ZIP_ERRNO                       (Z_ERRNO)
-#define ZIP_PARAMERROR                  (-102)
-#define ZIP_BADZIPFILE                  (-103)
-#define ZIP_INTERNALERROR               (-104)
-
-#ifndef DEF_MEM_LEVEL
-#  if MAX_MEM_LEVEL >= 8
-#    define DEF_MEM_LEVEL 8
-#  else
-#    define DEF_MEM_LEVEL  MAX_MEM_LEVEL
-#  endif
-#endif
-/* default memLevel */
-
-/* tm_zip contain date/time info */
-typedef struct tm_zip_s
-{
-    uInt tm_sec;            /* seconds after the minute - [0,59] */
-    uInt tm_min;            /* minutes after the hour - [0,59] */
-    uInt tm_hour;           /* hours since midnight - [0,23] */
-    uInt tm_mday;           /* day of the month - [1,31] */
-    uInt tm_mon;            /* months since January - [0,11] */
-    uInt tm_year;           /* years - [1980..2044] */
-} tm_zip;
-
-typedef struct
-{
-    tm_zip      tmz_date;       /* date in understandable format           */
-    uLong       dosDate;       /* if dos_date == 0, tmu_date is used      */
-/*    uLong       flag;        */   /* general purpose bit flag        2 bytes */
-
-    uLong       internal_fa;    /* internal file attributes        2 bytes */
-    uLong       external_fa;    /* external file attributes        4 bytes */
-} zip_fileinfo;
-
-typedef const char* zipcharpc;
-
-
-#define APPEND_STATUS_CREATE        (0)
-#define APPEND_STATUS_CREATEAFTER   (1)
-#define APPEND_STATUS_ADDINZIP      (2)
-
-extern zipFile ZEXPORT zipOpen OF((voidpf file, int append));
-/*
-  Create a zipfile.
-     file is whatever the IO API accepts. For Qt IO API it's a pointer to
-       QIODevice. For fopen() IO API it's a file name (const char*).
-     if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
-       will be created at the end of the file.
-         (useful if the file contain a self extractor code)
-     if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
-       add files in existing zip (be sure you don't add file that doesn't exist)
-     If the zipfile cannot be opened, the return value is NULL.
-     Else, the return value is a zipFile Handle, usable with other function
-       of this zip package.
-*/
-
-/* Note : there is no delete function into a zipfile.
-   If you want delete file into a zipfile, you must open a zipfile, and create another
-   Of couse, you can use RAW reading and writing to copy the file you did not want delte
-*/
-
-extern zipFile ZEXPORT zipOpen2 OF((voidpf file,
-                                   int append,
-                                   zipcharpc* globalcomment,
-                                   zlib_filefunc_def* pzlib_filefunc_def));
-
-extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
-                       const char* filename,
-                       const zip_fileinfo* zipfi,
-                       const void* extrafield_local,
-                       uInt size_extrafield_local,
-                       const void* extrafield_global,
-                       uInt size_extrafield_global,
-                       const char* comment,
-                       int method,
-                       int level));
-/*
-  Open a file in the ZIP for writing.
-  filename : the filename in zip (if NULL, '-' without quote will be used
-  *zipfi contain supplemental information
-  if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
-    contains the extrafield data the the local header
-  if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
-    contains the extrafield data the the local header
-  if comment != NULL, comment contain the comment string
-  method contain the compression method (0 for store, Z_DEFLATED for deflate)
-  level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
-*/
-
-
-extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
-                                            const char* filename,
-                                            const zip_fileinfo* zipfi,
-                                            const void* extrafield_local,
-                                            uInt size_extrafield_local,
-                                            const void* extrafield_global,
-                                            uInt size_extrafield_global,
-                                            const char* comment,
-                                            int method,
-                                            int level,
-                                            int raw));
-
-/*
-  Same than zipOpenNewFileInZip, except if raw=1, we write raw file
- */
-
-extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
-                                            const char* filename,
-                                            const zip_fileinfo* zipfi,
-                                            const void* extrafield_local,
-                                            uInt size_extrafield_local,
-                                            const void* extrafield_global,
-                                            uInt size_extrafield_global,
-                                            const char* comment,
-                                            int method,
-                                            int level,
-                                            int raw,
-                                            int windowBits,
-                                            int memLevel,
-                                            int strategy,
-                                            const char* password,
-                                            uLong crcForCtypting));
-
-/*
-  Same than zipOpenNewFileInZip2, except
-    windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
-    password : crypting password (NULL for no crypting)
-    crcForCtypting : crc of file to compress (needed for crypting)
- */
-
-
-extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
-                       const void* buf,
-                       unsigned len));
-/*
-  Write data in the zipfile
-*/
-
-extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
-/*
-  Close the current file in the zipfile
-*/
-
-extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
-                                            uLong uncompressed_size,
-                                            uLong crc32));
-/*
-  Close the current file in the zipfile, for fiel opened with
-    parameter raw=1 in zipOpenNewFileInZip2
-  uncompressed_size and crc32 are value for the uncompressed size
-*/
-
-extern int ZEXPORT zipClose OF((zipFile file,
-                const char* global_comment));
-/*
-  Close the zipfile
-*/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _zip_H */
--- a/misc/quazip/zlib.h	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1368 +0,0 @@
-/* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.2.3, July 18th, 2005
-
-  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  Jean-loup Gailly        Mark Adler
-  jloup@gzip.org          madler@alumni.caltech.edu
-
-
-  The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
-  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
-*/
-
-#ifndef ZLIB_H
-#define ZLIB_H
-
-#include "zconf.h"
-#include "qconfig.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ZLIB_VERSION "1.2.3"
-#define ZLIB_VERNUM 0x1230
-
-#if defined(QT_VISIBILITY_AVAILABLE)
-# define Q_ZEXPORT __attribute__((visibility("default")))
-#else
-# ifdef QT_MAKEDLL
-# define Q_ZEXPORT __declspec(dllexport)
-# else
-# define Q_ZEXPORT ZEXPORT
-# endif
-#endif
-
-/*
-     The 'zlib' compression library provides in-memory compression and
-  decompression functions, including integrity checks of the uncompressed
-  data.  This version of the library supports only one compression method
-  (deflation) but other algorithms will be added later and will have the same
-  stream interface.
-
-     Compression can be done in a single step if the buffers are large
-  enough (for example if an input file is mmap'ed), or can be done by
-  repeated calls of the compression function.  In the latter case, the
-  application must provide more input and/or consume the output
-  (providing more output space) before each call.
-
-     The compressed data format used by default by the in-memory functions is
-  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
-  around a deflate stream, which is itself documented in RFC 1951.
-
-     The library also supports reading and writing files in gzip (.gz) format
-  with an interface similar to that of stdio using the functions that start
-  with "gz".  The gzip format is different from the zlib format.  gzip is a
-  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
-
-     This library can optionally read and write gzip streams in memory as well.
-
-     The zlib format was designed to be compact and fast for use in memory
-  and on communications channels.  The gzip format was designed for single-
-  file compression on file systems, has a larger header than zlib to maintain
-  directory information, and uses a different, slower check method than zlib.
-
-     The library does not install any signal handler. The decoder checks
-  the consistency of the compressed data, so the library should never
-  crash even in case of corrupted input.
-*/
-
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
-
-struct internal_state;
-
-typedef struct z_stream_s {
-    Bytef    *next_in;  /* next input byte */
-    uInt     avail_in;  /* number of bytes available at next_in */
-    uLong    total_in;  /* total nb of input bytes read so far */
-
-    Bytef    *next_out; /* next output byte should be put there */
-    uInt     avail_out; /* remaining free space at next_out */
-    uLong    total_out; /* total nb of bytes output so far */
-
-    char     *msg;      /* last error message, NULL if no error */
-    struct internal_state FAR *state; /* not visible by applications */
-
-    alloc_func zalloc;  /* used to allocate the internal state */
-    free_func  zfree;   /* used to free the internal state */
-    voidpf     opaque;  /* private data object passed to zalloc and zfree */
-
-    int     data_type;  /* best guess about the data type: binary or text */
-    uLong   adler;      /* adler32 value of the uncompressed data */
-    uLong   reserved;   /* reserved for future use */
-} z_stream;
-
-typedef z_stream FAR *z_streamp;
-
-/*
-     gzip header information passed to and from zlib routines.  See RFC 1952
-  for more details on the meanings of these fields.
-*/
-typedef struct gz_header_s {
-    int     text;       /* true if compressed data believed to be text */
-    uLong   time;       /* modification time */
-    int     xflags;     /* extra flags (not used when writing a gzip file) */
-    int     os;         /* operating system */
-    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
-    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
-    uInt    extra_max;  /* space at extra (only when reading header) */
-    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
-    uInt    name_max;   /* space at name (only when reading header) */
-    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
-    uInt    comm_max;   /* space at comment (only when reading header) */
-    int     hcrc;       /* true if there was or will be a header crc */
-    int     done;       /* true when done reading gzip header (not used
-                           when writing a gzip file) */
-} gz_header;
-
-typedef gz_header FAR *gz_headerp;
-
-/*
-   The application must update next_in and avail_in when avail_in has
-   dropped to zero. It must update next_out and avail_out when avail_out
-   has dropped to zero. The application must initialize zalloc, zfree and
-   opaque before calling the init function. All other fields are set by the
-   compression library and must not be updated by the application.
-
-   The opaque value provided by the application will be passed as the first
-   parameter for calls of zalloc and zfree. This can be useful for custom
-   memory management. The compression library attaches no meaning to the
-   opaque value.
-
-   zalloc must return Z_NULL if there is not enough memory for the object.
-   If zlib is used in a multi-threaded application, zalloc and zfree must be
-   thread safe.
-
-   On 16-bit systems, the functions zalloc and zfree must be able to allocate
-   exactly 65536 bytes, but will not be required to allocate more than this
-   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
-   pointers returned by zalloc for objects of exactly 65536 bytes *must*
-   have their offset normalized to zero. The default allocation function
-   provided by this library ensures this (see zutil.c). To reduce memory
-   requirements and avoid any allocation of 64K objects, at the expense of
-   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
-
-   The fields total_in and total_out can be used for statistics or
-   progress reports. After compression, total_in holds the total size of
-   the uncompressed data and may be saved for use in the decompressor
-   (particularly if the decompressor wants to decompress everything in
-   a single step).
-*/
-
-                        /* constants */
-
-#define Z_NO_FLUSH      0
-#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
-#define Z_SYNC_FLUSH    2
-#define Z_FULL_FLUSH    3
-#define Z_FINISH        4
-#define Z_BLOCK         5
-/* Allowed flush values; see deflate() and inflate() below for details */
-
-#define Z_OK            0
-#define Z_STREAM_END    1
-#define Z_NEED_DICT     2
-#define Z_ERRNO        (-1)
-#define Z_STREAM_ERROR (-2)
-#define Z_DATA_ERROR   (-3)
-#define Z_MEM_ERROR    (-4)
-#define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
-/* Return codes for the compression/decompression functions. Negative
- * values are errors, positive values are used for special but normal events.
- */
-
-#define Z_NO_COMPRESSION         0
-#define Z_BEST_SPEED             1
-#define Z_BEST_COMPRESSION       9
-#define Z_DEFAULT_COMPRESSION  (-1)
-/* compression levels */
-
-#define Z_FILTERED            1
-#define Z_HUFFMAN_ONLY        2
-#define Z_RLE                 3
-#define Z_FIXED               4
-#define Z_DEFAULT_STRATEGY    0
-/* compression strategy; see deflateInit2() below for details */
-
-#define Z_BINARY   0
-#define Z_TEXT     1
-#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
-#define Z_UNKNOWN  2
-/* Possible values of the data_type field (though see inflate()) */
-
-#define Z_DEFLATED   8
-/* The deflate compression method (the only one supported in this version) */
-
-#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
-
-#define zlib_version zlibVersion()
-/* for compatibility with versions < 1.0.2 */
-
-                        /* basic functions */
-
-ZEXTERN Q_ZEXPORT const char * zlibVersion OF((void));
-/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
-   If the first character differs, the library code actually used is
-   not compatible with the zlib.h header file used by the application.
-   This check is automatically made by deflateInit and inflateInit.
- */
-
-/*
-ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
-
-     Initializes the internal stream state for compression. The fields
-   zalloc, zfree and opaque must be initialized before by the caller.
-   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
-   use default allocation functions.
-
-     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
-   1 gives best speed, 9 gives best compression, 0 gives no compression at
-   all (the input data is simply copied a block at a time).
-   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
-   compression (currently equivalent to level 6).
-
-     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
-   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
-   with the version assumed by the caller (ZLIB_VERSION).
-   msg is set to null if there is no error message.  deflateInit does not
-   perform any compression: this will be done by deflate().
-*/
-
-
-ZEXTERN int Q_ZEXPORT deflate OF((z_streamp strm, int flush));
-/*
-    deflate compresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may introduce some
-  output latency (reading input without producing any output) except when
-  forced to flush.
-
-    The detailed semantics are as follows. deflate performs one or both of the
-  following actions:
-
-  - Compress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in and avail_in are updated and
-    processing will resume at this point for the next call of deflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly. This action is forced if the parameter flush is non zero.
-    Forcing flush frequently degrades the compression ratio, so this parameter
-    should be set only when necessary (in interactive applications).
-    Some output may be provided even if flush is not set.
-
-  Before the call of deflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating avail_in or avail_out accordingly; avail_out
-  should never be zero before the call. The application can consume the
-  compressed output when it wants, for example when the output buffer is full
-  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
-  and with zero avail_out, it must be called again after making room in the
-  output buffer because there might be more output pending.
-
-    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
-  decide how much data to accumualte before producing output, in order to
-  maximize compression.
-
-    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
-  flushed to the output buffer and the output is aligned on a byte boundary, so
-  that the decompressor can get all input data available so far. (In particular
-  avail_in is zero after the call if enough output space has been provided
-  before the call.)  Flushing may degrade compression for some compression
-  algorithms and so it should be used only when necessary.
-
-    If flush is set to Z_FULL_FLUSH, all output is flushed as with
-  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
-  restart from this point if previous compressed data has been damaged or if
-  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
-  compression.
-
-    If deflate returns with avail_out == 0, this function must be called again
-  with the same value of the flush parameter and more output space (updated
-  avail_out), until the flush is complete (deflate returns with non-zero
-  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
-  avail_out is greater than six to avoid repeated flush markers due to
-  avail_out == 0 on return.
-
-    If the parameter flush is set to Z_FINISH, pending input is processed,
-  pending output is flushed and deflate returns with Z_STREAM_END if there
-  was enough output space; if deflate returns with Z_OK, this function must be
-  called again with Z_FINISH and more output space (updated avail_out) but no
-  more input data, until it returns with Z_STREAM_END or an error. After
-  deflate has returned Z_STREAM_END, the only possible operations on the
-  stream are deflateReset or deflateEnd.
-
-    Z_FINISH can be used immediately after deflateInit if all the compression
-  is to be done in a single step. In this case, avail_out must be at least
-  the value returned by deflateBound (see below). If deflate does not return
-  Z_STREAM_END, then it must be called again as described above.
-
-    deflate() sets strm->adler to the adler32 checksum of all input read
-  so far (that is, total_in bytes).
-
-    deflate() may update strm->data_type if it can make a good guess about
-  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
-  binary. This field is only for information purposes and does not affect
-  the compression algorithm in any manner.
-
-    deflate() returns Z_OK if some progress has been made (more input
-  processed or more output produced), Z_STREAM_END if all input has been
-  consumed and all output has been produced (only when flush is set to
-  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
-  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
-  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
-  fatal, and deflate() can be called again with more input and more output
-  space to continue compressing.
-*/
-
-
-ZEXTERN int Q_ZEXPORT deflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
-   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
-   prematurely (some input or output was discarded). In the error case,
-   msg may be set but then points to a static string (which must not be
-   deallocated).
-*/
-
-
-/*
-ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
-
-     Initializes the internal stream state for decompression. The fields
-   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
-   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
-   value depends on the compression method), inflateInit determines the
-   compression method from the zlib header and allocates all data structures
-   accordingly; otherwise the allocation will be deferred to the first call of
-   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
-   use default allocation functions.
-
-     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
-   version assumed by the caller.  msg is set to null if there is no error
-   message. inflateInit does not perform any decompression apart from reading
-   the zlib header if present: this will be done by inflate().  (So next_in and
-   avail_in may be modified, but next_out and avail_out are unchanged.)
-*/
-
-
-ZEXTERN int Q_ZEXPORT inflate OF((z_streamp strm, int flush));
-/*
-    inflate decompresses as much data as possible, and stops when the input
-  buffer becomes empty or the output buffer becomes full. It may introduce
-  some output latency (reading input without producing any output) except when
-  forced to flush.
-
-  The detailed semantics are as follows. inflate performs one or both of the
-  following actions:
-
-  - Decompress more input starting at next_in and update next_in and avail_in
-    accordingly. If not all input can be processed (because there is not
-    enough room in the output buffer), next_in is updated and processing
-    will resume at this point for the next call of inflate().
-
-  - Provide more output starting at next_out and update next_out and avail_out
-    accordingly.  inflate() provides as much output as possible, until there
-    is no more input data or no more space in the output buffer (see below
-    about the flush parameter).
-
-  Before the call of inflate(), the application should ensure that at least
-  one of the actions is possible, by providing more input and/or consuming
-  more output, and updating the next_* and avail_* values accordingly.
-  The application can consume the uncompressed output when it wants, for
-  example when the output buffer is full (avail_out == 0), or after each
-  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
-  must be called again after making room in the output buffer because there
-  might be more output pending.
-
-    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
-  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
-  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
-  if and when it gets to the next deflate block boundary. When decoding the
-  zlib or gzip format, this will cause inflate() to return immediately after
-  the header and before the first block. When doing a raw inflate, inflate()
-  will go ahead and process the first block, and will return when it gets to
-  the end of that block, or when it runs out of data.
-
-    The Z_BLOCK option assists in appending to or combining deflate streams.
-  Also to assist in this, on return inflate() will set strm->data_type to the
-  number of unused bits in the last byte taken from strm->next_in, plus 64
-  if inflate() is currently decoding the last block in the deflate stream,
-  plus 128 if inflate() returned immediately after decoding an end-of-block
-  code or decoding the complete header up to just before the first byte of the
-  deflate stream. The end-of-block will not be indicated until all of the
-  uncompressed data from that block has been written to strm->next_out.  The
-  number of unused bits may in general be greater than seven, except when
-  bit 7 of data_type is set, in which case the number of unused bits will be
-  less than eight.
-
-    inflate() should normally be called until it returns Z_STREAM_END or an
-  error. However if all decompression is to be performed in a single step
-  (a single call of inflate), the parameter flush should be set to
-  Z_FINISH. In this case all pending input is processed and all pending
-  output is flushed; avail_out must be large enough to hold all the
-  uncompressed data. (The size of the uncompressed data may have been saved
-  by the compressor for this purpose.) The next operation on this stream must
-  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
-  is never required, but can be used to inform inflate that a faster approach
-  may be used for the single inflate() call.
-
-     In this implementation, inflate() always flushes as much output as
-  possible to the output buffer, and always uses the faster approach on the
-  first call. So the only effect of the flush parameter in this implementation
-  is on the return value of inflate(), as noted below, or when it returns early
-  because Z_BLOCK is used.
-
-     If a preset dictionary is needed after this call (see inflateSetDictionary
-  below), inflate sets strm->adler to the adler32 checksum of the dictionary
-  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
-  strm->adler to the adler32 checksum of all output produced so far (that is,
-  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
-  below. At the end of the stream, inflate() checks that its computed adler32
-  checksum is equal to that saved by the compressor and returns Z_STREAM_END
-  only if the checksum is correct.
-
-    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
-  deflate data.  The header type is detected automatically.  Any information
-  contained in the gzip header is not retained, so applications that need that
-  information should instead use raw inflate, see inflateInit2() below, or
-  inflateBack() and perform their own processing of the gzip header and
-  trailer.
-
-    inflate() returns Z_OK if some progress has been made (more input processed
-  or more output produced), Z_STREAM_END if the end of the compressed data has
-  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
-  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
-  corrupted (input stream not conforming to the zlib format or incorrect check
-  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
-  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
-  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
-  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
-  inflate() can be called again with more input and more output space to
-  continue decompressing. If Z_DATA_ERROR is returned, the application may then
-  call inflateSync() to look for a good compression block if a partial recovery
-  of the data is desired.
-*/
-
-
-ZEXTERN int Q_ZEXPORT inflateEnd OF((z_streamp strm));
-/*
-     All dynamically allocated data structures for this stream are freed.
-   This function discards any unprocessed input and does not flush any
-   pending output.
-
-     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
-   was inconsistent. In the error case, msg may be set but then points to a
-   static string (which must not be deallocated).
-*/
-
-                        /* Advanced functions */
-
-/*
-    The following functions are needed only in some special applications.
-*/
-
-/*
-ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
-                                     int  level,
-                                     int  method,
-                                     int  windowBits,
-                                     int  memLevel,
-                                     int  strategy));
-
-     This is another version of deflateInit with more compression options. The
-   fields next_in, zalloc, zfree and opaque must be initialized before by
-   the caller.
-
-     The method parameter is the compression method. It must be Z_DEFLATED in
-   this version of the library.
-
-     The windowBits parameter is the base two logarithm of the window size
-   (the size of the history buffer). It should be in the range 8..15 for this
-   version of the library. Larger values of this parameter result in better
-   compression at the expense of memory usage. The default value is 15 if
-   deflateInit is used instead.
-
-     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
-   determines the window size. deflate() will then generate raw deflate data
-   with no zlib header or trailer, and will not compute an adler32 check value.
-
-     windowBits can also be greater than 15 for optional gzip encoding. Add
-   16 to windowBits to write a simple gzip header and trailer around the
-   compressed data instead of a zlib wrapper. The gzip header will have no
-   file name, no extra data, no comment, no modification time (set to zero),
-   no header crc, and the operating system will be set to 255 (unknown).  If a
-   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
-
-     The memLevel parameter specifies how much memory should be allocated
-   for the internal compression state. memLevel=1 uses minimum memory but
-   is slow and reduces compression ratio; memLevel=9 uses maximum memory
-   for optimal speed. The default value is 8. See zconf.h for total memory
-   usage as a function of windowBits and memLevel.
-
-     The strategy parameter is used to tune the compression algorithm. Use the
-   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match), or Z_RLE to limit match distances to one (run-length
-   encoding). Filtered data consists mostly of small values with a somewhat
-   random distribution. In this case, the compression algorithm is tuned to
-   compress them better. The effect of Z_FILTERED is to force more Huffman
-   coding and less string matching; it is somewhat intermediate between
-   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
-   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
-   parameter only affects the compression ratio but not the correctness of the
-   compressed output even if it is not set appropriately.  Z_FIXED prevents the
-   use of dynamic Huffman codes, allowing for a simpler decoder for special
-   applications.
-
-      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
-   method). msg is set to null if there is no error message.  deflateInit2 does
-   not perform any compression: this will be done by deflate().
-*/
-
-ZEXTERN int Q_ZEXPORT deflateSetDictionary OF((z_streamp strm,
-                                             const Bytef *dictionary,
-                                             uInt  dictLength));
-/*
-     Initializes the compression dictionary from the given byte sequence
-   without producing any compressed output. This function must be called
-   immediately after deflateInit, deflateInit2 or deflateReset, before any
-   call of deflate. The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
-
-     The dictionary should consist of strings (byte sequences) that are likely
-   to be encountered later in the data to be compressed, with the most commonly
-   used strings preferably put towards the end of the dictionary. Using a
-   dictionary is most useful when the data to be compressed is short and can be
-   predicted with good accuracy; the data can then be compressed better than
-   with the default empty dictionary.
-
-     Depending on the size of the compression data structures selected by
-   deflateInit or deflateInit2, a part of the dictionary may in effect be
-   discarded, for example if the dictionary is larger than the window size in
-   deflate or deflate2. Thus the strings most likely to be useful should be
-   put at the end of the dictionary, not at the front. In addition, the
-   current implementation of deflate will use at most the window size minus
-   262 bytes of the provided dictionary.
-
-     Upon return of this function, strm->adler is set to the adler32 value
-   of the dictionary; the decompressor may later use this value to determine
-   which dictionary has been used by the compressor. (The adler32 value
-   applies to the whole dictionary even if only a subset of the dictionary is
-   actually used by the compressor.) If a raw deflate was requested, then the
-   adler32 value is not computed and strm->adler is not set.
-
-     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent (for example if deflate has already been called for this stream
-   or if the compression method is bsort). deflateSetDictionary does not
-   perform any compression: this will be done by deflate().
-*/
-
-ZEXTERN int Q_ZEXPORT deflateCopy OF((z_streamp dest,
-                                    z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.
-
-     This function can be useful when several compression strategies will be
-   tried, for example when there are several ways of pre-processing the input
-   data with a filter. The streams that will be discarded should then be freed
-   by calling deflateEnd.  Note that deflateCopy duplicates the internal
-   compression state which can be quite large, so this strategy is slow and
-   can consume lots of memory.
-
-     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-ZEXTERN int Q_ZEXPORT deflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to deflateEnd followed by deflateInit,
-   but does not free and reallocate all the internal compression state.
-   The stream will keep the same compression level and any other attributes
-   that may have been set by deflateInit2.
-
-      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-ZEXTERN int Q_ZEXPORT deflateParams OF((z_streamp strm,
-                                      int level,
-                                      int strategy));
-/*
-     Dynamically update the compression level and compression strategy.  The
-   interpretation of level and strategy is as in deflateInit2.  This can be
-   used to switch between compression and straight copy of the input data, or
-   to switch to a different kind of input data requiring a different
-   strategy. If the compression level is changed, the input available so far
-   is compressed with the old level (and may be flushed); the new level will
-   take effect only at the next call of deflate().
-
-     Before the call of deflateParams, the stream state must be set as for
-   a call of deflate(), since the currently available input may have to
-   be compressed and flushed. In particular, strm->avail_out must be non-zero.
-
-     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
-   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
-   if strm->avail_out was zero.
-*/
-
-ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
-                                    int good_length,
-                                    int max_lazy,
-                                    int nice_length,
-                                    int max_chain));
-/*
-     Fine tune deflate's internal compression parameters.  This should only be
-   used by someone who understands the algorithm used by zlib's deflate for
-   searching for the best matching string, and even then only by the most
-   fanatic optimizer trying to squeeze out the last compressed bit for their
-   specific input data.  Read the deflate.c source code for the meaning of the
-   max_lazy, good_length, nice_length, and max_chain parameters.
-
-     deflateTune() can be called after deflateInit() or deflateInit2(), and
-   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
- */
-
-ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
-                                       uLong sourceLen));
-/*
-     deflateBound() returns an upper bound on the compressed size after
-   deflation of sourceLen bytes.  It must be called after deflateInit()
-   or deflateInit2().  This would be used to allocate an output buffer
-   for deflation in a single pass, and so would be called before deflate().
-*/
-
-ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
-                                     int bits,
-                                     int value));
-/*
-     deflatePrime() inserts bits in the deflate output stream.  The intent
-  is that this function is used to start off the deflate output with the
-  bits leftover from a previous deflate stream when appending to it.  As such,
-  this function can only be used for raw deflate, and must be used before the
-  first deflate() call after a deflateInit2() or deflateReset().  bits must be
-  less than or equal to 16, and that many of the least significant bits of
-  value will be inserted in the output.
-
-      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent.
-*/
-
-ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
-                                         gz_headerp head));
-/*
-      deflateSetHeader() provides gzip header information for when a gzip
-   stream is requested by deflateInit2().  deflateSetHeader() may be called
-   after deflateInit2() or deflateReset() and before the first call of
-   deflate().  The text, time, os, extra field, name, and comment information
-   in the provided gz_header structure are written to the gzip header (xflag is
-   ignored -- the extra flags are set according to the compression level).  The
-   caller must assure that, if not Z_NULL, name and comment are terminated with
-   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
-   available there.  If hcrc is true, a gzip header crc is included.  Note that
-   the current versions of the command-line version of gzip (up through version
-   1.3.x) do not support header crc's, and will report that it is a "multi-part
-   gzip file" and give up.
-
-      If deflateSetHeader is not used, the default gzip header has text false,
-   the time set to zero, and os set to 255, with no extra, name, or comment
-   fields.  The gzip header is returned to the default state by deflateReset().
-
-      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent.
-*/
-
-/*
-ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
-                                     int  windowBits));
-
-     This is another version of inflateInit with an extra parameter. The
-   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
-   before by the caller.
-
-     The windowBits parameter is the base two logarithm of the maximum window
-   size (the size of the history buffer).  It should be in the range 8..15 for
-   this version of the library. The default value is 15 if inflateInit is used
-   instead. windowBits must be greater than or equal to the windowBits value
-   provided to deflateInit2() while compressing, or it must be equal to 15 if
-   deflateInit2() was not used. If a compressed stream with a larger window
-   size is given as input, inflate() will return with the error code
-   Z_DATA_ERROR instead of trying to allocate a larger window.
-
-     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
-   determines the window size. inflate() will then process raw deflate data,
-   not looking for a zlib or gzip header, not generating a check value, and not
-   looking for any check values for comparison at the end of the stream. This
-   is for use with other formats that use the deflate compressed data format
-   such as zip.  Those formats provide their own check values. If a custom
-   format is developed using the raw deflate format for compressed data, it is
-   recommended that a check value such as an adler32 or a crc32 be applied to
-   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
-   most applications, the zlib format should be used as is. Note that comments
-   above on the use in deflateInit2() applies to the magnitude of windowBits.
-
-     windowBits can also be greater than 15 for optional gzip decoding. Add
-   32 to windowBits to enable zlib and gzip decoding with automatic header
-   detection, or add 16 to decode only the gzip format (the zlib format will
-   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
-   a crc32 instead of an adler32.
-
-     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
-   is set to null if there is no error message.  inflateInit2 does not perform
-   any decompression apart from reading the zlib header if present: this will
-   be done by inflate(). (So next_in and avail_in may be modified, but next_out
-   and avail_out are unchanged.)
-*/
-
-ZEXTERN int Q_ZEXPORT inflateSetDictionary OF((z_streamp strm,
-                                             const Bytef *dictionary,
-                                             uInt  dictLength));
-/*
-     Initializes the decompression dictionary from the given uncompressed byte
-   sequence. This function must be called immediately after a call of inflate,
-   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
-   can be determined from the adler32 value returned by that call of inflate.
-   The compressor and decompressor must use exactly the same dictionary (see
-   deflateSetDictionary).  For raw inflate, this function can be called
-   immediately after inflateInit2() or inflateReset() and before any call of
-   inflate() to set the dictionary.  The application must insure that the
-   dictionary that was used for compression is provided.
-
-     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
-   parameter is invalid (such as NULL dictionary) or the stream state is
-   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
-   expected one (incorrect adler32 value). inflateSetDictionary does not
-   perform any decompression: this will be done by subsequent calls of
-   inflate().
-*/
-
-ZEXTERN int Q_ZEXPORT inflateSync OF((z_streamp strm));
-/*
-    Skips invalid compressed data until a full flush point (see above the
-  description of deflate with Z_FULL_FLUSH) can be found, or until all
-  available input is skipped. No output is provided.
-
-    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
-  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
-  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
-  case, the application may save the current current value of total_in which
-  indicates where valid compressed data was found. In the error case, the
-  application may repeatedly call inflateSync, providing more input each time,
-  until success or end of the input data.
-*/
-
-ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
-                                    z_streamp source));
-/*
-     Sets the destination stream as a complete copy of the source stream.
-
-     This function can be useful when randomly accessing a large stream.  The
-   first pass through the stream can periodically record the inflate state,
-   allowing restarting inflate at those points when randomly accessing the
-   stream.
-
-     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
-   (such as zalloc being NULL). msg is left unchanged in both source and
-   destination.
-*/
-
-ZEXTERN int Q_ZEXPORT inflateReset OF((z_streamp strm));
-/*
-     This function is equivalent to inflateEnd followed by inflateInit,
-   but does not free and reallocate all the internal decompression state.
-   The stream will keep attributes that may have been set by inflateInit2.
-
-      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent (such as zalloc or state being NULL).
-*/
-
-ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
-                                     int bits,
-                                     int value));
-/*
-     This function inserts bits in the inflate input stream.  The intent is
-  that this function is used to start inflating at a bit position in the
-  middle of a byte.  The provided bits will be used before any bytes are used
-  from next_in.  This function should only be used with raw inflate, and
-  should be used before the first inflate() call after inflateInit2() or
-  inflateReset().  bits must be less than or equal to 16, and that many of the
-  least significant bits of value will be inserted in the input.
-
-      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent.
-*/
-
-ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
-                                         gz_headerp head));
-/*
-      inflateGetHeader() requests that gzip header information be stored in the
-   provided gz_header structure.  inflateGetHeader() may be called after
-   inflateInit2() or inflateReset(), and before the first call of inflate().
-   As inflate() processes the gzip stream, head->done is zero until the header
-   is completed, at which time head->done is set to one.  If a zlib stream is
-   being decoded, then head->done is set to -1 to indicate that there will be
-   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
-   force inflate() to return immediately after header processing is complete
-   and before any actual data is decompressed.
-
-      The text, time, xflags, and os fields are filled in with the gzip header
-   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
-   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
-   contains the maximum number of bytes to write to extra.  Once done is true,
-   extra_len contains the actual extra field length, and extra contains the
-   extra field, or that field truncated if extra_max is less than extra_len.
-   If name is not Z_NULL, then up to name_max characters are written there,
-   terminated with a zero unless the length is greater than name_max.  If
-   comment is not Z_NULL, then up to comm_max characters are written there,
-   terminated with a zero unless the length is greater than comm_max.  When
-   any of extra, name, or comment are not Z_NULL and the respective field is
-   not present in the header, then that field is set to Z_NULL to signal its
-   absence.  This allows the use of deflateSetHeader() with the returned
-   structure to duplicate the header.  However if those fields are set to
-   allocated memory, then the application will need to save those pointers
-   elsewhere so that they can be eventually freed.
-
-      If inflateGetHeader is not used, then the header information is simply
-   discarded.  The header is always checked for validity, including the header
-   CRC if present.  inflateReset() will reset the process to discard the header
-   information.  The application would need to call inflateGetHeader() again to
-   retrieve the header from the next gzip stream.
-
-      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent.
-*/
-
-/*
-ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
-                                        unsigned char FAR *window));
-
-     Initialize the internal stream state for decompression using inflateBack()
-   calls.  The fields zalloc, zfree and opaque in strm must be initialized
-   before the call.  If zalloc and zfree are Z_NULL, then the default library-
-   derived memory allocation routines are used.  windowBits is the base two
-   logarithm of the window size, in the range 8..15.  window is a caller
-   supplied buffer of that size.  Except for special applications where it is
-   assured that deflate was used with small window sizes, windowBits must be 15
-   and a 32K byte window must be supplied to be able to decompress general
-   deflate streams.
-
-     See inflateBack() for the usage of these routines.
-
-     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
-   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
-   be allocated, or Z_VERSION_ERROR if the version of the library does not
-   match the version of the header file.
-*/
-
-typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
-typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
-
-ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
-                                    in_func in, void FAR *in_desc,
-                                    out_func out, void FAR *out_desc));
-/*
-     inflateBack() does a raw inflate with a single call using a call-back
-   interface for input and output.  This is more efficient than inflate() for
-   file i/o applications in that it avoids copying between the output and the
-   sliding window by simply making the window itself the output buffer.  This
-   function trusts the application to not change the output buffer passed by
-   the output function, at least until inflateBack() returns.
-
-     inflateBackInit() must be called first to allocate the internal state
-   and to initialize the state with the user-provided window buffer.
-   inflateBack() may then be used multiple times to inflate a complete, raw
-   deflate stream with each call.  inflateBackEnd() is then called to free
-   the allocated state.
-
-     A raw deflate stream is one with no zlib or gzip header or trailer.
-   This routine would normally be used in a utility that reads zip or gzip
-   files and writes out uncompressed files.  The utility would decode the
-   header and process the trailer on its own, hence this routine expects
-   only the raw deflate stream to decompress.  This is different from the
-   normal behavior of inflate(), which expects either a zlib or gzip header and
-   trailer around the deflate stream.
-
-     inflateBack() uses two subroutines supplied by the caller that are then
-   called by inflateBack() for input and output.  inflateBack() calls those
-   routines until it reads a complete deflate stream and writes out all of the
-   uncompressed data, or until it encounters an error.  The function's
-   parameters and return types are defined above in the in_func and out_func
-   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
-   number of bytes of provided input, and a pointer to that input in buf.  If
-   there is no input available, in() must return zero--buf is ignored in that
-   case--and inflateBack() will return a buffer error.  inflateBack() will call
-   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
-   should return zero on success, or non-zero on failure.  If out() returns
-   non-zero, inflateBack() will return with an error.  Neither in() nor out()
-   are permitted to change the contents of the window provided to
-   inflateBackInit(), which is also the buffer that out() uses to write from.
-   The length written by out() will be at most the window size.  Any non-zero
-   amount of input may be provided by in().
-
-     For convenience, inflateBack() can be provided input on the first call by
-   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
-   in() will be called.  Therefore strm->next_in must be initialized before
-   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
-   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
-   must also be initialized, and then if strm->avail_in is not zero, input will
-   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
-
-     The in_desc and out_desc parameters of inflateBack() is passed as the
-   first parameter of in() and out() respectively when they are called.  These
-   descriptors can be optionally used to pass any information that the caller-
-   supplied in() and out() functions need to do their job.
-
-     On return, inflateBack() will set strm->next_in and strm->avail_in to
-   pass back any unused input that was provided by the last in() call.  The
-   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
-   if in() or out() returned an error, Z_DATA_ERROR if there was a format
-   error in the deflate stream (in which case strm->msg is set to indicate the
-   nature of the error), or Z_STREAM_ERROR if the stream was not properly
-   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
-   distinguished using strm->next_in which will be Z_NULL only if in() returned
-   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
-   out() returning non-zero.  (in() will always be called before out(), so
-   strm->next_in is assured to be defined if out() returns non-zero.)  Note
-   that inflateBack() cannot return Z_OK.
-*/
-
-ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
-/*
-     All memory allocated by inflateBackInit() is freed.
-
-     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
-   state was inconsistent.
-*/
-
-ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
-/* Return flags indicating compile-time options.
-
-    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
-     1.0: size of uInt
-     3.2: size of uLong
-     5.4: size of voidpf (pointer)
-     7.6: size of z_off_t
-
-    Compiler, assembler, and debug options:
-     8: DEBUG
-     9: ASMV or ASMINF -- use ASM code
-     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
-     11: 0 (reserved)
-
-    One-time table building (smaller code, but not thread-safe if true):
-     12: BUILDFIXED -- build static block decoding tables when needed
-     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
-     14,15: 0 (reserved)
-
-    Library content (indicates missing functionality):
-     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
-                          deflate code when not needed)
-     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
-                    and decode gzip streams (to avoid linking crc code)
-     18-19: 0 (reserved)
-
-    Operation variations (changes in library functionality):
-     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
-     21: FASTEST -- deflate algorithm with only one, lowest compression level
-     22,23: 0 (reserved)
-
-    The sprintf variant used by gzprintf (zero is best):
-     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
-     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
-     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
-
-    Remainder:
-     27-31: 0 (reserved)
- */
-
-
-                        /* utility functions */
-
-/*
-     The following utility functions are implemented on top of the
-   basic stream-oriented functions. To simplify the interface, some
-   default options are assumed (compression level and memory usage,
-   standard memory allocation functions). The source code of these
-   utility functions can easily be modified if you need special options.
-*/
-
-ZEXTERN int Q_ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
-                                 const Bytef *source, uLong sourceLen));
-/*
-     Compresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be at least the value returned
-   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
-   compressed buffer.
-     This function can be used to compress a whole file at once if the
-   input file is mmap'ed.
-     compress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer.
-*/
-
-ZEXTERN int Q_ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
-                                  const Bytef *source, uLong sourceLen,
-                                  int level));
-/*
-     Compresses the source buffer into the destination buffer. The level
-   parameter has the same meaning as in deflateInit.  sourceLen is the byte
-   length of the source buffer. Upon entry, destLen is the total size of the
-   destination buffer, which must be at least the value returned by
-   compressBound(sourceLen). Upon exit, destLen is the actual size of the
-   compressed buffer.
-
-     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
-   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
-   Z_STREAM_ERROR if the level parameter is invalid.
-*/
-
-ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
-/*
-     compressBound() returns an upper bound on the compressed size after
-   compress() or compress2() on sourceLen bytes.  It would be used before
-   a compress() or compress2() call to allocate the destination buffer.
-*/
-
-ZEXTERN int Q_ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
-                                   const Bytef *source, uLong sourceLen));
-/*
-     Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer. Upon entry, destLen is the total
-   size of the destination buffer, which must be large enough to hold the
-   entire uncompressed data. (The size of the uncompressed data must have
-   been saved previously by the compressor and transmitted to the decompressor
-   by some mechanism outside the scope of this compression library.)
-   Upon exit, destLen is the actual size of the compressed buffer.
-     This function can be used to decompress a whole file at once if the
-   input file is mmap'ed.
-
-     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
-   enough memory, Z_BUF_ERROR if there was not enough room in the output
-   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
-*/
-
-
-typedef voidp gzFile;
-
-ZEXTERN gzFile Q_ZEXPORT gzopen  OF((const char *path, const char *mode));
-/*
-     Opens a gzip (.gz) file for reading or writing. The mode parameter
-   is as in fopen ("rb" or "wb") but can also include a compression level
-   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
-   Huffman only compression as in "wb1h", or 'R' for run-length encoding
-   as in "wb1R". (See the description of deflateInit2 for more information
-   about the strategy parameter.)
-
-     gzopen can be used to read a file which is not in gzip format; in this
-   case gzread will directly read from the file without decompression.
-
-     gzopen returns NULL if the file could not be opened or if there was
-   insufficient memory to allocate the (de)compression state; errno
-   can be checked to distinguish the two cases (if errno is zero, the
-   zlib error is Z_MEM_ERROR).  */
-
-ZEXTERN gzFile Q_ZEXPORT gzdopen  OF((int fd, const char *mode));
-/*
-     gzdopen() associates a gzFile with the file descriptor fd.  File
-   descriptors are obtained from calls like open, dup, creat, pipe or
-   fileno (in the file has been previously opened with fopen).
-   The mode parameter is as in gzopen.
-     The next call of gzclose on the returned gzFile will also close the
-   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
-   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
-     gzdopen returns NULL if there was insufficient memory to allocate
-   the (de)compression state.
-*/
-
-ZEXTERN int Q_ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
-/*
-     Dynamically update the compression level or strategy. See the description
-   of deflateInit2 for the meaning of these parameters.
-     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
-   opened for writing.
-*/
-
-ZEXTERN int Q_ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
-/*
-     Reads the given number of uncompressed bytes from the compressed file.
-   If the input file was not in gzip format, gzread copies the given number
-   of bytes into the buffer.
-     gzread returns the number of uncompressed bytes actually read (0 for
-   end of file, -1 for error). */
-
-ZEXTERN int Q_ZEXPORT    gzwrite OF((gzFile file,
-                                   voidpc buf, unsigned len));
-/*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes actually written
-   (0 in case of error).
-*/
-
-ZEXTERN int Q_ZEXPORT gzprintf OF((gzFile file, const char *format, ...));
-/*
-     Converts, formats, and writes the args to the compressed file under
-   control of the format string, as in fprintf. gzprintf returns the number of
-   uncompressed bytes actually written (0 in case of error).  The number of
-   uncompressed bytes written is limited to 4095. The caller should assure that
-   this limit is not exceeded. If it is exceeded, then gzprintf() will return
-   return an error (0) with nothing written. In this case, there may also be a
-   buffer overflow with unpredictable consequences, which is possible only if
-   zlib was compiled with the insecure functions sprintf() or vsprintf()
-   because the secure snprintf() or vsnprintf() functions were not available.
-*/
-
-ZEXTERN int Q_ZEXPORT gzputs OF((gzFile file, const char *s));
-/*
-      Writes the given null-terminated string to the compressed file, excluding
-   the terminating null character.
-      gzputs returns the number of characters written, or -1 in case of error.
-*/
-
-ZEXTERN Q_ZEXPORT char * gzgets OF((gzFile file, char *buf, int len));
-/*
-      Reads bytes from the compressed file until len-1 characters are read, or
-   a newline character is read and transferred to buf, or an end-of-file
-   condition is encountered.  The string is then terminated with a null
-   character.
-      gzgets returns buf, or Z_NULL in case of error.
-*/
-
-ZEXTERN int Q_ZEXPORT    gzputc OF((gzFile file, int c));
-/*
-      Writes c, converted to an unsigned char, into the compressed file.
-   gzputc returns the value that was written, or -1 in case of error.
-*/
-
-ZEXTERN int Q_ZEXPORT    gzgetc OF((gzFile file));
-/*
-      Reads one byte from the compressed file. gzgetc returns this byte
-   or -1 in case of end of file or error.
-*/
-
-ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
-/*
-      Push one character back onto the stream to be read again later.
-   Only one character of push-back is allowed.  gzungetc() returns the
-   character pushed, or -1 on failure.  gzungetc() will fail if a
-   character has been pushed but not read yet, or if c is -1. The pushed
-   character will be discarded if the stream is repositioned with gzseek()
-   or gzrewind().
-*/
-
-ZEXTERN int Q_ZEXPORT    gzflush OF((gzFile file, int flush));
-/*
-     Flushes all pending output into the compressed file. The parameter
-   flush is as in the deflate() function. The return value is the zlib
-   error number (see function gzerror below). gzflush returns Z_OK if
-   the flush parameter is Z_FINISH and all output could be flushed.
-     gzflush should be called only when strictly necessary because it can
-   degrade compression.
-*/
-
-ZEXTERN z_off_t Q_ZEXPORT    gzseek OF((gzFile file,
-                                      z_off_t offset, int whence));
-/*
-      Sets the starting position for the next gzread or gzwrite on the
-   given compressed file. The offset represents a number of bytes in the
-   uncompressed data stream. The whence parameter is defined as in lseek(2);
-   the value SEEK_END is not supported.
-     If the file is opened for reading, this function is emulated but can be
-   extremely slow. If the file is opened for writing, only forward seeks are
-   supported; gzseek then compresses a sequence of zeroes up to the new
-   starting position.
-
-      gzseek returns the resulting offset location as measured in bytes from
-   the beginning of the uncompressed stream, or -1 in case of error, in
-   particular if the file is opened for writing and the new starting position
-   would be before the current position.
-*/
-
-ZEXTERN int Q_ZEXPORT    gzrewind OF((gzFile file));
-/*
-     Rewinds the given file. This function is supported only for reading.
-
-   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
-*/
-
-ZEXTERN z_off_t Q_ZEXPORT    gztell OF((gzFile file));
-/*
-     Returns the starting position for the next gzread or gzwrite on the
-   given compressed file. This position represents a number of bytes in the
-   uncompressed data stream.
-
-   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
-*/
-
-ZEXTERN int Q_ZEXPORT gzeof OF((gzFile file));
-/*
-     Returns 1 when EOF has previously been detected reading the given
-   input stream, otherwise zero.
-*/
-
-ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
-/*
-     Returns 1 if file is being read directly without decompression, otherwise
-   zero.
-*/
-
-ZEXTERN int Q_ZEXPORT    gzclose OF((gzFile file));
-/*
-     Flushes all pending output if necessary, closes the compressed file
-   and deallocates all the (de)compression state. The return value is the zlib
-   error number (see function gzerror below).
-*/
-
-ZEXTERN Q_ZEXPORT const char * gzerror OF((gzFile file, int *errnum));
-/*
-     Returns the error message for the last error which occurred on the
-   given compressed file. errnum is set to zlib error number. If an
-   error occurred in the file system and not in the compression library,
-   errnum is set to Z_ERRNO and the application may consult errno
-   to get the exact error code.
-*/
-
-ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
-/*
-     Clears the error and end-of-file flags for file. This is analogous to the
-   clearerr() function in stdio. This is useful for continuing to read a gzip
-   file that is being written concurrently.
-*/
-
-                        /* checksum functions */
-
-/*
-     These functions are not related to compression but are exported
-   anyway because they might be useful in applications using the
-   compression library.
-*/
-
-ZEXTERN uLong Q_ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
-/*
-     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
-   return the updated checksum. If buf is NULL, this function returns
-   the required initial value for the checksum.
-   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
-   much faster. Usage example:
-
-     uLong adler = adler32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       adler = adler32(adler, buffer, length);
-     }
-     if (adler != original_adler) error();
-*/
-
-ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
-                                          z_off_t len2));
-/*
-     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
-   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
-   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
-   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
-*/
-
-ZEXTERN uLong Q_ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
-/*
-     Update a running CRC-32 with the bytes buf[0..len-1] and return the
-   updated CRC-32. If buf is NULL, this function returns the required initial
-   value for the for the crc. Pre- and post-conditioning (one's complement) is
-   performed within this function so it shouldn't be done by the application.
-   Usage example:
-
-     uLong crc = crc32(0L, Z_NULL, 0);
-
-     while (read_buffer(buffer, length) != EOF) {
-       crc = crc32(crc, buffer, length);
-     }
-     if (crc != original_crc) error();
-*/
-
-ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
-
-/*
-     Combine two CRC-32 check values into one.  For two sequences of bytes,
-   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
-   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
-   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
-   len2.
-*/
-
-
-                        /* various hacks, don't look :) */
-
-/* deflateInit and inflateInit are macros to allow checking the zlib version
- * and the compiler's view of z_stream:
- */
-ZEXTERN int Q_ZEXPORT deflateInit_ OF((z_streamp strm, int level,
-                                     const char *version, int stream_size));
-ZEXTERN int Q_ZEXPORT inflateInit_ OF((z_streamp strm,
-                                     const char *version, int stream_size));
-ZEXTERN int Q_ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
-                                      int windowBits, int memLevel,
-                                      int strategy, const char *version,
-                                      int stream_size));
-ZEXTERN int Q_ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-                                      const char *version, int stream_size));
-ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
-                                         unsigned char FAR *window,
-                                         const char *version,
-                                         int stream_size));
-#define deflateInit(strm, level) \
-        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit(strm) \
-        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
-        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
-                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
-        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
-#define inflateBackInit(strm, windowBits, window) \
-        inflateBackInit_((strm), (windowBits), (window), \
-        ZLIB_VERSION, sizeof(z_stream))
-
-
-#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
-    struct internal_state {int dummy;}; /* hack for buggy compilers */
-#endif
-
-ZEXTERN Q_ZEXPORT const char   * zError           OF((int));
-ZEXTERN int            Q_ZEXPORT inflateSyncPoint OF((z_streamp z));
-ZEXTERN Q_ZEXPORT const uLongf * get_crc_table    OF((void));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ZLIB_H */
--- a/project_files/Android-build/CMakeLists.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/CMakeLists.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -32,7 +32,7 @@
 endif()
 
 if(NOT ANDROID_NDK_TOOLCHAINDIR)
-    set(toolchainbase "${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.4.3/prebuilt")
+    set(toolchainbase "${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt")
     find_path(ANDROID_NDK_TOOLCHAINDIR arm-linux-androideabi
                 "${toolchainbase}/linux-x86"
                 "${toolchainbase}/windows")
@@ -74,7 +74,7 @@
 set(SDL_DIR /home/richard/Downloads/android-project)
 
 
-set(ANDROID_SDK_API_LVL 14)
+set(ANDROID_SDK_API_LVL 16)
 set(ANDROID_NDK_API_LVL 5)
 
 MESSAGE(STATUS "Creating Makefile.android...")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/Licenses/Android Support library/NOTICE.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,195 @@
+Notice for all the files in this folder.
+------------------------------------------------------------
+
+
+
+   Copyright (c) 2005-2008, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/Licenses/ini4j/LICENSE.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/Licenses/ini4j/NOTICE.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,13 @@
+Copyright 2005,2009 Ivan SZKIBA
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/AndroidManifest.xml	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/AndroidManifest.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -1,54 +1,105 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="org.hedgewars.hedgeroid"
-      android:versionCode="8"
-      android:installLocation="preferExternal" android:versionName="0.2">
-    <uses-sdk android:targetSdkVersion="14" android:minSdkVersion="7"></uses-sdk>
-    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
-    <application android:label="@string/app_name" android:icon="@drawable/icon">
-        <activity android:name=".MainActivity"
-                  android:label="@string/app_name"
- 		  		  android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
+    package="org.hedgewars.hedgeroid"
+    android:installLocation="preferExternal"
+    android:versionCode="8"
+    android:versionName="0.2" >
+
+    <uses-sdk
+        android:minSdkVersion="7"
+        android:targetSdkVersion="14" >
+    </uses-sdk>
+
+    <uses-permission android:name="android.permission.INTERNET" >
+    </uses-permission>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
+    </uses-permission>
+
+    <application
+        android:icon="@drawable/icon"
+        android:label="@string/app_name" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="landscape" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <activity android:name=".SDLActivity"
-                  android:label="@string/app_name"
- 		  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-		  android:screenOrientation='landscape'>
+        <activity
+            android:name=".SDLActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="landscape"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+        </activity>
+        <activity
+            android:name=".Downloader.DownloadFragment"
+            android:label="@string/app_name"
+            android:theme="@android:style/Theme.Dialog" >
         </activity>
-        
-        <activity android:name=".Downloader.DownloadFragment"
-                  android:label="@string/app_name"
-				  android:theme="@android:style/Theme.Dialog">
+        <activity
+            android:name=".Downloader.DownloadListActivity"
+            android:label="@string/app_name"
+            android:launchMode="singleTop"
+            android:screenOrientation="landscape"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />
+
+        <service android:name=".Downloader.DownloadService" />
+		
+        <activity
+            android:name=".LocalRoomActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="landscape" >
+        </activity>
+        <activity
+            android:name=".TeamListActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="landscape"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
         </activity>
-        
-        <activity android:name=".Downloader.DownloadListActivity"
-                  android:label="@string/app_name"
-				  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-				  android:screenOrientation='landscape'
-				  android:launchMode="singleTop"/>
-        
-        <service android:name=".Downloader.DownloadService"/>
-        
-        <activity android:name="StartGameActivity"
-                  android:label="@string/app_name"
-				  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-				  android:screenOrientation='landscape'>
+        <activity
+            android:name="TeamCreatorActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="landscape"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+            android:windowSoftInputMode="stateUnchanged" >
+        </activity>
+        <activity
+            android:name=".LobbyActivity"
+            android:label="@string/title_activity_lobby"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustPan" >
+        </activity>
+        <activity
+            android:name=".NetRoomActivity"
+            android:label="@string/title_activity_room"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustPan" >
         </activity>
-        <activity android:name="TeamSelectionActivity"
-                  android:label="@string/app_name"
-				  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-				  android:screenOrientation='landscape'>
+        <activity
+            android:name=".WeaponsetListActivity"
+            android:label="@string/title_activity_weaponset_list"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustPan" >
+        </activity>
+        <activity
+            android:name=".WeaponsetCreatorActivity"
+            android:label="@string/title_activity_weaponset_creator"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustPan" >
         </activity>
-        <activity android:name="TeamCreatorActivity"
-                  android:label="@string/app_name"
-				  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-				  android:screenOrientation='landscape'
-				  android:windowSoftInputMode="stateUnchanged">
+        <activity
+            android:name=".SchemeListActivity"
+            android:label="@string/title_activity_scheme_list"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustPan" >
+        </activity>
+        <activity
+            android:name=".SchemeCreatorActivity"
+            android:label="@string/title_activity_scheme_creator"
+            android:screenOrientation="landscape"
+            android:windowSoftInputMode="adjustPan" >
         </activity>
     </application>
-</manifest> 
+</manifest>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Airplane.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/AmmoMenu/Ammos.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/AmmoMenu/Ammos_bw.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_42.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_anarchy.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_balrog.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_bars.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_birdy.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_bloodyblade.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_brittany.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_bustamove.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_cog.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_crossedswords.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_dragonrb.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_earth.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_earth2.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_eyeofhorus.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_face.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_fcw.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_female.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_galaxy.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_hax0r.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_hurrah.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_iluvu.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_lips.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_magicskull.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_male.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_mog.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_music.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_pacman.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_pacman2.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_pentagram.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_pirate.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_pokemon.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_scout.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_shoppa.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_sonic.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_spider.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_star.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_swordshield.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_swordshield2.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_vampire.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Flags/cm_yinyang.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Badger.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Cherry.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Duck2.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Earth.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Egg.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Flower.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Ghost.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Grave.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Plinko.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Rip.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Rubberduck.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Simple.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/Statue.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/bp2.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/bubble.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/chest.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/coffin.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/deadhog.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/eyecross.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/heart.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/money.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/mouton1.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/octopus.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/plant2.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/plant3.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/pokeball.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/pyramid.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/ring.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/skull.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Graves/star.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Hats/android.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Hedgehog/amKamikaze.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Hedgehog/amSineGun.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/LandIce.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Molotov.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Progress.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/RCPlane.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/Snow.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/SuddenDeath/SDFlake.png has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Graphics/botlevels.png has changed
--- a/project_files/Android-build/SDL-android-project/assets/Data/Locale/en.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Locale/en.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -79,6 +79,7 @@
 01:18=High
 01:19=Extreme
 01:20=%1 Bounce
+01:21=Audio Muted
 
 ; Event messages
 ; Hog (%1) died
@@ -491,7 +492,7 @@
 04:36=Well, sometimes you're just too bad in aiming. Get|some assistance using modern day technology.|Attack: Activate
 04:37=Don't fear the daylight. It will just last one turn|but will enable you to absorb the damage you do to|other hogs.|Attack: Activate
 04:38=The sniper rifle can be the most devastating weapon|in your whole arsenal, however it's very ineffective|at close quarters. The damage dealt increases with|the distance to its target.|Attack: Shoot (twice)
-04:39=Fly to other parts of the map using the flying|saucer. This hard to master utility is able to|take you to almost any position on the battlefield.|Attack: Activate|Up/Left/Right: Apply force in one direction|Long Jump: Drop grenades or similar weapons
+04:39=Fly to other parts of the map using the flying|saucer. This hard to master utility can|take you to almost any position on the battlefield.|Attack: Activate|Up/Left/Right: Apply force in one direction|Long Jump: Drop grenades or similar weapons
 04:40=Set some ground on fire using this bottle filled|with (soon to be) burning liquid.|Attack: Hold to shoot with more power
 04:41=The evidence nature might even top the flying|saucer. Birdy can carry your hog around and|drop eggs on your enemies!|Be quick, as using Birdy eats into your turn|time!|Attack: Activate and drop eggs|Up/Left/Right: Flap in one direction
 04:42=This portable portal device is capable|of instantly transporting you, your enemies,|or your weaponry between two points on the|terrain.|Use it wisely and your campaign will be a...|HUGE SUCCESS!|Attack: Shoot a portal|Switch: Cycle portal colours
@@ -505,7 +506,7 @@
 04:50=Is someone hiding underground?|Dig them out with a drill strike!|Timer controls how far it will dig.
 04:51=Get in a free shot by hurling a ball of mud.|Stings a bit, and knocks hogs back.
 04:52=UNUSED
-04:53=Go on an adventure through time and space,|while leaving your comrades to fight on alone.|Be prepared to return at any time,|or for Sudden Death or if they are all defeated.|Disclaimer. Does not function in Sudden Death,|if you are alone, or if you are a King.
+04:53=Take a trip through time and space,|while leaving your comrades to fight on alone.|Be prepared to return at any time,|or for Sudden Death or if they are all defeated.|Disclaimer. Does not function in Sudden Death,|if you are alone, or if you are a King.
 04:54=INCOMPLETE                                                                                                                                     
 04:55=Spray a stream of sticky flakes.|Build bridges, bury enemies, seal off tunnels.|Be careful you don't get any on you!
 
Binary file project_files/Android-build/SDL-android-project/assets/Data/Locale/hedgewars_en.qm has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Locale.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,18 @@
+-- Library for localizing strings in lua scripts
+
+local lang = loadfile(GetUserDataPath() .. "Locale/" .. tostring(L) .. ".lua")
+
+if lang ~= nil then
+    lang()
+else
+    lang = loadfile(GetDataPath() .. "Locale/" .. tostring(L) .. ".lua")
+    if lang ~= nil then
+        lang()
+    end
+end
+
+function loc(text)
+    if lang ~= nil and locale ~= nil and locale[text] ~= nil then return locale[text]
+    else return text
+    end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Balanced_Random_Weapon.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+locked
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,148 @@
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer, amBaseballBat, amMortar, amCake, amSeduction, amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane, amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb, amFlamethrower, amSMine, amKamikaze }
+
+--                      G,C,B,B,S,M,D,D,F,W,P,B,M,C,S,W,H,D,B,R,S,M,B,B,G,F,S,K
+local weapons_values = {1,1,1,2,1,1,1,2,1,1,1,2,1,3,1,3,3,2,3,3,1,1,2,1,1,2,2,1}
+
+local airweapons = { amAirAttack, amMineStrike, amNapalm, amDrillStrike }
+
+--                         A,M,N,D
+local airweapons_values = {2,2,2,2}
+
+local utilities = { amTeleport, amGirder, amSwitch, amLowGravity, amResurrector, amRope, amParachute, amJetpack, amPortalGun, amSnowball }
+
+--                        T,G,S,L,R,R,P,J,P,S
+local utilities_values = {1,2,2,1,2,2,1,2,2,2}
+
+function randomAmmo()
+    local n = 3   --"points" to be allocated on weapons
+
+    --pick random weapon and subtract cost
+    local r = GetRandom(table.maxn(weapons_values)) + 1
+    local picked_items = {}
+    table.insert(picked_items, weapons[r])
+    n = n - weapons_values[r]
+
+
+    --choose any weapons or utilities to use up remaining n
+
+    while n > 0 do
+        local items = {}
+        local items_values = {}
+
+        for i, w in pairs(weapons_values) do
+            local used = false
+            if w <= n then
+                --check that this weapon hasn't been given already
+                for j, k in pairs(picked_items) do
+                    if weapons[i] == k then
+                        used = true
+                    end
+                end
+                if not used then
+                    table.insert(items_values, w)
+                    table.insert(items, weapons[i])
+                end
+            end
+        end
+
+        for i, w in pairs(utilities_values) do
+            local used = false
+            if w <= n then
+                --check that this weapon hasn't been given already
+                for j, k in pairs(picked_items) do
+                    if utilities[i] == k then
+                        used = true
+                    end
+                end
+                if not used then
+                    table.insert(items_values, w)
+                    table.insert(items, utilities[i])
+                end
+            end
+        end
+
+        local r = GetRandom(table.maxn(items_values)) + 1
+        table.insert(picked_items, items[r])
+        n = n - items_values[r]
+    end
+
+    return picked_items
+end
+
+function assignAmmo(hog)
+    local name = GetHogTeamName(hog)
+    local processed = getTeamValue(name, "processed")
+    if processed == nil or not processed then
+        local ammo = getTeamValue(name, "ammo")
+        if ammo == nil then
+            ammo = randomAmmo()
+            setTeamValue(name, "ammo", ammo)
+        end
+        for i, w in pairs(ammo) do
+            AddAmmo(hog, w)
+        end
+        setTeamValue(name, "processed", true)
+    end
+end
+
+function reset(hog)
+    setTeamValue(GetHogTeamName(hog), "processed", false)
+end
+
+function onGameInit()
+    GameFlags = band(bor(GameFlags, gfResetWeps), bnot(gfPerHogAmmo))
+    Goals = loc("Each turn you get 1-3 random weapons")
+end
+
+function onGameStart()
+    trackTeams()
+    if MapHasBorder() == false then
+        for i, w in pairs(airweapons) do
+            table.insert(weapons, w)
+        end
+        for i, w in pairs(airweapons_values) do
+            table.insert(weapons_values, w)
+        end
+    end
+end
+
+function onAmmoStoreInit()
+    SetAmmo(amSkip, 9, 0, 0, 0)
+
+    SetAmmo(amExtraDamage, 0, 1, 0, 1)
+    SetAmmo(amInvulnerable, 0, 1, 0, 1)
+    SetAmmo(amExtraTime, 0, 1, 0, 1)
+    SetAmmo(amLaserSight, 0, 1, 0, 1)
+    SetAmmo(amVampiric, 0, 1, 0, 1)
+
+    for i, w in pairs(utilities) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+
+    for i, w in pairs(weapons) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+
+    for i, w in pairs(airweapons) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+end
+
+function onNewTurn()
+    runOnGears(assignAmmo)
+    runOnGears(reset)
+    setTeamValue(GetHogTeamName(CurrentHedgehog), "ammo", nil)
+end
+
+function onGearAdd(gear)
+    if GetGearType(gear) == gtHedgehog then
+        trackGear(gear)
+    end
+end
+
+function onGearDelete(gear)
+    trackDeletion(gear)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Capture_the_Flag.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Capture_the_Flag.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,630 @@
+---------------------------------------
+-- CAPTURE_THE_FLAG GAMEPLAY MODE 0.5
+-- by mikade
+---------------------------------------
+
+-- Version History
+---------
+-- 0.1
+---------
+
+-- [conversion from map-dependant CTF_Blizzard to map independant Capture the Flag]
+-- added an intial starting stage where flagspawn is decided by the players (weapon set will require a jetpack unless I set)
+-- changed the flag from a crate to a visual gear, and all associated methods and checks relating to flags (five hours later, lol)
+-- changed starting/respawning positioning to accommodate different map sizes
+-- added another circle to mark flag spawn
+-- added gameFlag filter
+-- changed scoring feedback
+-- cleaned up some code
+
+-- removing own flag from spawning point no longer possible
+-- destroying flags no longer possible.
+-- added basic glowing circle effect to spawn area
+-- added expanding circle to fgear itself
+
+-- removed teleporters
+-- removed random crate drops (this should be decided by scheme)
+-- removed set map criteria like minesNum, turnTime, explosives etc. except for sudden death
+-- removed weapon defintions
+-- removed placement and respawning methods, hopefully divideTeams will have this covered
+
+---------
+-- 0.2
+---------
+
+-- [now with user friendliness]
+-- flag is now placed wherever you end up at the end of your first turn, this ensures that it is always placed by turn 3
+-- removed a bunch of backup code and no-longer needed variables / methods from CTF_Blizzard days
+-- removed an aura that was still mistakenly hanging about
+-- added an in-game note about placements
+-- added an in-game note about the rules of the game
+-- added translation support and loc()'ed everything
+-- changed things so the seed is no longer always the same...
+
+-- In this version:
+---------
+-- 0.3
+---------
+-- [fufufufu kamikaze fix]
+-- added nill checks to make sure the player doesn't generate errors by producing a nil value in hhs[] when he uses kamikaze
+-- added a check to make sure the player doesn't kamikaze straight down and make the flag's starting point underwater
+-- added a check to make sure the player drops the flag if he has it and he uses kamikaze
+
+--------
+-- 0.4
+--------
+
+-- remove user-branding and version numbers
+-- removed some stuff that wasn't needed
+-- fix piano strike exploit
+-- changed delay to allow for better portals
+-- changed starting feedback a little
+-- increased the radius around the circle indicating the flag thief so that it doesn't obscure his health
+
+--------
+-- 0.5
+--------
+
+-- add support for more players
+-- allow limited sudden death
+-- stop TimeBox ruining my life
+-- profit???
+
+-----------------
+--SCRIPT BEGINS
+-----------------
+
+-- enable awesome translaction support so we can use loc() wherever we want
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+
+---------------------------------------------------------------
+----------lots of bad variables and things
+----------because someone is too lazy
+----------to read about tables properly
+------------------ "Oh well, they probably have the memory"
+
+local gameStarted = false
+local gameTurns = 0
+
+--------------------------
+-- hog and team tracking variales
+--------------------------
+
+local numhhs = 0 -- store number of hedgehogs
+local hhs = {} -- store hedgehog gears
+
+local numTeams --  store the number of teams in the game
+local teamNameArr = {}	-- store the list of teams
+local teamSize = {}	-- store how many hogs per team
+local teamIndex = {} -- at what point in the hhs{} does each team begin
+
+-------------------
+-- flag variables
+-------------------
+
+local fPlaced = {} -- has the flag been placed TRUE/FALSE
+
+local fGear = {}	-- pointer to the visual gears that represent the flag
+local fGearX = {}
+local fGearY = {}
+
+local fThief = {}	-- pointer to the hogs who stole the flags
+local fIsMissing = {}	-- have the flags been destroyed or captured
+local fNeedsRespawn = {}	-- do the flags need to be respawned
+local fCaptures = {}	-- the team "scores" how many captures
+local fSpawnX = {}		-- spawn X for flags
+local fSpawnY = {}		-- spawn Y for flags
+
+local fThiefX = {}
+local fThiefY = {}
+local FTTC = 0 -- flag thief tracker counter
+
+local fSpawnC = {} -- spawn circle marker
+local fCirc = {} -- flag/carrier marker circles
+local fCol = {} -- colour of the clans
+
+local fGearRad = 0
+local fGearRadMin = 5
+local fGearRadMax = 33
+local fGearTimer = 0
+
+------------------------
+--flag methods
+------------------------
+
+function CheckScore(teamID)
+
+	if teamID == 0 then
+		alt = 1
+	elseif teamID == 1 then
+		alt = 0
+	end
+
+	if fCaptures[teamID] == 3 then
+		for i = 0, (numhhs-1) do
+			if hhs[i] ~= nil then
+				if GetHogClan(hhs[i]) == alt then
+					SetEffect(hhs[i], heResurrectable, false)
+					SetHealth(hhs[i],0)
+				end
+			end
+		end
+		if CurrentHedgehog ~= nil then
+			ShowMission(loc("GAME OVER!"), loc("Victory for the ") .. GetHogTeamName(CurrentHedgehog), loc("Hooray!"), 0, 0)
+		end
+	end
+
+end
+
+function DoFlagStuff(gear)
+
+	if (gear == fGear[0]) then
+		wtf = 0
+		bbq = 1
+	elseif (gear == fGear[1]) then
+		wtf = 1
+		bbq = 0
+	end
+
+	-- player has successfully captured the enemy flag
+	if (GetHogClan(CurrentHedgehog) == wtf) and (CurrentHedgehog == fThief[bbq]) and (fIsMissing[wtf] == false) then
+
+		DeleteVisualGear(fGear[wtf])
+		fGear[wtf] = nil -- the flag has now disappeared
+
+		fIsMissing[wtf] = false
+		fNeedsRespawn[wtf] = true
+		fIsMissing[bbq] = false
+		fNeedsRespawn[bbq] = true
+		fCaptures[wtf] = fCaptures[wtf] +1
+		ShowMission(loc("You have SCORED!!"), GetHogTeamName(CurrentHedgehog) .. ": " .. fCaptures[wtf], loc("Opposing Team: ") .. fCaptures[bbq], 0, 0)
+		PlaySound(sndVictory)
+		fThief[bbq] = nil -- player no longer has the enemy flag
+		CheckScore(wtf)
+
+	--if the player is returning the flag
+	elseif (GetHogClan(CurrentHedgehog) == wtf) and (fIsMissing[wtf] == true) then
+
+		DeleteVisualGear(fGear[wtf])
+		fGear[wtf] = nil -- the flag has now disappeared
+
+		fNeedsRespawn[wtf] = true
+		HandleRespawns() -- this will set fIsMissing[wtf] to false :)
+		AddCaption(loc("Flag returned!"))
+
+	--if the player is taking the enemy flag
+	elseif GetHogClan(CurrentHedgehog) == bbq then
+
+		DeleteVisualGear(fGear[wtf])
+		fGear[wtf] = nil -- the flag has now disappeared
+
+		fIsMissing[wtf] = true
+		for i = 0,numhhs-1 do
+			if CurrentHedgehog ~= nil then
+				if CurrentHedgehog == hhs[i] then
+					fThief[wtf] = hhs[i]
+				end
+			end
+		end
+		AddCaption(loc("Flag captured!"))
+
+	end
+
+end
+
+function CheckFlagProximity()
+
+	for i = 0, 1 do
+		if fGear[i] ~= nil then
+
+			g1X = fGearX[i]
+			g1Y = fGearY[i]
+
+			g2X, g2Y = GetGearPosition(CurrentHedgehog)
+
+			q = g1X - g2X
+			w = g1Y - g2Y
+			dist = (q*q) + (w*w)
+
+			if dist < 500 then --1600
+				DoFlagStuff(fGear[i])
+			end
+		end
+	end
+
+end
+
+
+function HandleRespawns()
+
+	for i = 0, 1 do
+
+		if fNeedsRespawn[i] == true then
+			fGear[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
+			fGearX[i] = fSpawnX[i]
+			fGearY[i] = fSpawnY[i]
+
+			fNeedsRespawn[i] = false
+			fIsMissing[i] = false -- new, this should solve problems of a respawned flag being "returned" when a player tries to score
+			AddCaption(loc("Flag respawned!"))
+		end
+
+	end
+
+end
+
+
+function FlagThiefDead(gear)
+
+	if (gear == fThief[0]) then
+		wtf = 0
+		bbq = 1
+	elseif (gear == fThief[1]) then
+		wtf = 1
+		bbq = 0
+	end
+
+	if fThief[wtf] ~= nil then
+		-- falls into water
+		--ShowMission(LAND_HEIGHT,  fThiefY[wtf], (LAND_HEIGHT - fThiefY[wtf]), 0, 0)
+		if (LAND_HEIGHT - fThiefY[wtf]) < 15 then
+			fIsMissing[wtf] = true
+			fNeedsRespawn[wtf] = true
+			HandleRespawns()
+		else	--normally
+			fGearX[wtf]  =  fThiefX[wtf]
+			fGearY[wtf]  =  fThiefY[wtf]
+			fGear[wtf] = AddVisualGear(fGearX[wtf],fGearY[wtf],vgtCircle,0,true)
+		end
+
+		AddVisualGear(fThiefX[wtf], fThiefY[wtf], vgtBigExplosion, 0, false)
+		fThief[wtf] = nil
+	end
+
+end
+
+function HandleCircles()
+
+	fGearTimer = fGearTimer + 1
+	if fGearTimer == 50 then
+		fGearTimer = 0
+		fGearRad = fGearRad + 1
+		if fGearRad > fGearRadMax then
+			fGearRad = fGearRadMin
+		end
+	end
+
+	for i = 0, 1 do
+
+		--SetVisualGearValues(fSpawnC[i], fSpawnX[i],fSpawnY[i], 20, 200, 0, 0, 100, 50, 3, fCol[i]) -- draw a circ for spawning area
+
+		if fIsMissing[i] == false then -- draw a flag marker at the flag's spawning place
+			SetVisualGearValues(fCirc[i], fSpawnX[i],fSpawnY[i], 20, 20, 0, 10, 0, 33, 3, fCol[i])
+			if fGear[i] ~= nil then -- draw the flag gear itself
+				SetVisualGearValues(fGear[i], fSpawnX[i],fSpawnY[i], 20, 200, 0, 0, 100, fGearRad, 2, fCol[i])
+			end
+		elseif (fIsMissing[i] == true) and (fNeedsRespawn[i] == false) then
+			if fThief[i] ~= nil then -- draw circle round flag carrier			-- 33
+				SetVisualGearValues(fCirc[i], fThiefX[i], fThiefY[i], 20, 200, 0, 0, 100, 50, 3, fCol[i])
+				--AddCaption("circle marking carrier")
+			elseif fThief[i] == nil then -- draw cirle round dropped flag
+				--g1X,g1Y,g4,g5,g6,g7,g8,g9,g10,g11 =  GetVisualGearValues(fGear[i])
+				--SetVisualGearValues(fCirc[i], g1X, g1Y, 20, 200, 0, 0, 100, 33, 2, fCol[i])
+				SetVisualGearValues(fCirc[i], fGearX[i], fGearY[i], 20, 200, 0, 0, 100, 33, 3, fCol[i])
+				--AddCaption('dropped circle marker')
+				if fGear[i] ~= nil then -- flag gear itself
+					--SetVisualGearValues(fGear[i], g1X, g1Y, 20, 200, 0, 0, 100, 10, 4, fCol[i])
+					SetVisualGearValues(fGear[i], fGearX[i], fGearY[i], 20, 200, 0, 0, 100, fGearRad, 2, fCol[i])
+					--AddCaption('dropped flag itself')
+				end
+			end
+		end
+
+		if fNeedsRespawn[i] == true then -- if the flag has been destroyed, no need for a circle
+			SetVisualGearValues(fCirc[i], fSpawnX[i],fSpawnY[i], 20, 200, 0, 0, 100, 0, 0, fCol[i])
+			--AddCaption("needs respawn = true. flag 'destroyed'?")
+		end
+	end
+
+end
+
+------------------------
+-- general methods
+------------------------
+
+function CheckDistance(gear1, gear2)
+
+	g1X, g1Y = GetGearPosition(gear1)
+	g2X, g2Y = GetGearPosition(gear2)
+
+	g1X = g1X - g2X
+	g1Y = g1Y - g2Y
+	z = (g1X*g1X) + (g1Y*g1Y)
+
+	dist = z
+
+	return dist
+
+end
+
+function RebuildTeamInfo()
+
+
+	-- make a list of individual team names
+	for i = 0, (TeamsCount-1) do
+		teamNameArr[i] = i
+		teamSize[i] = 0
+		teamIndex[i] = 0
+	end
+	numTeams = 0
+
+	for i = 0, (numhhs-1) do
+
+		z = 0
+		unfinished = true
+		while(unfinished == true) do
+
+			newTeam = true
+			tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name
+
+			if tempHogTeamName == teamNameArr[z] then
+				newTeam = false
+				unfinished = false
+			end
+
+			z = z + 1
+
+			if z == TeamsCount then
+				unfinished = false
+				if newTeam == true then
+					teamNameArr[numTeams] = tempHogTeamName
+					numTeams = numTeams + 1
+				end
+			end
+
+		end
+
+	end
+
+	-- find out how many hogs per team, and the index of the first hog in hhs
+	for i = 0, numTeams-1 do
+
+		for z = 0, numhhs-1 do
+			if GetHogTeamName(hhs[z]) == teamNameArr[i] then
+				if teamSize[i] == 0 then
+					teamIndex[i] = z -- should give starting index
+				end
+				teamSize[i] = teamSize[i] + 1
+				--add a pointer so this hog appears at i in hhs
+			end
+		end
+
+	end
+
+end
+
+function StartTheGame()
+
+	gameStarted = true
+	AddCaption(loc("Game Started!"))
+
+	for i = 0, 1 do
+
+		-- if someone uses kamikaze downwards, this can happen as the hog won't respawn
+		if (LAND_HEIGHT - fSpawnY[i]) < 0 then
+			tempG = AddGear(0, 0, gtTarget, 0, 0, 0, 0)
+     			FindPlace(tempG, true, 0, LAND_WIDTH, true)
+			fSpawnX[i], fSpawnY[i] = GetGearPosition(tempG)
+			DeleteGear(tempG)
+		end
+
+		fGear[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
+		fCirc[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
+		fSpawnC[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
+
+		fGearX[i] = fSpawnX[i]
+		fGearY[i] = fSpawnY[i]
+
+		fCol[i] = GetClanColor(i)
+		fIsMissing[i] = false
+		fNeedsRespawn[i] = false
+		fCaptures[i] = 0
+
+		--SetVisualGearValues(zxc, 1000,1000, 20, 100, 0,    10,                     1,         100,        5,      GetClanColor(0))
+
+		SetVisualGearValues(fSpawnC[i], fSpawnX[i],fSpawnY[i], 20, 100, 0, 10, 0, 75, 5, fCol[i])
+
+	end
+
+end
+
+------------------------
+-- game methods
+------------------------
+
+function onGameInit()
+
+	GameFlags = band(bor(GameFlags, gfDivideTeams), bnot(gfKing + gfForts))
+	--SuddenDeathTurns = 999 -- suddendeath is off, effectively
+	WaterRise = 0
+	Delay = 10
+
+end
+
+
+function onGameStart()
+
+	--ShowMission(loc(caption), loc(subcaption), loc(goal), 0, 0)
+	ShowMission(loc("CAPTURE THE FLAG"), loc("Flags, and their home base will be placed where each team ends their first turn."), "", 0, 0)
+
+	RebuildTeamInfo()
+
+	-- should gfDivideTeams do this automatically?
+	--[[for i = 0, (TeamsCount-1) do
+		for g = teamIndex[i], (teamIndex[i]+teamSize[i]-1) do
+			if GetHogClan(hhs[g]) == 0 then
+				FindPlace(hhs[g], false, 0, LAND_WIDTH/2)
+			elseif GetHogClan(hhs[g]) == 1 then
+				FindPlace(hhs[g], false, LAND_WIDTH/2, LAND_WIDTH)
+			end
+		end
+	end]]
+
+	fPlaced[0] = false
+	fPlaced[1] = false
+
+	--zxc = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
+
+
+	--SetVisualGearValues(zxc, 1000,1000, 20, 255, 1,    10,                     0,         200,        1,      GetClanColor(0))
+					--minO,max0 -glowyornot	--pulsate timer	 -- fuckall      -- radius -- width  -- colour
+end
+
+
+function onNewTurn()
+
+	gameTurns = gameTurns + 1
+
+	if lastTeam ~= GetHogTeamName(CurrentHedgehog) then
+		lastTeam = GetHogTeamName(CurrentHedgehog)
+	end
+
+	--AddCaption("Handling respawns")
+	if gameStarted == true then
+		HandleRespawns()
+	--new method of placing starting flags
+	elseif gameTurns == 1 then
+		ShowMission(loc("CAPTURE THE FLAG"), loc("Flags, and their home base will be placed where each team ends their first turn."), "", 0, 0)
+	elseif gameTurns == 2 then
+		fPlaced[0] = true
+		ShowMission(loc("CAPTURE THE FLAG"), loc("RULES OF THE GAME [Press ESC to view]"), loc(" - Return the enemy flag to your base to score | - First team to 3 captures wins | - You may only score when your flag is in your base | - Hogs will drop the flag if killed, or drowned | - Dropped flags may be returned or recaptured | - Hogs respawn when killed"), 0, 0)
+	elseif gameTurns == 3 then
+		fPlaced[1] = true
+		StartTheGame()
+	end
+
+end
+
+function onGameTick()
+
+	-- onRessurect calls AFTER you have resurrected,
+	-- so keeping track of x,y a few milliseconds before
+	-- is useful
+	--FTTC = FTTC + 1
+	--if FTTC == 100 then
+	--	FTTC = 0
+		for i = 0,1 do
+			if fThief[i] ~= nil then
+				fThiefX[i] = GetX(fThief[i])
+				fThiefY[i] = GetY(fThief[i])
+			end
+		end
+	--end
+
+	-- things we wanna check often
+	if (CurrentHedgehog ~= nil) then
+		--AddCaption(LAND_HEIGHT - GetY(CurrentHedgehog))
+		--AddCaption(GetX(CurrentHedgehog) .. "; " .. GetY(CurrentHedgehog))
+		--CheckTeleporters()
+
+	end
+
+	if gameStarted == true then
+		HandleCircles()
+		if CurrentHedgehog ~= nil then
+			CheckFlagProximity()
+		end
+	elseif CurrentHedgehog ~= nil then -- if the game hasn't started yet, keep track of where we are gonna put the flags on turn end
+
+		if GetHogClan(CurrentHedgehog) == 0 then
+			i = 0
+		elseif GetHogClan(CurrentHedgehog) == 1 then
+			i = 1
+		end
+
+		fSpawnX[i] = GetX(CurrentHedgehog)
+		fSpawnY[i] = GetY(CurrentHedgehog)
+
+	end
+
+end
+
+function onGearResurrect(gear)
+
+	--AddCaption("A gear has been resurrected!")
+
+	-- mark the flag thief as dead if he needed a respawn
+	for i = 0,1 do
+		if gear == fThief[i] then
+			FlagThiefDead(gear)
+		end
+	end
+
+	-- should be covered by gfDivideTeams, actually
+	-- place hogs belonging to each clan either left or right side of map
+	--if GetHogClan(gear) == 0 then
+	--	FindPlace(gear, false, 0, LAND_WIDTH/2)
+	--elseif GetHogClan(gear) == 1 then
+	--	FindPlace(gear, false, LAND_WIDTH/2, LAND_WIDTH)
+	--end
+
+	AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+
+end
+
+function InABetterPlaceNow(gear)
+	for i = 0, (numhhs-1) do
+		if gear == hhs[i] then
+
+			for i = 0,1 do
+				if gear == fThief[i] then
+					FlagThiefDead(gear)
+				end
+			end
+			hhs[i] = nil
+		end
+	end
+end
+
+function onHogHide(gear)
+	 InABetterPlaceNow(gear)
+end
+
+function onHogRestore(gear)
+	match = false
+	for i = 0, (numhhs-1) do
+		if (hhs[i] == nil) and (match == false) then
+			hhs[i] = gear
+			--AddCaption(GetHogName(gear) .. " has reappeared it seems!")
+			match = true
+		end
+	end
+end
+
+
+function onGearAdd(gear)
+
+	if GetGearType(gear) == gtHedgehog then
+		hhs[numhhs] = gear
+		numhhs = numhhs + 1
+		SetEffect(gear, heResurrectable, true)
+
+	elseif GetGearType(gear) == gtPiano then
+
+		for i = 0, 1 do
+			if CurrentHedgehog == fThief[i] then
+				FlagThiefDead(gear)
+			end
+		end
+
+	end
+
+end
+
+function onGearDelete(gear)
+
+	if GetGearType(gear) == gtHedgehog then
+		InABetterPlaceNow(gear)
+	end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Highlander.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Highlander.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,233 @@
+--------------------------------
+-- HIGHLANDER / HOGS OF WAR
+-- version 0.3c
+-- by mikade
+--------------------------------
+
+-----------
+--0.1
+-----------
+
+-- concept test
+
+-----------
+--0.2
+-----------
+
+-- remove tardis till Henek fixes his tracker
+-- change wep crates to health crates
+-- reset arb turntimevalue
+-- include randomOrder
+-- Until fixed .17 methods come out, remove switches and resurrector
+-- on request, removed kamikaze and piano weapons
+-- provisional fixing of bugs that can't actually be fixed yet
+
+-----------
+--0.3
+-----------
+
+-- meh, update incorrect display
+-- may change this in the future to have switches
+-- but for now people are used to it without, so~
+
+-- mudball is now counted as a utility
+
+-----------
+--0.3b
+-----------
+
+-- cleaned up code and got rid of unneccessary vars
+-- mudball is a weapon again
+-- landgun is now a utility
+-- extra time, vampirism utility removed
+-- hammer wep removed
+-- all hogs have kamikaze
+
+-----------
+--0.3c
+-----------
+
+-- restructured some code
+-- added napalm (whoops) to list of possible weapons you can get
+-- hogs no longer recieve airstrike-related weps on border maps
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+local airWeapons = 	{amAirAttack, amMineStrike, amNapalm, amDrillStrike --[[,amPiano]]}
+
+local atkArray = 	{
+					amBazooka, amBee, amMortar, amDrill, --[[amSnowball,]]
+					amGrenade, amClusterBomb, amMolotov, amWatermelon, amHellishBomb, amGasBomb,
+					amShotgun, amDEagle, amFlamethrower, amSniperRifle, amSineGun,
+					amFirePunch, amWhip, amBaseballBat, --[[amKamikaze,]] amSeduction, --[[amHammer,]]
+					amMine, amDynamite, amCake, amBallgun, amRCPlane, amSMine,
+					amRCPlane, amSMine,
+					amBirdy
+					}
+
+local utilArray = 	{
+					amBlowTorch, amPickHammer, amGirder, amPortalGun,
+					amRope, amParachute, amTeleport, amJetpack,
+					amInvulnerable, amLaserSight, --[[amVampiric,]]
+					amLowGravity, amExtraDamage, --[[amExtraTime,]]
+					amLandGun
+					--[[,amTardis, amResurrector, amSwitch]]
+					}
+
+local wepArray = 	{}
+
+local currName
+local lastName
+local started = false
+local switchStage = 0
+
+function StartingSetUp(gear)
+
+	for i = 1, #wepArray do
+		setGearValue(gear,wepArray[i],0)
+	end
+
+	setGearValue(gear,amKamikaze,1)
+
+	i = 1 + GetRandom(#atkArray)
+	setGearValue(gear,atkArray[i],1)
+
+	i = 1 + GetRandom(#utilArray)
+	setGearValue(gear,utilArray[i],1)
+
+	SetHealth(gear, 100)
+
+end
+
+--[[function SaveWeapons(gear)
+
+	-
+	for i = 1, (#wepArray) do
+		setGearValue(gear, wepArray[i], GetAmmoCount(gear, wepArray[i]) )
+		 --AddAmmo(gear, wepArray[i], getGearValue(gear,wepArray[i]) )
+	end
+
+end]]
+
+function ConvertValues(gear)
+
+	for i = 1, #wepArray do
+		AddAmmo(gear, wepArray[i], getGearValue(gear,wepArray[i]) )
+	end
+
+
+end
+
+
+function TransferWeps(gear)
+
+	if CurrentHedgehog ~= nil then
+
+		for i = 1, #wepArray do
+			val = getGearValue(gear,wepArray[i])
+			if val ~= 0 then
+				setGearValue(CurrentHedgehog, wepArray[i], val)
+				AddAmmo(CurrentHedgehog, wepArray[i], val)
+			end
+		end
+
+	end
+
+end
+
+function onGameInit()
+	GameFlags = gfInfAttack + gfRandomOrder
+	HealthCaseProb = 100
+end
+
+function onGameStart()
+
+
+	ShowMission	(
+				loc("HIGHLANDER"),
+				loc("Not all hogs are born equal."),
+
+				"- " .. loc("Eliminate enemy hogs and take their weapons.") .. "|" ..
+				"- " .. loc("Per-Hog Ammo") .. "|" ..
+				"- " .. loc("Weapons reset.") .. "|" ..
+				"- " .. loc("Unlimited Attacks") .. "|" ..
+				"", 4, 4000
+				)
+
+	if MapHasBorder() == false then
+        for i, w in pairs(airWeapons) do
+            table.insert(atkArray, w)
+        end
+    end
+
+	for i, w in pairs(atkArray) do
+        table.insert(wepArray, w)
+	end
+
+	for i, w in pairs(utilArray) do
+        table.insert(wepArray, w)
+	end
+
+	runOnGears(StartingSetUp)
+	runOnGears(ConvertValues)
+
+
+end
+
+function onNewTurn()
+--
+end
+
+
+function onGameTick20()
+
+	if (CurrentHedgehog ~= nil) then
+
+		currName = GetHogName(CurrentHedgehog)
+
+		if (currName ~= lastName) then
+			AddCaption(loc("Switched to ") .. currName .. "!")
+			ConvertValues(CurrentHedgehog)
+		end
+
+		lastName = currName
+	end
+
+end
+
+--[[function onHogHide(gear)
+	-- waiting for Henek
+end
+
+function onHogRestore(gear)
+	-- waiting for Henek
+end]]
+
+function onGearAdd(gear)
+
+	--if GetGearType(gear) == gtSwitcher then
+	--	SaveWeapons(CurrentHedgehog)
+	--end
+
+	if (GetGearType(gear) == gtHedgehog) then
+		trackGear(gear)
+	end
+
+end
+
+function onGearDelete(gear)
+
+	if (GetGearType(gear) == gtHedgehog) then --or (GetGearType(gear) == gtResurrector) then
+		TransferWeps(gear)
+		trackDeletion(gear)
+	end
+
+end
+
+function onAmmoStoreInit()
+	SetAmmo(amSkip, 9, 0, 0, 0)
+	SetAmmo(amKamikaze, 9, 0, 0, 0)
+	--SetAmmo(amSwitch, 9, 0, 0, 0) -------1
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/No_Jumping.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/No_Jumping.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,34 @@
+--------------------------------
+-- NO JUMPING
+--------------------------------
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+
+local specialGear = nil
+
+function onGameInit()
+    Goals = loc("Jumping is disabled")
+end
+
+function onNewTurn()
+	SetInputMask(band(0xFFFFFFFF, bnot(gmLJump + gmHJump)))
+end
+
+function onGearAdd(gear)
+
+	if (GetGearType(gear) == gtJetpack) or (GetGearType(gear) == gtRope) or (GetGearType(gear) == gtParachute) then
+		specialGear = gear
+		SetInputMask(band(0xFFFFFFFF, bnot(gmHJump)))
+	end
+
+end
+
+function onGearDelete(gear)
+
+	if (GetGearType(gear) == gtJetpack) or (GetGearType(gear) == gtRope) or (GetGearType(gear) == gtParachute) then
+		specialGear = nil
+		SetInputMask(band(0xFFFFFFFF, bnot(gmLJump + gmHJump)))
+	end
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Racer.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Shoppa
+Shoppa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Racer.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,700 @@
+
+------------------------------------------
+-- RACER 0.5
+-- map-independant racing script
+-- by mikade
+-----------------------------------------
+
+-----------------------------------
+--0.1: took all the code from crazy racer and scrapped most of it
+-----------------------------------
+
+-- Removed tumbler system
+-- Removed extra adds like boosters etc
+-- Added experimental waypoint placement system
+-- More user feedback
+-- Reduced race complexity limit to 5 waypoints
+-- stop placement at complexity limit reached and end turn
+-- guys dont keep racing after dying
+-- invulnerable feasibility
+-- reverted time keeping method
+-- reduced feedback display time
+-- colour-coded addcaptions
+-- cleaned up code
+-- support for more players properly added
+-- tardis fix
+-- remove airstrikes
+
+-- i think the remainder 0 .456 sec of the tracktime isnt getting reset on newturn
+
+-- update feedback
+
+-------
+-- 0.2
+-------
+
+-- allow gameflags
+-- extend time to 90s
+-- remove other air-attack based weps
+-- turn off water rise for sd
+
+-------
+-- 0.3
+-------
+
+-- prevent WP being placed in land
+-- prevent waypoints being placed outside border
+
+-------
+-- 0.4
+-------
+
+-- update user feedback
+-- add more sounds
+
+-------
+-- 0.5
+-------
+
+-- fix ghost disappearing if hog falls in water or somehow dies
+-- lengthen ghost tracking interval to improve performance on slower machines
+-- increase waypoint limit to 8
+-- allow for persistent showmission information
+
+-----------------------------
+-- SCRIPT BEGINS
+-----------------------------
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+
+------------------
+-- Got Variables?
+------------------
+
+local fMod = 1000000 -- 1
+local roundLimit = 3
+local roundNumber = 0
+local firstClan = 10
+
+local fastX = {}
+local fastY = {}
+local fastCount = 0
+local fastIndex = 0
+local fastColour
+
+local currX = {}
+local currY = {}
+local currCount = 0
+
+--------------------------
+-- hog and team tracking variales
+--------------------------
+
+local numhhs = 0 -- store number of hedgehogs
+local hhs = {} -- store hedgehog gears
+
+local numTeams --  store the number of teams in the game
+local teamNameArr = {}	-- store the list of teams
+local teamClan = {}
+local teamSize = {}	-- store how many hogs per team
+local teamIndex = {} -- at what point in the hhs{} does each team begin
+
+local teamComment = {}
+local teamScore = {}
+
+-------
+-- racer vars
+--------
+
+local cGear = nil
+
+local bestClan = nil
+local bestTime = nil
+
+local gameBegun = false
+local gameOver = false
+local racerActive = false
+local trackTime = 0
+
+local wpCirc = {}
+local wpX = {}
+local wpY = {}
+local wpCol = {}
+local wpActive = {}
+local wpRad = 450 --75
+local wpCount = 0
+local wpLimit = 8
+
+local roundN
+local lastRound
+local RoundHasChanged
+
+-------------------
+-- general methods
+-------------------
+
+function RebuildTeamInfo()
+
+
+	-- make a list of individual team names
+	for i = 0, (TeamsCount-1) do
+		teamNameArr[i] = " " -- = i
+		teamSize[i] = 0
+		teamIndex[i] = 0
+		teamScore[i] = 100000
+	end
+	numTeams = 0
+
+	for i = 0, (numhhs-1) do
+
+		z = 0
+		unfinished = true
+		while(unfinished == true) do
+
+			newTeam = true
+			tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name
+
+			if tempHogTeamName == teamNameArr[z] then
+				newTeam = false
+				unfinished = false
+			end
+
+			z = z + 1
+
+			if z == TeamsCount then
+				unfinished = false
+				if newTeam == true then
+					teamNameArr[numTeams] = tempHogTeamName
+					numTeams = numTeams + 1
+				end
+			end
+
+		end
+
+	end
+
+	-- find out how many hogs per team, and the index of the first hog in hhs
+	for i = 0, (numTeams-1) do
+		for z = 0, (numhhs-1) do
+			if GetHogTeamName(hhs[z]) == teamNameArr[i] then
+				teamClan[i] = GetHogClan(hhs[z])
+				if teamSize[i] == 0 then
+					teamIndex[i] = z -- should give starting index
+				end
+				teamSize[i] = teamSize[i] + 1
+				--add a pointer so this hog appears at i in hhs
+			end
+		end
+
+	end
+
+end
+
+
+-----------------
+-- RACER METHODS
+-----------------
+
+function CheckWaypoints()
+
+	trackFinished = true
+
+	for i = 0, (wpCount-1) do
+
+		g1X, g1Y = GetGearPosition(CurrentHedgehog)
+		g2X, g2Y = wpX[i], wpY[i]
+
+		g1X = g1X - g2X
+		g1Y = g1Y - g2Y
+		dist = (g1X*g1X) + (g1Y*g1Y)
+
+		--if i == 0 then
+		--	AddCaption(dist .. "/" .. (wpRad*wpRad) )
+		--end
+
+		NR = (48/100*wpRad)/2
+
+		if dist < (NR*NR) then
+		--if dist < (wpRad*wpRad) then
+			--AddCaption("howdy")
+			wpActive[i] = true
+			wpCol[i] = GetClanColor(GetHogClan(CurrentHedgehog)) -- new				--GetClanColor(1)
+			SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 1, 10, 0, wpRad, 5, wpCol[i])
+
+			wpRem = 0
+			for k = 0, (wpCount-1) do
+				if wpActive[k] == false then
+					wpRem = wpRem + 1
+				end
+			end
+
+			AddCaption(loc("Way-Points Remaining") .. ": " .. wpRem,0xffba00ff,capgrpAmmoinfo)
+
+		end
+
+		if wpActive[i] == false then
+			trackFinished = false
+		end
+
+	end
+
+	return(trackFinished)
+
+end
+
+function AdjustScores()
+
+	if bestTime == nil then
+		bestTime = 100000
+		bestClan = 10
+		bestTimeComment = "N/A"
+	end
+
+	newScore = false
+
+	-- update this clan's time if the new track is better
+	for i = 0, (numTeams-1) do
+		if teamClan[i] == GetHogClan(CurrentHedgehog) then
+			if trackTime < teamScore[i] then
+				teamScore[i] = trackTime
+				newScore = true
+			else
+				newScore = false
+			end
+		end
+	end
+
+	--bestTime = 100000
+	--bestClan = 10
+
+	-- find the best time out of those so far
+	for i = 0, (numTeams-1) do
+		if teamScore[i] < bestTime then
+			bestTime = teamScore[i]
+			bestClan = teamClan[i]
+		end
+	end
+
+	if bestTime ~= 100000 then
+		bestTimeComment = (bestTime/1000) ..loc("s")
+	end
+
+	if newScore == true then
+		if trackTime == bestTime then -- best time of the race
+			ShowMission(loc("RACER"),
+			loc("TRACK COMPLETED"),
+			loc("NEW RACE RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" ..
+			loc("WINNING TIME: ") .. bestTimeComment, 0, 4000)
+			PlaySound(sndHomerun)
+		else	-- best time for the clan
+			ShowMission(loc("RACER"),
+			loc("TRACK COMPLETED"),
+			loc("NEW CLAN RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" ..
+			loc("WINNING TIME: ") .. bestTimeComment, 4, 4000)
+		end
+	else -- not any kind of new score
+		ShowMission(loc("RACER"),
+		loc("TRACK COMPLETED"),
+		loc("TIME: ") .. (trackTime/1000) ..loc("s") .. "|" ..
+		loc("WINNING TIME: ") .. bestTimeComment, -amSkip, 4000)
+		PlaySound(sndHellish)
+	end
+
+
+	--------
+	--new
+	--------
+
+	if bestTime == trackTime then
+		--AddCaption("wooooooooooooooooooooooooooooo")
+
+		fastColour = GetClanColor(GetHogClan(CurrentHedgehog))
+
+		for i = 0, (currCount-1) do
+			fastX[i] = currX[i]
+			fastY[i] = currY[i]
+		end
+
+		fastCount = currCount
+		fastIndex = 0
+
+		--currCount = 0 -- is this needed?
+
+	else
+		currCount = 0
+		fastIndex = 0
+	end
+
+
+end
+
+function onNewRound()
+
+	roundNumber = roundNumber + 1
+
+	totalComment = ""
+	for i = 0, (TeamsCount-1) do
+			if teamNameArr[i] ~= " " then				-- teamScore[teamClan[i]]
+				teamComment[i] = teamNameArr[i] .. ": " .. (teamScore[i]/1000) .. loc("s|")
+				totalComment = totalComment .. teamComment[i]
+			elseif teamNameArr[i] == " " then
+				teamComment[i] = "|"
+			end
+	end
+
+	ShowMission(	loc("RACER"),
+					loc("STATUS UPDATE"),
+					loc("Rounds Complete: ") .. roundNumber .. "/" .. roundLimit .. "|" .. " " .. "|" ..
+					loc("Best Team Times: ") .. "|" .. totalComment, 0, 4000)
+
+	-- end game if its at round limit
+	if roundNumber == roundLimit then
+		for i = 0, (numhhs-1) do
+			if GetHogClan(hhs[i]) ~= bestClan then
+				SetEffect(hhs[i], heResurrectable, false)
+				SetHealth(hhs[i],0)
+			end
+		end
+		gameOver = true
+		TurnTimeLeft = 1
+	end
+
+end
+
+function CheckForNewRound()
+
+	-------------
+	------ new
+	-------------
+
+	--[[turnN = turnN + 1
+	if gameBegun == false then
+		if turnN == 2 then
+			for i = 0, (numhhs-1) do
+				if hhs[i] ~= nil then
+					SetEffect(hhs[i], heResurrectable, false)
+					SetHealth(hhs[i],0)
+				end
+			end
+			gameOver = true
+			TurnTimeLeft = 1
+		end
+	else
+
+
+	end]]
+
+	--[[if roundBegun == true then
+
+		if RoundHasChanged == true then
+			roundN = roundN + 1
+			RoundHasChanged = false
+			onNewRound()
+		end
+
+		if lastRound ~= TotalRounds then -- new round, but not really
+
+			if RoundHasChanged == false then
+				RoundHasChanged = true
+			end
+
+		end
+
+		AddCaption("RoundN:" .. roundN .. "; " .. "TR: " .. TotalRounds)
+
+		lastRound = TotalRounds
+
+	end]]
+
+	------------
+	----- old
+	------------
+
+	if GetHogClan(CurrentHedgehog) == firstClan then
+		onNewRound()
+	end
+
+end
+
+function DisableTumbler()
+	currCount = 0
+	fastIndex = 0
+	TurnTimeLeft = 0
+	racerActive = false -- newadd
+end
+
+function HandleGhost()
+
+	-- get the current xy of the racer at this point
+	currX[currCount] = GetX(CurrentHedgehog)
+	currY[currCount] = GetY(CurrentHedgehog)
+	currCount = currCount + 1
+
+	-- draw a ping of smoke where the fastest player was at this point
+	if (fastCount ~= 0) and (fastIndex < fastCount) then
+
+		fastIndex = fastIndex + 1
+
+		tempE = AddVisualGear(fastX[fastIndex], fastY[fastIndex], vgtSmoke, 0, false)
+		g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+		SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, fastColour )
+
+		--AddCaption("fC: " .. fastIndex .. " / " .. fastCount)
+
+	else
+
+		--AddCaption("excep fC: " .. fastIndex .. " / " .. fastCount)
+
+	end
+
+
+
+end
+
+----------------------------------
+-- GAME METHODS / EVENT HANDLERS
+----------------------------------
+
+function onGameInit()
+	GameFlags = GameFlags + gfInfAttack + gfInvulnerable
+	CaseFreq = 0
+	TurnTime = 90000
+	WaterRise = 0
+end
+
+
+function onGameStart()
+
+	roundN = 0
+	lastRound = TotalRounds
+	RoundHasChanged = false -- true
+
+	RebuildTeamInfo()
+
+	ShowMission	(
+				loc("RACER"),
+				loc("a Hedgewars mini-game"),
+
+				loc("Build a track and race.") .. "|" ..
+				loc("Round Limit:") .. " " .. roundLimit .. "|" ..
+
+				"", 4, 4000
+				)
+end
+
+function PlaceWayPoint(x,y)
+
+	if (wpCount < wpLimit) then -- seems to not work with a hedgehog nil chek
+
+		wpX[wpCount] = x
+		wpY[wpCount] = y
+		wpCol[wpCount] = 0xffffffff
+		wpCirc[wpCount] = AddVisualGear(wpX[wpCount],wpY[wpCount],vgtCircle,0,true)
+																		--100
+		SetVisualGearValues(wpCirc[wpCount], wpX[wpCount], wpY[wpCount], 20, 100, 1, 10, 0, wpRad, 5, wpCol[wpCount])
+
+		wpCount = wpCount + 1
+
+		AddCaption(loc("Waypoint placed.") .. " " .. loc("Available points remaining: ") .. (wpLimit-wpCount))
+
+	end
+
+end
+
+function onNewTurn()
+
+	CheckForNewRound()
+
+	racerActive = false
+
+	trackTime = 0
+
+	currCount = 0 -- hopefully this solves problem
+	AddAmmo(CurrentHedgehog, amAirAttack, 0)
+	gTimer = 0
+
+	-- Set the waypoints to unactive on new round
+	for i = 0,(wpCount-1) do
+		wpActive[i] = false
+		wpCol[i] = 0xffffffff
+		SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 1, 10, 0, wpRad, 5, wpCol[i])
+	end
+
+	-- Handle Starting Stage of Game
+	if (gameOver == false) and (gameBegun == false) then
+		if wpCount >= 3 then
+			gameBegun = true
+			roundNumber = 0
+			firstClan = GetHogClan(CurrentHedgehog)
+			ShowMission(loc("RACER"),
+			loc("GAME BEGUN!!!"),
+			loc("Complete the track as fast as you can!"), 2, 4000)
+		else
+			ShowMission(loc("RACER"),
+			loc("NOT ENOUGH WAYPOINTS"),
+			loc("Place more waypoints using the 'Air Attack' weapon."), 2, 4000)
+			AddAmmo(CurrentHedgehog, amAirAttack, 4000)
+            ParseCommand("setweap " .. string.char(amAirAttack))
+		end
+	end
+
+	if gameOver == true then
+		gameBegun = false
+		racerActive = false -- newadd
+	end
+
+	AddAmmo(CurrentHedgehog, amTardis, 0)
+	AddAmmo(CurrentHedgehog, amDrillStrike, 0)
+	AddAmmo(CurrentHedgehog, amMineStrike, 0)
+	AddAmmo(CurrentHedgehog, amNapalm, 0)
+	AddAmmo(CurrentHedgehog, amPiano, 0)
+
+end
+
+function onGameTick20()
+
+	-- airstrike detected, convert this into a potential waypoint spot
+	if cGear ~= nil then
+		x,y = GetGearPosition(cGear)
+        if x > -9000 then
+            x,y = GetGearTarget(cGear)
+
+
+            if TestRectForObstacle(x-20, y-20, x+20, y+20, true) then
+                AddCaption(loc("Please place the way-point in the open, within the map boundaries."))
+                PlaySound(sndDenied)
+            elseif (y > WaterLine-50) then
+                AddCaption(loc("Please place the way-point further from the waterline."))
+                PlaySound(sndDenied)
+            else
+                PlaceWayPoint(x, y)
+                if wpCount == wpLimit then
+                    AddCaption(loc("Race complexity limit reached."))
+                    DisableTumbler()
+                end
+            end
+        else
+            DeleteGear(cGear)
+        end
+        SetGearPosition(cGear, -10000, 0)
+	end
+
+
+	-- start the player tumbling with a boom once their turn has actually begun
+	if racerActive == false then
+
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
+
+			-- if the gamehas started put the player in the middle of the first
+			--waypoint that was placed
+			if gameBegun == true then
+				AddCaption(loc("Good to go!"))
+				racerActive = true
+				trackTime = 0
+
+				SetGearPosition(CurrentHedgehog, wpX[0], wpY[0])
+				AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+				FollowGear(CurrentHedgehog)
+
+				HideMission()
+
+			else
+				-- still in placement mode
+			end
+
+		end
+	end
+
+
+
+	-- has the player started his tumbling spree?
+	if (CurrentHedgehog ~= nil) then
+
+		--airstrike conversion used to be here
+
+		-- if the RACE has started, show tracktimes and keep tabs on waypoints
+		if (racerActive == true) and (gameBegun == true) then
+
+			--ghost
+			if GameTime%40 == 0 then
+				HandleGhost()
+			end
+
+			trackTime = trackTime + 20
+
+			if GameTime%100 == 0 then
+                
+                if trackTime%1000 == 0 then
+                    AddCaption((trackTime/1000)..'.0',GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+                else
+                    AddCaption(trackTime/1000,GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+                end
+
+				if (CheckWaypoints() == true) then
+					AdjustScores()
+					racerActive = false
+					DisableTumbler()
+				end
+
+			end
+
+		end
+
+
+
+		-- if the player has expended his tunbling time, stop him tumbling
+		if TurnTimeLeft <= 20 then
+			DisableTumbler()
+		end
+
+	end
+
+end
+
+function onGearResurrect(gear)
+
+	AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+
+	if gear == CurrentHedgehog then
+		DisableTumbler()
+	end
+
+	-- if the player stops and "dies" or flies into water, stop him racing
+	--[[if gear == CurrentHedgehog then
+		DisableTumbler()
+		ShowMission(loc("RACER"),
+		loc("TRACK FAILED!"),
+		loc("WINNING TIME: ") .. bestTimeComment, -amSkip, 4000)
+	end]]
+
+end
+
+function onGearAdd(gear)
+
+	if GetGearType(gear) == gtHedgehog then
+		hhs[numhhs] = gear
+		numhhs = numhhs + 1
+		SetEffect(gear, heResurrectable, true)
+	end
+
+	if GetGearType(gear) == gtAirAttack then
+		cGear = gear
+	end
+
+end
+
+function onGearDelete(gear)
+
+	if GetGearType(gear) == gtAirAttack then
+		cGear = nil
+	end
+
+end
+
+--[[function onAmmoStoreInit()
+	SetAmmo(amRope, 9, 0, 0, 0)
+	SetAmmo(amJetpack, 9, 0, 0, 0)
+	SetAmmo(amSkip, 9, 0, 0, 0)
+end]]
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Random_Weapon.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+locked
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Random_Weapon.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,113 @@
+-- Random Weapons, example for gameplay scripts
+
+-- Load the library for localisation ("loc" function)
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+
+-- Load the gear tracker
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+-- List of available weapons
+local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun,
+            amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer,
+            amBaseballBat, amTeleport, amMortar, amCake, amSeduction,
+            amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane,
+            amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb,
+            amFlamethrower, amSMine, amHammer }
+
+-- List of weapons that attack from the air
+local airweapons = { amAirAttack, amMineStrike, amNapalm, amDrillStrike }
+
+-- Function that assigns the team their weapon
+function assignAmmo(hog)
+    -- Get name of the current team
+    local name = GetHogTeamName(hog)
+    -- Get whither the team has been processed
+    local processed = getTeamValue(name, "processed")
+    -- If it has not, process it
+    if processed == nil or not processed then
+        -- Get the ammo for this hog's team
+        local ammo = getTeamValue(name, "ammo")
+        -- If there is no ammo, get a random one from the list and store it
+        if ammo == nil then
+            ammo = weapons[GetRandom(table.maxn(weapons)) + 1]
+            setTeamValue(name, "ammo", ammo)
+        end
+        -- Add the ammo for the hog
+        AddAmmo(hog, ammo)
+        -- Mark as processed
+        setTeamValue(name, "processed", true)
+    end
+end
+
+-- Mark team as not processed
+function reset(hog)
+    setTeamValue(GetHogTeamName(hog), "processed", false)
+end
+
+function onGameInit()
+    -- Limit flags that can be set, but allow game schemes to be used
+    GameFlags = band(bor(GameFlags, gfResetWeps), bnot(gfInfAttack))
+    -- Set a custom game goal that will show together with the scheme ones
+    Goals = loc("Each turn you get one random weapon")
+end
+
+function onGameStart()
+    -- Initialize the tracking of hogs and teams
+    trackTeams()
+    -- Add air weapons to the game if the border is not active
+    if MapHasBorder() == false then
+        for i, w in pairs(airweapons) do
+            table.insert(weapons, w)
+        end
+    end
+end
+
+function onAmmoStoreInit()
+    -- Allow skip at all times
+    SetAmmo(amSkip, 9, 0, 0, 0)
+
+    -- Let utilities be available through crates
+    SetAmmo(amParachute, 0, 1, 0, 1)
+    SetAmmo(amGirder, 0, 1, 0, 2)
+    SetAmmo(amSwitch, 0, 1, 0, 1)
+    SetAmmo(amLowGravity, 0, 1, 0, 1)
+    SetAmmo(amExtraDamage, 0, 1, 0, 1)
+    SetAmmo(amInvulnerable, 0, 1, 0, 1)
+    SetAmmo(amExtraTime, 0, 1, 0, 1)
+    SetAmmo(amLaserSight, 0, 1, 0, 1)
+    SetAmmo(amVampiric, 0, 1, 0, 1)
+    SetAmmo(amJetpack, 0, 1, 0, 1)
+    SetAmmo(amPortalGun, 0, 1, 0, 1)
+    SetAmmo(amResurrector, 0, 1, 0, 1)
+
+    -- Allow weapons to be used
+    for i, w in pairs(weapons) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+
+    -- Allow air weapons to be used
+    for i, w in pairs(airweapons) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+end
+
+function onNewTurn()
+    -- Give every team their weapons, so one can plan during anothers turn
+    runOnGears(assignAmmo)
+    -- Mark all teams as not processed
+    runOnGears(reset)
+    -- Set the current teams weapons to nil so they will get new after the turn has ended
+    setTeamValue(GetHogTeamName(CurrentHedgehog), "ammo", nil)
+end
+
+function onGearAdd(gear)
+    -- Catch hedgehogs for the tracker
+    if GetGearType(gear) == gtHedgehog then
+        trackGear(gear)
+    end
+end
+
+function onGearDelete(gear)
+    -- Remove hogs that are gone
+    trackDeletion(gear)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Space_Invasion.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Space_Invasion.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2435 @@
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+---------------------------------------------------
+---------------------------------------------------
+---------------------------------------------------
+--- Space Invasion Code Follows (1.1)
+---------------------------------------------------
+---------------------------------------------------
+-- VERSION HISTORY
+----------------
+-- version 0.1
+----------------
+-- conversion of tumbler into space invasion
+-- a million and one changes
+-- bells and whistles
+
+----------------
+-- version 0.2
+----------------
+-- code slowly getting cleaner, it still looks like a spaghetti monster tho
+-- lots of console tracking :/
+-- all visual gears are now compulsary (will probably revert this)
+-- implemented fMod to try combat desyncs and bring this in line with dev
+
+----------------
+-- version 0.3
+----------------
+-- values of scoring changed to 3:10, and now based on vCircScore
+-- time gained from killing a red circ increased from 3 to 4
+-- circles now spawn at a distance of at least 800 or until sanity limit
+-- roundsLimit now based off MinesTime (kinda, its an experiment)
+
+-----------------
+--0.4
+-----------------
+-- commented out a lot of WriteLnToConsoles (dont need them at this point)
+-- added some different WriteLnToConsoles
+-- changed some of the collision detect for explosives in checkvarious()
+
+-----------------
+--0.5
+-----------------
+-- added implementation for a projectile shield
+-- added a "bonus" orange invader that partially recharges player shield
+-- added a tough "blueboss" blue invader
+-- expanded user feedback
+-- circles now have health and are capable of being merely "damaged"
+-- redid a lot of the collision code and added CircleDamaged
+-- added more sounds to events
+-- added more visual gears
+
+-----------------
+--0.6
+-----------------
+-- removed a few WriteLns
+-- added randomized grunts on circ damage
+-- added (mostly) graceful fading out of circles :D:
+-- changed odds for circles
+-- changed user feedback
+-- fixed the location of the explosion where player bashes into circ
+
+-----------------
+--0.7
+-----------------
+-- added PlaySound(sndSuddenDeath) when ammo gets depleted
+-- added an extra "Ammo Depleted" note if user presses fire while empty
+-- specified how much shield power is gained on shield powerup collection
+-- changed odds for circles AGAIN, ammo is now sliiightly more common
+-- switched most of the explosions/smoke effects back to non-critical vgears (with a few exceptions)
+-- tumbletime is now based off turntime and is variable
+-- delete explosives in DeleteFarFlungBarrel rather than explode them on map boundaries to save on performance
+-- utilized the improved AddCaption to tint / prevent overrides
+-- temporarily disabled bugged sort that displays teams according to their score
+-- reluctantly changed the colour of the bonus circ to purple
+-- standarized point notation
+-- added some missing locs
+-- commented out remaining WriteLnToConsoles for the meanwhile with the prefix "nw"
+
+-- ACHIEIVEMENTS added
+-- (during one turn) aka repeatable
+-- Ammo Manic (Destroy 3 green circles for + 5 points)
+-- Drone Hunter (Destroy 5 red circles for + 10 points)
+-- Shield Seeker (Destroy 3 purple circles for +10 points)
+-- Boss Slayer (Destroy 2 blue circles for +25 points)
+
+-- Shield Master (disolve 5 shells for +10 points)
+-- Shield Miser (don't use your shield at all (3.5*roundkills)+2 points)
+
+-- Depleted Kamikaze! (kamikaze into a blue/red circ when you are out of ammo) 5pts
+-- Timed Kamikaze! (kamikaze into a blue/red circ when you only have 5s left) 10pts
+-- Kamikaze Expert (combination of the above two) 15pts
+
+-- Multi-shot (destroy more than 1 invader with a single bullet) 15pts
+-- X-Hit Combo (destroy another invader in less than 3 seconds) chainLength*2 points
+
+-- Accuracy Bonus (80% accuracy at the end of your turn with more than 5 shots fired) 15pts
+
+--(during the length of the game) aka non-repeatable
+-- 10/25/50 kills (+25/+50/+100 points)
+
+-----------------
+--0.8
+-----------------
+-- added a HUD for turntimeleft, ammo, shield
+-- shieldhealth hits 0 properly
+
+------------------------
+-- version 0.8.1
+------------------------
+
+-- stop hiding non-existant 4th Tag
+-- redraw HUD on screen resolution change
+
+------------------------
+-- version 0.9
+------------------------
+-- time for more 'EXPERIMENTS' mwahahahahahaha D:
+-- (hopefully) balanced Shield Miser
+-- bosses are no longer a redunkulous 50 points, but toned down to 30
+-- experimental radar (it's INTERACTIVE and math-heavy :D) (visual gears are safe... right? D:)
+-- bugfix and balance for multishot
+
+------------------------
+-- version 1.0
+------------------------
+-- if only version numbers actually worked like this, wouldn't that be awful :D
+-- added surfer achievement
+-- increased value of shield miser by 1 point per kill (OP?)
+
+------------------------
+-- version 1.1
+------------------------
+-- fixed radar so that blips dont go past circs when you get very close
+-- added a missing loc for shield depletion
+-- increased delay to 1000 to try stop noobies missing their turn
+-- added sniper achievement for hits from over a 1000000 away
+-- added achievement for 3 "sniper" shots in a round
+-- added achievement for 3 "point blank" shots in a round
+-- added "fierce Competition" achievement for shooting an enemy hog (once per round)
+-- some support for more weapons later
+
+--------------------------
+--notes for later
+--------------------------
+-- maybe add a check for a tie, IMPOSSIBRU THERE ARE NO TIES
+-- more achievements? (3 kamikazes in a row, supreme shield expert/miser etc?)
+
+-- if more weps are added, replace primshotsfired all over the place
+
+-- look for derp and let invaders shoot again
+
+-- more weps? flamer/machineballgun,
+-- some kind of bomb that just drops straight down
+-- "fire and forget" missile
+-- shockwave
+
+-- some kind of ability-meter that lets you do something awesome when you are
+-- doing really well in a given round.
+-- probably new kind of shield that pops any invaders who come near
+
+-- fix game never ending bug
+-- fix radar
+-- new invader: golden snitch, doesn't show up on your radar
+
+-- maybe replace (48/100*vCircRadius[i])/2 with something better
+
+
+--[[CAPTION CATEGORIES
+-----------------
+capgrpGameState
+-----------------
+AddCaption(LOC_NOT("Sniper!") .. " +10 " .. LOC_NOT("points") .. "!",0xffba00ff,capgrpAmmostate)
+--they call me bullsye
+--point blank combo
+--fierce Competition
+-----------------
+capgrpAmmostate
+-----------------
+AddCaption( chainLength .. LOC_NOT("-chain! +") .. chainLength*2 .. LOC_NOT(" points!"),0xffba00ff,capgrpAmmostate)
+AddCaption(LOC_NOT("Multi-shot! +15 points!"),0xffba00ff,capgrpAmmostate)
+
+-----------------
+capgrpAmmoinfo
+-----------------
+AddCaption(LOC_NOT("Shield Miser! +20 points!"),0xffba00ff,capgrpAmmoinfo)
+AddCaption(LOC_NOT("Shield Master! +10 points!"),0xffba00ff,capgrpAmmoinfo)
+
+-----------------
+capgrpVolume
+-----------------
+AddCaption(LOC_NOT("Boom! +25 points!"),0xffba00ff,capgrpVolume)
+AddCaption(LOC_NOT("BOOM! +50 points!"),0xffba00ff,capgrpVolume)
+AddCaption(LOC_NOT("BOOM! BOOM! BOOM! +100 points!"),0xffba00ff,capgrpVolume)
+AddCaption(LOC_NOT("Accuracy Bonus! +15 points!"),0xffba00ff,capgrpVolume)
+AddCaption(LOC_NOT("Surfer! +15 points!"),0xffba00ff,capgrpVolume)
+
+-----------------
+capgrpMessage
+-----------------
+AddCaption(LOC_NOT("Ammo Depleted!"),0xff0000ff,capgrpMessage)
+AddCaption(LOC_NOT("Ammo: ") .. primShotsLeft)
+AddCaption(LOC_NOT("Shield Depleted"),0xff0000ff,capgrpMessage)
+AddCaption( LOC_NOT("Shield ON:") .. " " .. shieldHealth - 80 .. " " .. LOC_NOT("Power Remaining") )
+AddCaption(LOC_NOT("Shield OFF:") .. " " .. shieldHealth - 80 .. " " .. LOC_NOT("Power Remaining") )
+
+AddCaption(LOC_NOT("Time Extended!") .. "+" .. 4 .. LOC_NOT("s"), 0xff0000ff,capgrpMessage )
+AddCaption("+" .. 3 .. " " .. LOC_NOT("Ammo"), 0x00ff00ff,capgrpMessage)
+AddCaption(LOC_NOT("Shield boosted! +30 power"), 0xff00ffff,capgrpMessage)
+AddCaption(LOC_NOT("Shield is fully recharged!"), 0xffae00ff,capgrpMessage)
+AddCaption(LOC_NOT("Boss defeated! +50 points!"), 0x0050ffff,capgrpMessage)
+
+AddCaption(LOC_NOT("GOTCHA!"))
+AddCaption(LOC_NOT("Kamikaze Expert! +15 points!"),0xffba00ff,capgrpMessage)
+AddCaption(LOC_NOT("Depleted Kamikaze! +5 points!"),0xffba00ff,capgrpMessage)
+AddCaption(LOC_NOT("Timed Kamikaze! +10 points!"),0xffba00ff,capgrpMessage)
+
+-----------------
+capgrpMessage2
+-----------------
+AddCaption(LOC_NOT("Drone Hunter! +10 points!"),0xffba00ff,capgrpMessage2)
+AddCaption(LOC_NOT("Ammo Maniac! +5 points!"),0xffba00ff,capgrpMessage2)
+AddCaption(LOC_NOT("Shield Seeker! +10 points!"),0xffba00ff,capgrpMessage2)
+AddCaption(LOC_NOT("Boss Slayer! +25 points!"),0xffba00ff,capgrpMessage2)
+]]
+
+----------------------------------
+-- so I herd u liek wariables
+----------------------------------
+
+--local fMod = 1	-- for use in .15 single player only, otherwise desync
+local fMod = 1000000 -- use this for dev and .16+ games
+
+-- some console stuff
+local shellID = 0
+local explosivesID = 0
+
+-- gaudyRacer
+local boosterOn = false
+local roundLimit = 3	-- no longer set here (see version history)
+local roundNumber = 0
+local firstClan = 10
+local gameOver = false
+local gameBegun = false
+
+local bestClan = 10
+local bestScore = 0
+local sdScore = {}
+local sdName = {}
+local sdKills = {}
+
+local roundN = 0
+local lastRound
+local RoundHasChanged = true
+
+--------------------------
+-- hog and team tracking variales
+--------------------------
+
+local numhhs = 0
+local hhs = {}
+
+local numTeams
+local teamNameArr = {}
+local teamClan = {}
+local teamSize = {}
+local teamIndex = {}
+
+local teamComment = {}
+local teamScore = {}
+local teamCircsKilled = {}
+local teamSurfer = {}
+
+-- stats variables
+--local teamRed = {}
+--local teamBlue = {}
+--local teamOrange = {}
+--local teamGreen = {}
+local roundKills = 0
+local RK = 0
+local GK = 0
+local BK = 0
+local OK = 0
+local SK = 0
+local shieldMiser = true
+local fierceComp = false
+local chainCounter = 0
+local chainLength = 0
+local shotsFired = 0
+local shotsHit = 0
+local SurfTime = 0
+local sniperHits = 0
+local pointBlankHits = 0
+---------------------
+-- tumbler goods
+---------------------
+
+local leftOn = false
+local rightOn = false
+local upOn = false
+local downOn = false
+
+----------------
+-- TUMBLER
+local wep = {}
+local wepAmmo = {}
+local wepCol = {}
+local wepIndex = 0
+local wepCount = 0
+local fireTimer = 0
+----------------
+
+
+
+local primShotsMax = 5
+local primShotsLeft = 0
+
+local TimeLeft = 0
+local stopMovement = false
+local tumbleStarted = false
+
+local beam = false
+local pShield
+local shieldHealth
+
+local shockwave
+local shockwaveHealth = 0
+local shockwaveRad = 300
+
+local vTag = {}
+
+-----------------------------------------------
+-- CIRCLY GOODIES
+-----------------------------------------------
+
+local CirclesAreGo = false
+local playerIsFine = true
+local targetHit = false
+
+local FadeAlpha = 0 -- used to fade the circles out gracefully when player dies
+local pTimer = 0 -- tracking projectiles following player
+
+--local m2Count = 0		-- handle speed of circs
+
+local vCirc = {}
+local vCCount = 0
+
+local rCirc = {}
+local rCircX = {}
+local rCircY = {}
+local rAlpha = 255
+local radShotsLeft = 0
+
+local vCircActive = {}
+local vCircHealth = {}
+local vType = {}
+local vCounter = {}		-- how often this circ gets to "fire" etc
+local vCounterLim = {} -- when vCounter == vCounterLim circle performs its special
+local vCircScore = {} -- how many points killing this invader gives
+
+local vCircRadMax = {}
+local vCircRadMin = {}
+local vCircRadDir = {}
+local vCircRadCounter = {}
+
+local vCircDX = {}
+local vCircDY = {}
+
+local vCircX = {}
+local vCircY = {}
+local vCircMinA = {}
+local vCircMaxA = {}
+local vCircType = {}
+local vCircPulse = {}
+local vCircFuckAll = {}
+local vCircRadius = {}
+local vCircWidth = {}
+local vCircCol = {}
+
+-------------------------------------------
+-- some lazy copypasta/modified methods
+-------------------------------------------
+
+
+
+function HideTags()
+
+	for i = 0, 2 do
+		SetVisualGearValues(vTag[i],0,0,0,0,0,1,0, 0, 240000, 0xffffff00)
+	end
+
+end
+
+function DrawTag(i)
+
+	zoomL = 1.3
+
+	xOffset = 40
+
+	if i == 0 then
+		yOffset = 40
+		tCol = 0xffba00ff
+		tValue = TimeLeft
+	elseif i == 1 then
+		zoomL = 1.1
+		yOffset = 70
+		tCol = 0x00ff00ff
+		tValue = wepAmmo[wepIndex] --primShotsLeft
+	elseif i == 2 then
+		zoomL = 1.1
+		xOffset = 40 + 35
+		yOffset = 70
+		tCol = 0xa800ffff
+		tValue = shieldHealth - 80
+	end
+
+	DeleteVisualGear(vTag[i])
+	vTag[i] = AddVisualGear(0, 0, vgtHealthTag, 0, false)
+	g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(vTag[i])
+	SetVisualGearValues	(
+				vTag[i], 		--id
+				-(ScreenWidth/2) + xOffset,	--xoffset
+				ScreenHeight - yOffset, --yoffset
+				0, 			--dx
+				0, 			--dy
+				zoomL, 			--zoom
+				1, 			--~= 0 means align to screen
+				g7, 			--frameticks
+				tValue, 		--value
+				240000, 		--timer
+				tCol		--GetClanColor( GetHogClan(CurrentHedgehog) )
+				)
+
+end
+
+function RebuildTeamInfo()
+
+	-- make a list of individual team names
+	for i = 0, (TeamsCount-1) do
+		teamNameArr[i] = " " -- = i
+		teamSize[i] = 0
+		teamIndex[i] = 0
+		teamScore[i] = 0
+		teamCircsKilled[i] = 0
+		teamSurfer[i] = false
+	end
+	numTeams = 0
+
+	for i = 0, (numhhs-1) do
+
+		z = 0
+		unfinished = true
+		while(unfinished == true) do
+
+			newTeam = true
+			tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name
+
+			if tempHogTeamName == teamNameArr[z] then
+				newTeam = false
+				unfinished = false
+			end
+
+			z = z + 1
+
+			if z == (TeamsCount-1) then
+				unfinished = false
+				if newTeam == true then
+					teamNameArr[numTeams] = tempHogTeamName
+					numTeams = numTeams + 1
+				end
+			end
+
+		end
+
+	end
+
+	-- find out how many hogs per team, and the index of the first hog in hhs
+	for i = 0, (TeamsCount-1) do
+
+		for z = 0, (numhhs-1) do
+			if GetHogTeamName(hhs[z]) == teamNameArr[i] then
+				teamClan[i] = GetHogClan(hhs[z])
+				if teamSize[i] == 0 then
+					teamIndex[i] = z -- should give starting index
+				end
+				teamSize[i] = teamSize[i] + 1
+				--add a pointer so this hog appears at i in hhs
+			end
+		end
+
+	end
+
+end
+
+-- control
+function AwardPoints(p)
+
+	for i = 0,(TeamsCount-1) do
+		if teamClan[i] == GetHogClan(CurrentHedgehog) then
+			teamScore[i] = teamScore[i] + p
+		end
+	end
+
+end
+
+function AwardKills(t)
+
+	roundKills = roundKills + 1
+
+	for i = 0,(TeamsCount-1) do
+		if teamClan[i] == GetHogClan(CurrentHedgehog) then
+			teamCircsKilled[i] = teamCircsKilled[i] + 1
+
+			if teamCircsKilled[i] == 10 then
+				AddCaption(loc("Boom!") .. " +25 " .. loc("points").."!",0xffba00ff,capgrpVolume)
+				AwardPoints(25)
+			elseif teamCircsKilled[i] == 25 then
+				AddCaption(loc("BOOM!") .. " +50 " .. loc("points") .. "!",0xffba00ff,capgrpVolume)
+				AwardPoints(50)
+			elseif teamCircsKilled[i] == 50 then
+				AddCaption(loc("BOOM!") .. loc("BOOM!") .. loc("BOOM!") .. " +100 " .. loc("points") .. "!",0xffba00ff,capgrpVolume)
+				AwardPoints(100)
+			end
+
+			--[[
+			if t == "R" then
+				redCircsKilled[i] = redCircsKilled[i] + 1
+			end
+			--etc
+			--etc
+			]]
+		end
+	end
+
+end
+
+-----------------
+
+function bubbleSort(table)
+
+	for i = 1, #table do
+        for j = 2, #table do
+            if table[j] < table[j-1] then
+
+				temp = table[j-1]
+				t2 = sdName[j-1]
+				t3 = sdKills[j-1]
+
+				table[j-1] = table[j]
+                sdName[j-1] = sdName[j]
+				sdKills[j-1] = sdKills[j]
+
+				table[j] = temp
+				sdName[j] = t2
+				sdKills[j] = t3
+
+            end
+        end
+    end
+
+    return
+
+end
+
+-----------------
+
+function CommentOnScore()
+
+	for i = 0,(TeamsCount-1) do
+		sdScore[i] = teamScore[i]
+		sdKills[i] = teamCircsKilled[i]
+		sdName[i] = teamNameArr[i]
+	end
+
+	--bubbleSort(sdScore)
+
+	for i = 0,(TeamsCount-1) do
+		if sdName[i] ~= " " then
+			teamComment[i] = sdName[i] .. " |" ..
+			loc("SCORE") .. ": " .. sdScore[i] .. " " .. loc("points") .. "|" ..
+			loc("KILLS") .. ": " .. sdKills[i] .. " " .. loc("invaders destroyed") .. "|" ..
+			" " .. "|"
+		elseif sdName[i] == " " then
+			teamComment[i] = "|"
+		end
+	end
+
+	entireC = ""
+	for i = (TeamsCount-1),0,-1 do
+		entireC = entireC .. teamComment[i]
+	end
+
+	ShowMission("SPACE INVASION", loc("STATUS UPDATE"), loc("Rounds Complete") .. ": " .. roundNumber .. "/" .. roundLimit .. "| " .. "|" .. loc("Team Scores") .. ": |" ..entireC, 4, 1)
+
+end
+
+function onNewRound()
+	roundNumber = roundNumber + 1
+
+	CommentOnScore()
+
+	-- end game if its at round limit
+	if roundNumber == roundLimit then
+
+		for i = 0, (TeamsCount-1) do
+			if teamScore[i] > bestScore then
+				bestScore = teamScore[i]
+				bestClan = teamClan[i]
+			end
+		end
+
+		for i = 0, (numhhs-1) do
+			if GetHogClan(hhs[i]) ~= bestClan then
+				SetEffect(hhs[i], heResurrectable, false)
+				SetHealth(hhs[i],0)
+			end
+		end
+		gameOver = true
+		TurnTimeLeft = 0	--1
+		TimeLeft = 0
+	end
+end
+
+-- gaudy racer
+function CheckForNewRound()
+
+	----------
+	-- new
+	----------
+
+	--[[if gameBegun == true then
+
+		if RoundHasChanged == true then
+			roundN = roundN + 1
+			RoundHasChanged = false
+			onNewRound()
+		end
+
+		if lastRound ~= TotalRounds then -- new round, but not really
+
+			if RoundHasChanged == false then
+				RoundHasChanged = true
+			end
+
+		end
+
+		--AddCaption("RoundN:" .. roundN .. "; " .. "TR: " .. TotalRounds)
+		lastRound = TotalRounds
+
+	end]]
+
+	----------
+	-- old
+	----------
+	if GetHogClan(CurrentHedgehog) == firstClan then
+		onNewRound()
+	end
+
+end
+
+
+----------------------------------------
+-- some tumbler/space invaders methods
+----------------------------------------
+
+function isATrackedGear(gear)
+	if 	(GetGearType(gear) == gtExplosives) or
+		(GetGearType(gear) == gtShell) or
+		(GetGearType(gear) == gtFlame) or-- new -- gtBall
+		(GetGearType(gear) == gtBall)
+	then
+		return(true)
+	else
+		return(false)
+	end
+end
+
+function setNewGearValues(gear)
+
+	if GetGearType(gear) == gtShell then
+		lfs = 50	-- roughly 5 seconds
+		shellID = shellID + 1
+		setGearValue(gear,"ID",shellID)
+		--nw WriteLnToConsole("Just assigned ID " .. getGearValue(gear,"ID") .. " to this shell")
+	elseif GetGearType(gear) == gtBall then
+		lfs = 5 --70	-- 7s
+	elseif GetGearType(gear) == gtExplosives then
+		lfs = 15	-- 1.5s
+		explosivesID = explosivesID + 1
+		setGearValue(gear,"ID",explosivesID)
+		setGearValue(gear,"XP", GetX(gear))
+		setGearValue(gear,"YP", GetY(gear))
+		--nw WriteLnToConsole("Just assigned ID " .. getGearValue(gear,"ID") .. " to this explosives")
+	elseif GetGearType(gear) == gtFlame then
+		lfs = 5	-- 0.5s
+	else
+		lfs = 100
+	end
+
+	setGearValue(gear,"lifespan",lfs)
+	--WriteLnToConsole("I also set its lifespan to " .. lfs)
+
+
+end
+
+function HandleLifeSpan(gear)
+
+	decreaseGearValue(gear,"lifespan")
+
+	--WriteLnToConsole("Just decreased the lifespan of a gear to " .. getGearValue(gear,"lifespan"))
+	--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+
+
+	if getGearValue(gear,"lifespan") == 0 then
+
+		if GetGearType(gear) == gtShell then
+			AddVisualGear(GetX(gear), GetY(gear), vgtExplosion, 0, false)
+			WriteLnToConsole("about to delete a shell due to lifespan == 0")
+		--elseif GetGearType(gear) == gtBall then
+		--	AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, true)
+		elseif GetGearType(gear) == gtExplosives then
+			AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+			--nw WriteLnToConsole("about to delete a explosive due to lifespan == 0")
+		elseif GetGearType(gear) == gtFlame then
+			AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, false)
+			--WriteLnToConsole("about to delete flame due to lifespan == 0")
+		end
+
+		DeleteGear(gear)
+
+	end
+
+end
+
+-- this prevents ugly barrel clipping sounds when a barrel flies off map limits
+function DeleteFarFlungBarrel(gear)
+
+	if GetGearType(gear) == gtExplosives then
+		if 	(GetX(gear) < -1900) or
+			(GetX(gear) > 6200) or
+			(GetY(gear) < -3400)
+		then
+			AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+			DeleteGear(gear)
+			--SetHealth(gear, 0)
+			--WriteLnToConsole("I'm setting barrel ID " .. getGearValue(gear,"ID") .. " to 0 health because it's been flung too close to the map edges. at Game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+		end
+
+	end
+
+end
+
+-----------------------
+--EVENT HANDLERS
+-- action keys
+-----------------------
+
+function HandleFlameThrower()
+
+	--
+	--flamer
+
+	fireTimer = fireTimer + 1
+	if fireTimer == 6 then	-- 6
+		fireTimer = 0
+
+		if (wep[wepIndex] == loc("Flamer") ) and (preciseOn == true) and (wepAmmo[wepIndex] > 0) and (stopMovement == false) and (tumbleStarted == true) then
+
+			wepAmmo[wepIndex] = wepAmmo[wepIndex] - 1
+			AddCaption(
+			loc("Flamer") .. ": " ..
+			(wepAmmo[wepIndex]/800*100) - (wepAmmo[wepIndex]/800*100)%2 .. "%",
+			wepCol[2],
+			capgrpMessage2
+			)
+			DrawTag(3)
+
+			dx, dy = GetGearVelocity(CurrentHedgehog)					--gtFlame -- gtSnowball -- gtAirBomb
+			shell = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtFlame, 0, 0, 0, 0)
+
+			xdev = 1 + GetRandom(35)	--25
+			xdev = xdev / 100
+
+			r = GetRandom(2)
+			if r == 1 then
+				xdev = xdev*-1
+			end
+
+			ydev = 1 + GetRandom(35)	--25
+			ydev = ydev / 100
+
+			r = GetRandom(2)
+			if r == 1 then
+				ydev = ydev*-1
+			end
+
+								--4.5	or 2.5 nonflames				--4.5
+			SetGearVelocity(shell, (dx*4.5)+(xdev*fMod), (dy*4.5)+(ydev*fMod))	--10
+
+		end
+
+	end
+
+
+end
+
+function ChangeWeapon()
+
+	wepIndex = wepIndex + 1
+	if wepIndex == wepCount then
+		wepIndex = 0
+	end
+
+	AddCaption(wep[wepIndex] .. " " .. loc("selected!"), wepCol[wepIndex],capgrpAmmoinfo )
+	AddCaption(wepAmmo[wepIndex] .. " " .. loc("shots remaining."), wepCol[wepIndex],capgrpMessage2)
+
+end
+
+--function onTimer()
+
+	-- experimental wep
+	--[[SetVisualGearValues(shockwave, GetX(CurrentHedgehog), GetY(CurrentHedgehog), 40, 255, 1, 10, 0, 300, 1, 0xff33ffff)
+	AddCaption("boom")
+	PlaySound(sndWarp)
+	shockwaveHealth = 100
+	shockwaveRad = 100]]
+
+
+	--change wep
+	--ChangeWeapon()
+
+	-- booster
+	--[[if boosterOn == false then
+		boosterOn = true
+	else
+		boosterOn = false
+	end]]
+
+--end
+
+-- o rite dis wan iz liek synched n stuff hope full lee
+-- old method
+--[[function onPrecise()
+
+
+	-- Fire Barrel
+	if (primShotsLeft > 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then
+
+		shotsFired = shotsFired +1
+
+		morte = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtExplosives, 0, 0, 0, 1)
+
+		primShotsLeft = primShotsLeft - 1
+
+		if primShotsLeft == 0 then
+			PlaySound(sndSuddenDeath)
+			AddCaption(loc("Ammo Depleted!"),0xff0000ff,capgrpMessage)
+		else
+			AddCaption(loc("Ammo") .. ": " .. primShotsLeft)
+		end
+		DrawTag(1)
+
+		CopyPV(CurrentHedgehog, morte) -- new addition
+		x,y = GetGearVelocity(morte)
+
+		x = x*2
+		y = y*2
+		SetGearVelocity(morte, x, y)
+
+
+	elseif (primShotsLeft == 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then
+		AddCaption(loc("Ammo Depleted!"),0xff0000ff,capgrpMessage)
+	end
+
+
+end]]
+
+-- derp tumbler
+function onPrecise()
+
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) and (wepAmmo[wepIndex] > 0) then
+
+		wepAmmo[wepIndex] = wepAmmo[wepIndex] - 1
+		--AddCaption(wepAmmo[wepIndex] .. " " .. loc("shots remaining."), wepCol[wepIndex],capgrpMessage2)
+
+		if wep[wepIndex] == loc("Barrel Launcher") then
+			shotsFired = shotsFired +1
+
+			morte = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtExplosives, 0, 0, 0, 1)
+			CopyPV(CurrentHedgehog, morte) -- new addition
+			x,y = GetGearVelocity(morte)
+			x = x*2
+			y = y*2
+			SetGearVelocity(morte, x, y)
+
+			if wepAmmo[wepIndex] == 0 then
+			PlaySound(sndSuddenDeath)
+			AddCaption(loc("Ammo Depleted!"),0xff0000ff,capgrpMessage)
+			else
+				--AddCaption(loc("Ammo") .. ": " .. wepAmmo[wepIndex])
+			end
+			DrawTag(1)
+
+		elseif wep[wepIndex] == loc("Mine Deployer") then
+			morte = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtAirBomb, 0, 0, 0, 0)
+			SetTimer(morte, 1000)
+			DrawTag(1)
+		end
+
+	elseif (wepAmmo[wepIndex] == 0) and (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then
+		AddCaption(loc("Ammo Depleted!"),0xff0000ff,capgrpMessage)
+	end
+
+	preciseOn = true
+
+end
+
+function onPreciseUp()
+	preciseOn = false
+end
+
+function onLJump()
+
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then
+		shieldMiser = false
+		if shieldHealth == 80 then
+			AddCaption(loc("Shield Depleted"),0xff0000ff,capgrpMessage)
+			PlaySound(sndMineTick)
+			PlaySound(sndSwitchHog)
+		elseif (beam == false) and (shieldHealth > 80) then
+			beam = true
+			SetVisualGearValues(pShield, GetX(CurrentHedgehog), GetY(CurrentHedgehog), 40, 255, 1, 10, 0, 300, 1, 0xa800ffff)
+			AddCaption( loc("Shield ON:") .. " " .. shieldHealth - 80 .. " " .. loc("Power Remaining") )
+			PlaySound(sndWarp)
+		else
+			beam = false
+			SetVisualGearValues(pShield, GetX(CurrentHedgehog), GetY(CurrentHedgehog), 0, 0, 1, 10, 0, 0, 0, 0xa800ffff)
+			AddCaption(loc("Shield OFF:") .. " " .. shieldHealth - 80 .. " " .. loc("Power Remaining") )
+		end
+	end
+end
+
+function onHJump()
+
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) and
+	(rAlpha == 255) and (radShotsLeft > 0) then
+		rPingTimer = 0
+		rAlpha = 0
+		radShotsLeft = radShotsLeft -1
+		AddCaption(loc("Pings left:") .. " " .. radShotsLeft,GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage)
+	end
+
+end
+
+-----------------
+-- movement keys
+-----------------
+
+function onLeft()
+	leftOn = true
+end
+
+function onRight()
+	rightOn = true
+end
+
+function onUp()
+	upOn = true
+end
+
+function onDown()
+	downOn = true
+end
+
+function onDownUp()
+	downOn = false
+end
+
+function onUpUp()
+	upOn = false
+end
+
+function onLeftUp()
+	leftOn = false
+end
+
+function onRightUp()
+	rightOn = false
+end
+
+--------------------------
+-- other event handlers
+--------------------------
+
+function onGameInit()
+	GameFlags = 0 + gfRandomOrder
+	Theme = "EarthRise"
+	CaseFreq = 0
+	HealthCaseProb = 0
+	MinesNum = 0
+	Explosives = 0
+	Delay = 1000
+
+	for i = 0, 3 do
+		vTag[0] = AddVisualGear(0, 0, vgtHealthTag, 0, false)
+	end
+
+	HideTags()
+
+	wep[0] = loc("Barrel Launcher")
+	wep[1] = loc("Mine Deployer")
+	wep[2] = loc("Flamer")
+
+	wepCol[0] = 0x78818eff
+	wepCol[1] = 0xa12a77ff
+	wepCol[2] = 0xf49318ff
+
+	wepCount = 3
+
+end
+
+function onGameStart()
+
+	if (MinesTime == -1000) or (MinesTime == 0) then
+		roundLimit = 3
+	else
+		roundLimit = (MinesTime / 1000)
+	end
+
+	ShowMission	(
+				"SPACE INVASION",
+				loc("a Hedgewars mini-game"),
+
+				loc("Destroy invaders to score points.") .. "|" ..
+				" " .. "|" ..
+
+				loc("Round Limit") .. ": " .. roundLimit .. "|" ..
+				loc("Turn Time") .. ": " .. (TurnTime/1000) .. loc("sec") .. "|" ..
+				" " .. "|" ..
+
+				loc("Movement: [Up], [Down], [Left], [Right]") .. "|" ..
+				loc("Fire") .. ": " .. loc("[Left Shift]") .. "|" ..
+				loc("Toggle Shield") .. ": " .. loc("[Enter]") .. "|" ..
+				loc("Radar Ping") .. ": " .. loc("[Backspace]") .. "|" ..
+
+				--" " .. "|" ..
+				--LOC_NOT("Invaders List: ") .. "|" ..
+				--LOC_NOT("Blue Jabberwock: (50 points)") .. "|" ..
+				--LOC_NOT("Red Warbler: (10 points)") .. "|" ..
+				--LOC_NOT("Orange Gob: (5 points)") .. "|" ..
+				--LOC_NOT("Green Wrangler: (3 points)") .. "|" ..
+
+
+				"", 4, 4000
+				)
+
+	CreateMeSomeCircles()
+	RebuildTeamInfo() -- control
+	lastRound = TotalRounds
+
+end
+
+function onScreenResize()
+
+	-- redraw Tags so that their screen locations are updated
+	if (CurrentHedgehog ~= nil) and (tumbleStarted == true) then
+			DrawTag(0)
+			DrawTag(1)
+			DrawTag(2)
+	end
+
+end
+
+function onNewTurn()
+
+	--primShotsLeft = primShotsMax
+	radShotsLeft = 2
+	stopMovement = false
+	tumbleStarted = false
+	boosterOn = false
+	beam = false
+	shieldHealth = 30 + 80 -- 50 = 5 secs, roughly
+	shockwaveHealth = 0
+
+	RK = 0
+	GK = 0
+	BK = 0
+	OK = 0
+	SK = 0
+	roundKills = 0
+	shieldMiser = true
+	fierceComp = false
+	shotsFired = 0
+	shotsHit = 0
+	sniperHits = 0
+	pointBlankHits = 0
+	chainLength = 0
+	chainCounter = 0
+	SurfTime = 12
+
+	-------------------------
+	-- gaudy racer
+	-------------------------
+	CheckForNewRound()
+
+	-- Handle Starting Stage of Game
+	if (gameOver == false) and (gameBegun == false) then
+		gameBegun = true
+		roundNumber = 0 -- 0
+		firstClan = GetHogClan(CurrentHedgehog)
+	end
+
+	if gameOver == true then
+		gameBegun = false
+		stopMovement = true
+		tumbleStarted = false
+		SetMyCircles(false)
+	end
+
+
+	-------
+	-- tumbler
+	----
+
+	wepAmmo[0] = 5
+	wepAmmo[1] = 2
+	wepAmmo[2] = 5000
+	wepIndex = 2
+	ChangeWeapon()
+
+
+	HideTags()
+
+	---------------
+	---------------
+	--AddCaption("num g: " .. numGears() )
+	--WriteLnToConsole("onNewTurn, I just set a bunch of variables to their necessary states. This was done at:")
+	--WriteLnToConsole("The above occured at Game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+
+end
+
+function ThingsToBeRunOnGears(gear)
+
+	HandleLifeSpan(gear)
+	DeleteFarFlungBarrel(gear)
+
+	if CirclesAreGo == true then
+		CheckVarious(gear)
+		ProjectileTrack(gear)
+	end
+
+end
+
+
+function onGameTick20()
+
+
+	--WriteLnToConsole("Start of GameTick")
+
+	HandleCircles()
+
+	-- derp
+	--if shockwaveHealth > 0 then
+	--	shockwaveHealth = shockwaveHealth - 1
+	--	shockwaveRad = shockwaveRad + 5
+	--end
+
+
+	if GameTime%100 == 0 then
+
+		if beam == true then
+			shieldHealth = shieldHealth - 1
+			if shieldHealth < 80 then -- <= 80
+				shieldHealth = 80
+				beam = false
+				AddCaption(loc("Shield Depleted"),0xff0000ff,capgrpMessage)
+				PlaySound(sndMineTick)
+				PlaySound(sndSwitchHog)
+			end
+		end
+
+
+
+		--nw WriteLnToConsole("Starting ThingsToBeRunOnGears()")
+
+		runOnGears(ThingsToBeRunOnGears)
+
+		--nw WriteLnToConsole("Finished ThingsToBeRunOnGears()")
+
+		--runOnGears(HandleLifeSpan)
+		--runOnGears(DeleteFarFlungBarrel)
+
+		if CirclesAreGo == true and CurrentHedgehog ~= nil then
+			CheckDistances()
+			--runOnGears(CheckVarious)	-- used to be in handletracking for some bizarre reason
+			--runOnGears(ProjectileTrack)
+		end
+
+		-- white smoke trail as player falls from the sky
+		if (TimeLeft <= 0) and (stopMovement == true) and (CurrentHedgehog ~= nil) then
+			j,k = GetGearVelocity(CurrentHedgehog)
+			if (j ~= 0) and (k ~= 0) then
+				AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmoke, 0, true)
+			end
+		end
+
+		--nw WriteLnToConsole("Finished 100Timer")
+
+	end
+
+
+	-- start the player tumbling with a boom once their turn has actually begun
+	if (tumbleStarted == false) and (gameOver == false) then
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
+			--AddCaption(LOC_NOT("Good to go!"))
+			tumbleStarted = true
+			TimeLeft = div(TurnTime, 1000)	--45
+			FadeAlpha = 0
+			rAlpha = 255
+			AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+			DrawTag(0)
+			DrawTag(1)
+			DrawTag(2)
+			SetMyCircles(true)
+		end
+	end
+
+	--WriteLnToConsole("Finished initial check")
+
+	if (CurrentHedgehog ~= nil) and (tumbleStarted == true) then
+
+		--AddCaption(GetX(CurrentHedgehog) .. ";" .. GetY(CurrentHedgehog) )
+
+		-- Calculate and display turn time
+		if GameTime%1000 == 0 then
+			TimeLeft = TimeLeft - 1
+
+			if TimeLeft >= 0 then
+				--AddCaption(LOC_NOT("Time Left: ") .. TimeLeft)
+				DrawTag(0)
+			end
+
+		end
+
+		--WriteLnToConsole("Finished timeleft calculations")
+
+		-------------------------------
+		-- Player has run out of luck (out of time or hit by gtShell)
+		-------------------------------
+		-- checks in FloatyThings
+		if PlayerIsFine() == false then
+			TimeLeft = 0
+		end
+
+		--WriteLnToConsole("successfully checked playerIsFine")
+
+		if (TimeLeft == 0) then
+			if (stopMovement == false) then	--time to stop the player
+				stopMovement = true
+				boosterOn = false
+				beam = false
+				upOn = false
+				down = false
+				leftOn = false
+				rightOn = false
+				SetMyCircles(false)
+				HideTags()
+				rAlpha = 255
+				--nw WriteLnToConsole("Player is out of luck")
+
+				if shieldMiser == true then
+
+					p = (roundKills*3.5) - ((roundKills*3.5)%1) + 2
+
+					AddCaption(loc("Shield Miser!") .." +" .. p .." ".. loc("points") .. "!",0xffba00ff,capgrpAmmoinfo)
+					AwardPoints(p)
+				end
+
+				if ((shotsHit / shotsFired * 100) >= 80) and (shotsFired > 4) then
+					AddCaption(loc("Accuracy Bonus!") .. " +15 " .. loc("points") .. "!",0xffba00ff,capgrpVolume)
+					AwardPoints(15)
+				end
+
+			end
+		else -- remove this if you want tumbler to fall slowly on death
+		-------------------------------
+		-- Player is still in luck
+		-------------------------------
+
+
+			--WriteLnToConsole("about to do chainCounter checks")
+			if chainCounter > 0 then
+				chainCounter = chainCounter -1
+				if chainCounter == 0 then
+					chainLength = 0
+				end
+			end
+
+			-- handle movement based on IO
+			if GameTime%100 == 0 then -- 100
+				--nw WriteLnToConsole("Start of Player MoveTimer")
+
+				---------------
+				-- new trail code
+				---------------
+				-- the trail lets you know you have 5s left to pilot, akin to birdy feathers
+				if (TimeLeft <= 5) and (TimeLeft > 0) then							--vgtSmoke
+					tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmoke, 0, true)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+					SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, GetClanColor(GetHogClan(CurrentHedgehog)) )
+				end
+				--------------
+				--------------
+
+				------------------------
+				-- surfer achievement
+				------------------------
+
+				if (WaterLine - GetY(CurrentHedgehog)) < 15 then
+					SurfTime = SurfTime -1
+				end
+
+				if SurfTime ~= 12 then
+
+					SurfTime = SurfTime - 1
+					if SurfTime <= 0 then
+						for i = 0,(TeamsCount-1) do
+							if teamClan[i] == GetHogClan(CurrentHedgehog) and (teamSurfer[i] == false) then
+								teamSurfer[i] = true
+								SurfTime = 12
+								AddCaption(loc("Surfer! +15 points!"),0xffba00ff,capgrpVolume)
+								AwardPoints(15)
+							end
+						end
+					end
+				end
+
+
+				dx, dy = GetGearVelocity(CurrentHedgehog)
+
+				--WriteLnToConsole("I just got the velocity of currenthedgehog. It is dx: " .. dx .. "; dy: " .. dy)
+				--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+
+				if boosterOn == true then
+					tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtDust, 0, false)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+					SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, 1, g9, GetClanColor(GetHogClan(CurrentHedgehog)) )
+					dxlimit = 0.8*fMod
+					dylimit = 0.8*fMod
+				else
+					dxlimit = 0.4*fMod
+					dylimit = 0.4*fMod
+				end
+
+				if dx > dxlimit then
+					dx = dxlimit
+				end
+				if dy > dylimit then
+					dy = dylimit
+				end
+				if dx < -dxlimit then
+					dx = -dxlimit
+				end
+				if dy < -dylimit then
+					dy = -dylimit
+				end
+
+
+				if leftOn == true then
+					dx = dx - 0.1*fMod
+				end
+				if rightOn == true then
+					dx = dx + 0.1*fMod
+				end
+
+				if upOn == true then
+					dy = dy - 0.1*fMod
+				end
+				if downOn == true then
+					dy = dy + 0.1*fMod
+				end
+
+				SetGearVelocity(CurrentHedgehog, dx, dy)
+
+				--WriteLnToConsole("I just SET the velocity of currenthedgehog. It is now dx: " .. dx .. "; dy: " .. dy)
+				--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+				--nw WriteLnToConsole("End of Player MoveTimer")
+
+			end
+
+
+			HandleFlameThrower()
+
+
+		end -- new end I put here to check if he's still alive or not
+
+	end
+
+	--WriteLnToConsole("End of GameTick")
+
+end
+
+function onGearDamage(gear, damage)
+	if GetGearType(gear) == gtHedgehog then
+		if (fierceComp == false) and (damage >= 60) and (GetHogClan(gear) ~= GetHogClan(CurrentHedgehog)) then
+			fierceComp = true
+			AddCaption(loc("Fierce Competition!") .. " +8 " .. loc("points") .. "!",0xffba00ff,capgrpGameState)
+			AwardPoints(8)
+		end
+	end
+end
+
+function onGearResurrect(gear)
+
+	-- did I fall into the water? well, that was a stupid thing to do
+	if gear == CurrentHedgehog then
+		TimeLeft = 0
+		--WriteLnToConsole("Current hedgehog just drowned himself")
+		--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+	end
+
+end
+
+function onGearAdd(gear)
+
+	if isATrackedGear(gear) then
+		trackGear(gear)
+		setNewGearValues(gear)
+	end
+
+	--if GetGearType(gear) == gtBall then
+	--	SetTimer(gear, 5000)
+	--end
+
+	if GetGearType(gear) == gtHedgehog then
+		SetEffect(gear, heResurrectable, true)
+
+		-----------
+		-- control
+		hhs[numhhs] = gear
+		numhhs = numhhs + 1
+		-----------
+	end
+
+end
+
+function onGearDelete(gear)
+
+
+	--[[if GetGearType(gear) == gtShell then
+		--nw WriteLnToConsole("on GearDelete call. Shell ID: " .. getGearValue(gear,"ID"))
+		--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+
+		--if CurrentHedgehog ~= nil then
+		--	WriteLnToConsole("As it happens, player is at: " .. GetX(CurrentHedgehog) .. "; " .. GetY(CurrentHedgehog))
+		--end
+	elseif GetGearType(gear) == gtExplosives then
+		--nw WriteLnToConsole("on GearDelete call. Explosives ID: " .. getGearValue(gear,"ID"))
+		--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+
+		--if CurrentHedgehog ~= nil then
+		--	WriteLnToConsole("As it happens, player is at: " .. GetX(CurrentHedgehog) .. "; " .. GetY(CurrentHedgehog))
+		--end
+	elseif GetGearType(gear) == gtFlame then
+		--WriteLnToConsole("on GearDelete flame")
+	end]]
+
+	if isATrackedGear(gear) then
+		trackDeletion(gear)
+	end
+
+	if CurrentHedgehog ~= nil then
+		FollowGear(CurrentHedgehog)
+	end
+
+end
+
+
+
+------------------------------------------------------------
+------------------------------------------------------------
+------------------------------------------------------------
+------------------------------------------------------------
+-- FLOATY THINGS
+-- "I'll make this into a generic library and code properly
+-- when I have more time and feel less lazy"
+------------------------------------------------------------
+------------------------------------------------------------
+------------------------------------------------------------
+------------------------------------------------------------
+
+function DoHorribleThings(cUID)
+
+	-- work out the distance to the target
+	g1X, g1Y = GetGearPosition(CurrentHedgehog)
+	g2X, g2Y = vCircX[cUID], vCircY[cUID]
+	q = g1X - g2X
+	w = g1Y - g2Y
+	r = math.sqrt( (q*q) + (w*w) )	--alternate
+
+	opp = w
+	if opp < 0 then
+		opp = opp*-1
+	end
+
+	-- work out the angle (theta) to the target
+	t = math.deg ( math.asin(opp / r) )
+
+	-- based on the radius of the radar, calculate what x/y displacement should be
+	NR = 150 -- radius at which to draw circs
+	NX = math.cos( math.rad(t) ) * NR
+	NY = math.sin( math.rad(t) ) * NR
+
+	-- displace xy based on where this thing actually is
+
+	if r < NR then
+		rCircX[cUID] = g2X
+	elseif q > 0 then
+		rCircX[cUID] = g1X - NX
+	else
+		rCircX[cUID] = g1X + NX
+	end
+
+	if r < NR then
+		rCircY[cUID] = g2Y
+	elseif w > 0 then
+		rCircY[cUID] = g1Y - NY
+	else
+		rCircY[cUID] = g1Y + NY
+	end
+
+end
+
+function PlayerIsFine()
+	return (playerIsFine)
+end
+
+function GetDistFromXYtoXY(a, b, c, d)
+	q = a - c
+	w = b - d
+	return ( (q*q) + (w*w) )
+end
+
+function GetDistFromGearToGear(gear, gear2)
+
+	g1X, g1Y = GetGearPosition(gear)
+	g2X, g2Y = GetGearPosition(gear2)
+	q = g1X - g2X
+	w = g1Y - g2Y
+
+
+	--[[
+	WriteLnToConsole("I just got the position of two gears and calculated the distance betwen them")
+	if gear == CurrentHedgehog then
+		WriteLnToConsole("Gear 1 is CurrentHedgehog.")
+	end
+	if gear2 == CurrentHedgehog then
+		WriteLnToConsole("Gear 2 is CurrentHedgehog.")
+	end
+	WriteLnToConsole("G1X: " .. g1X .. "; G1Y: " .. g1Y)
+	WriteLnToConsole("G2X: " .. g2X .. "; G2Y: " .. g2Y)
+	WriteLnToConsole("Their distance is " .. (q*q) + (w*w) )
+	WriteLnToConsole("The above events occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+]]
+
+
+	return ( (q*q) + (w*w) )
+
+end
+
+function GetDistFromGearToXY(gear, g2X, g2Y)
+
+	g1X, g1Y = GetGearPosition(gear)
+	q = g1X - g2X
+	w = g1Y - g2Y
+
+
+	--[[WriteLnToConsole("I just got the position of a gear and calculated the distance betwen it and another xy")
+	if gear == CurrentHedgehog then
+		WriteLnToConsole("Gear 1 is CurrentHedgehog.")
+	end
+
+	WriteLnToConsole("G1X: " .. g1X .. "; G1Y: " .. g1Y)
+	WriteLnToConsole("Other X: " .. g2X .. "; Other Y: " .. g2Y)
+	WriteLnToConsole("Their distance is " .. (q*q) + (w*w) )
+	WriteLnToConsole("The above events occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+]]
+
+
+	return ( (q*q) + (w*w) )
+
+
+end
+
+function CreateMeSomeCircles()
+
+	for i = 0, 7 do
+		vCCount = vCCount +1
+		vCirc[i] = AddVisualGear(0,0,vgtCircle,0,true)
+
+		rCirc[i] = AddVisualGear(0,0,vgtCircle,0,true)
+		rCircX[i] = 0
+		rCircY[i] = 0
+
+		vCircDX[i] = 0
+		vCircDY[i] = 0
+
+		vType[i] = "generic"
+		vCounter[i] = 0
+		vCounterLim[i] = 150
+		vCircScore[i] = 0
+		vCircHealth[i] = 1
+
+		vCircMinA[i] = 80	--80 --20
+		vCircMaxA[i] = 255
+		vCircType[i] = 1	--1
+		vCircPulse[i] = 10
+		vCircFuckAll[i] = 0
+		vCircRadius[i] = 0
+		vCircWidth[i] = 3 --5
+
+		vCircRadMax[i] = 0
+		vCircRadMin[i] = 0
+		vCircRadDir[i] = -1
+		vCircRadCounter[i] = 0
+
+		vCircX[i], vCircY[i] = 0,0
+
+		vCircCol[i] = 0xff00ffff
+
+		SetVisualGearValues(vCirc[i], vCircX[i], vCircY[i], vCircMinA[i], vCircMaxA[i], vCircType[i], vCircPulse[i], vCircFuckAll[i], vCircRadius[i], vCircWidth[i], vCircCol[i])
+
+		SetVisualGearValues(rCirc[i], 0, 0, 100, 255, 1, 10, 0, 40, 3, vCircCol[i])
+
+	end
+
+	pShield = AddVisualGear(0,0,vgtCircle,0,true)
+	--SetVisualGearValues(pShield, GetX(CurrentHedgehog), GetY(CurrentHedgehog), 80, 200, 1, 10, 0, 200, 5, 0xff00ffff)
+
+
+	shockwave = AddVisualGear(0,0,vgtCircle,0,true)
+
+end
+
+function IGotMeASafeXYValue(i)
+
+	acceptibleDistance = 800
+
+	-- put this in here to thwart attempts at repositioning and test sanity limit
+	--vCircX[i] = GetX(CurrentHedgehog)+250
+	--vCircY[i] = GetY(CurrentHedgehog)+250
+
+	vCircX[i] = GetRandom(5000)
+	vCircY[i] = GetRandom(2000)
+	dist = GetDistFromGearToXY(CurrentHedgehog, vCircX[i], vCircY[i])
+	if dist > acceptibleDistance*acceptibleDistance then
+		return(true)
+	else
+		return(false)
+	end
+
+end
+
+function CircleDamaged(i)
+
+	res = ""
+	vCircHealth[i] = vCircHealth[i] -1
+
+	if vCircHealth[i] <= 0 then
+	-- circle is dead, do death effects/consequences
+
+		vCircActive[i] = false
+
+		if (vType[i] == "drone") then
+			PlaySound(sndHellishImpact4)
+			TimeLeft = TimeLeft + 4
+			AddCaption(loc("Time Extended!") .. "+" .. 4 .. loc("sec"), 0xff0000ff,capgrpMessage )
+			DrawTag(0)
+
+			morte = AddGear(vCircX[i], vCircY[i], gtExplosives, 0, 0, 0, 1)
+			SetHealth(morte, 0)
+
+			RK = RK + 1
+			if RK == 5 then
+				RK = 0
+				AddCaption(loc("Drone Hunter!") .. " +10 " .. loc("points") .. "!",0xffba00ff,capgrpMessage2)
+				AwardPoints(10)
+			end
+
+		elseif (vType[i] == "ammo") then
+			AddVisualGear(vCircX[i], vCircY[i], vgtExplosion, 0, false)
+			PlaySound(sndExplosion)
+			PlaySound(sndShotgunReload)
+			wepAmmo[0] = wepAmmo[0] +3
+			--primShotsLeft = primShotsLeft + 3
+			AddCaption("+" .. 3 .. " " .. loc("Ammo"), 0x00ff00ff,capgrpMessage)
+			DrawTag(1)
+
+			GK = GK + 1
+			if GK == 3 then
+				GK = 0
+				AddCaption(loc("Ammo Maniac!") .. " +5 " .. loc("points") .. "!",0xffba00ff,capgrpMessage2)
+				AwardPoints(5)
+			end
+
+		elseif (vType[i] == "bonus") then
+
+			AddVisualGear(vCircX[i], vCircY[i], vgtExplosion, 0, false)
+			PlaySound(sndExplosion)
+
+			AddVisualGear(vCircX[i], vCircY[i], vgtFire, 0, false)
+			AddVisualGear(vCircX[i], vCircY[i], vgtFire, 0, false)
+			AddVisualGear(vCircX[i], vCircY[i], vgtFire, 0, false)
+			AddVisualGear(vCircX[i], vCircY[i], vgtFire, 0, false)
+			AddVisualGear(vCircX[i], vCircY[i], vgtFire, 0, false)
+			AddVisualGear(vCircX[i], vCircY[i], vgtSmoke, 0, false)
+
+			PlaySound(sndVaporize)
+			--sndWarp sndMineTick --sndSwitchHog --sndSuddenDeath
+
+			shieldHealth = shieldHealth + 30
+			AddCaption(loc("Shield boosted! +30 power"), 0xa800ffff,capgrpMessage)
+			if shieldHealth >= 250 then
+				shieldHealth = 250
+				AddCaption(loc("Shield is fully recharged!"),0xa800ffff,capgrpMessage)
+			end
+			DrawTag(2)
+
+			OK = OK + 1
+			if OK == 3 then
+				OK = 0
+				AddCaption(loc("Shield Seeker!") .. " + 10 " .. loc("points") .. "!",0xffba00ff,capgrpMessage2)
+				AwardPoints(10)
+			end
+
+		elseif (vType[i] == "blueboss") then
+			PlaySound(sndHellishImpact3)
+			AddCaption(loc("Boss defeated!") .. " +30 " .. loc("points") .. "!", 0x0050ffff,capgrpMessage)
+
+			morte = AddGear(vCircX[i], vCircY[i], gtExplosives, 0, 0, 0, 1)
+			SetHealth(morte, 0)
+
+			BK = BK + 1
+			if BK == 2 then
+				BK = 0
+				AddCaption(loc("Boss Slayer!") .. " +25 " .. loc("points") .. "!",0xffba00ff,capgrpMessage2)
+				AwardPoints(25)
+			end
+
+		end
+
+		AwardPoints(vCircScore[i])
+		AwardKills()
+		SetUpCircle(i)
+		res = "fatal"
+
+		chainCounter = 3000
+		chainLength = chainLength + 1
+		if chainLength > 1 then
+			AddCaption( chainLength .. "-" .. loc("Hit Combo!") .. " +" .. chainLength*2 .. " " .. loc("points") .. "!",0xffba00ff,capgrpAmmostate)
+			AwardPoints(chainLength*2)
+		end
+
+	else
+	-- circle is merely damaged
+	-- do damage effects/sounds
+		AddVisualGear(vCircX[i], vCircY[i], vgtSteam, 0, false)
+		r = GetRandom(4)
+		if r == 0 then
+			PlaySound(sndHellishImpact1)
+		elseif r == 1 then
+			PlaySound(sndHellishImpact2)
+		elseif r == 2 then
+			PlaySound(sndHellishImpact3)
+		elseif r == 3 then
+			PlaySound(sndHellishImpact4)
+		end
+		res = "non-fatal"
+
+	end
+
+	return(res)
+
+end
+
+function SetUpCircle(i)
+
+
+	r = GetRandom(10)
+	--r = 8
+	-- 80% of spawning either red/green
+	if r <= 7 then
+
+		--r = GetRandom(5)
+		r = GetRandom(2)
+		--r = 1
+		if r == 0 then
+		--if r <= 2 then
+			vCircCol[i] = 0xff0000ff -- red
+			vType[i] = "drone"
+			vCircRadMin[i] = 50	*5
+			vCircRadMax[i] = 90	*5
+			vCounterLim[i] = 150
+			vCircScore[i] = 10
+			vCircHealth[i] = 1
+		--else
+		elseif r == 1 then
+			vCircCol[i] = 0x00ff00ff -- green
+			vType[i] = "ammo"
+			vCircRadMin[i] = 25	*7
+			vCircRadMax[i] = 30	*7
+			vCircScore[i] = 3
+			vCircHealth[i] = 1
+		end
+
+	-- 20% chance of spawning boss or bonus
+	else
+		r = GetRandom(5)
+		--r = GetRandom(2)
+		--r = 0
+		if r <= 1 then
+		--if r == 0 then
+			vCircCol[i] = 0x0050ffff -- sexy blue
+			vType[i] = "blueboss"
+			vCircRadMin[i] = 100*5
+			vCircRadMax[i] = 180*5
+			vCircWidth[i] = 1
+			vCounterLim[i] = 100
+			vCircScore[i] = 30
+			vCircHealth[i] = 3
+		else
+		--elseif r == 1 then
+			--vCircCol[i] = 0xffae00ff -- orange
+			vCircCol[i] = 0xa800ffff -- purp
+			vType[i] = "bonus"
+			vCircRadMin[i] = 20 *7
+			vCircRadMax[i] = 40 *7
+			vCircScore[i] = 5
+			vCircHealth[i] = 1
+		end
+
+	end
+
+	-- regenerate circle xy if too close to player or until sanity limit kicks in
+	reN = 0
+	--zzz = 0
+	while (reN < 10) do
+		if IGotMeASafeXYValue(i) == false then
+			reN = reN + 1
+			--zzz = zzz + 1
+		else
+			reN = 15
+		end
+	end
+	--AddCaption("Took me this many retries: " .. zzz) -- number of times it took to work
+
+	vCircRadius[i] = vCircRadMax[i] - GetRandom(vCircRadMin[i])
+
+	g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(vCirc[i])
+	SetVisualGearValues(vCirc[i], vCircX[i], vCircY[i], g3, g4, g5, g6, g7, vCircRadius[i], vCircWidth[i], vCircCol[i]-0x000000ff)
+	-- - -0x000000ff
+
+	g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(rCirc[i])
+	SetVisualGearValues(rCirc[i], 0, 0, g3, g4, g5, g6, g7, g8, g9, vCircCol[i]-0x000000ff)
+
+
+	vCircActive[i] = true -- new
+
+	--nw WriteLnToConsole("CIRC " .. i .. ": X: " .. vCircX[i] .. "; Y: " .. vCircY[i])
+	--nw WriteLnToConsole("CIRC " .. i .. ": dX: " .. vCircDX[i] .. "; dY: " .. vCircDY[i])
+	--nw WriteLnToConsole("CIRC " .. i .. ": RAD:" .. vCircRadius[i])
+
+end
+
+function SetMyCircles(s)
+
+	CirclesAreGo = s
+	playerIsFine = s
+
+	if s == true then
+		--nw WriteLnToConsole("About to set up all circles, old values are here:")
+		for i = 0,(vCCount-1) do
+			--nw WriteLnToConsole("CIRC " .. i .. ": X: " .. vCircX[i] .. "; Y: " .. vCircY[i])
+			--nw WriteLnToConsole("CIRC " .. i .. ": dX: " .. vCircDX[i] .. "; dY: " .. vCircDY[i])
+			--nw WriteLnToConsole("CIRC " .. i .. ": RAD:" .. vCircRadius[i])
+		end
+		--nw WriteLnToConsole("Old values given, new values to follow...")
+	end
+
+	for i = 0,(vCCount-1) do
+
+		if s == false then
+			--vCircCol[i] = 0xffffffff
+			vCircActive[i] = false
+		elseif s == true then
+			SetUpCircle(i)
+		end
+
+	end
+
+end
+
+function WellHeAintGonnaJumpNoMore(x,y)
+
+	AddVisualGear(x, y, vgtBigExplosion, 0, false)
+	playerIsFine = false
+	AddCaption(loc("GOTCHA!"))
+	PlaySound(sndExplosion)
+	PlaySound(sndHellish)
+
+	targetHit = true
+
+end
+
+--- collision detection for weapons fire
+function CheckVarious(gear)
+
+	--if (GetGearType(gear) == gtExplosives) then
+		--nw WriteLnToConsole("Start of CheckVarious(): Exp ID: " .. getGearValue(gear,"ID"))
+	--elseif (GetGearType(gear) == gtShell) then
+		--nw WriteLnToConsole("Start of CheckVarious(): Shell ID: " .. getGearValue(gear,"ID"))
+	--end
+
+	targetHit = false
+
+	-- if circle is hit by player fire
+	if (GetGearType(gear) == gtExplosives) then
+		circsHit = 0
+
+		for i = 0,(vCCount-1) do
+
+			--nw WriteLnToConsole("Is it neccessary to check for collision with circ " .. i)
+
+			--if (vCircActive[i] == true) and ( (vType[i] == "drone") ) then
+
+				--nw WriteLnToConsole("YES. about to calc distance between gtExplosives and circ " .. i)
+
+				dist = GetDistFromGearToXY(gear, vCircX[i], vCircY[i])
+
+				-- calculate my real radius if I am an aura
+				if vCircType[i] == 0 then
+					NR = vCircRadius[i]
+				else
+					NR = (48/100*vCircRadius[i])/2
+				end
+
+				if dist <= NR*NR then
+
+
+					--nw WriteLnToConsole("Collision confirmed. The gtExplosives is within the circ radius!")
+
+					dist = (GetDistFromXYtoXY(vCircX[i], vCircY[i], getGearValue(gear,"XP"), getGearValue(gear,"YP")) - (NR*NR))
+					--AddCaption(loc("Dist: ") .. dist .. "!",0xffba00ff,capgrpGameState)
+					if dist >= 1000000 then
+						sniperHits = sniperHits +1
+						AddCaption(loc("Sniper!") .. " +8 " .. loc("points") .. "!",0xffba00ff,capgrpGameState)
+						AwardPoints(8)
+						if sniperHits == 3 then
+							sniperHits = 0
+							AddCaption(loc("They Call Me Bullseye!") .. " +16 " .. loc("points") .. "!",0xffba00ff,capgrpGameState)
+							AwardPoints(15)
+						end
+					elseif dist <= 6000 then
+						pointBlankHits = pointBlankHits +1
+						if pointBlankHits == 3 then
+							pointBlankHits = 0
+							AddCaption(loc("Point Blank Combo!") .. " +5 " .. loc("points") .. "!",0xffba00ff,capgrpGameState)
+							AwardPoints(5)
+						end
+					end
+
+					AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+
+					targetHit = true
+					--DeleteGear(gear)
+					--SetHealth(gear,0)
+						--WriteLnToConsole("set " .. "Exp ID: " .. getGearValue(gear,"ID") .. " health to 0")
+						--WriteLnToConsole("targetHit set to true, explosive is at distance " .. dist .. "(within range " .. NR*NR.. ") of circ" )
+
+					CircleDamaged(i)
+
+					circsHit = circsHit + 1
+					if circsHit > 1 then
+						AddCaption(loc("Multi-shot!") .. " +15 " .. loc("points") .. "!",0xffba00ff,capgrpAmmostate)
+						AwardPoints(15)
+						circsHit = 0
+					end
+
+					shotsHit = shotsHit + 1
+
+
+
+				end
+
+			--end
+
+		end
+
+	-- if player is hit by circle bazooka
+	elseif (GetGearType(gear) == gtShell) and (CurrentHedgehog ~= nil) then --or (GetGearType(gear) == gtBall) then
+
+		dist = GetDistFromGearToGear(gear, CurrentHedgehog)
+
+		if beam == true then
+
+			if dist < 3000 then
+				tempE = AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, true)
+				g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+				SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, 0xff00ffff )
+				PlaySound(sndVaporize)
+				DeleteGear(gear)
+
+				SK = SK + 1
+				if SK == 5 then
+					SK = 0
+					AddCaption(loc("Shield Master!") .. " +10 " .. loc("points") .. "!",0xffba00ff,capgrpAmmoinfo)
+					AwardPoints(10)
+				end
+			end
+
+		elseif dist < 1600 then
+			WellHeAintGonnaJumpNoMore(GetX(gear), GetY(gear))
+		end
+
+		--[[if targetHit == true then
+			WriteLnToConsole("about to delete shell due to targetHit being set to true earlier")
+			DeleteGear(gear)
+			WriteLnToConsole("there, I deleted it")
+		end]]
+
+
+	end
+
+	if targetHit == true then
+			--nw WriteLnToConsole("about to delete something due to targetHit being set to true earlier")
+			DeleteGear(gear)
+			--nw WriteLnToConsole("there, I deleted it")
+	end
+
+	--nw WriteLnToConsole("End of CheckVarious()")
+
+end
+
+-- collision detection for player entering a circle
+function CheckDistances()
+
+	--nw WriteLnToConsole("Start of CheckDistances()")
+
+	for i = 0,(vCCount-1) do
+
+
+		--nw WriteLnToConsole("Attempting to calculate dist of circ " .. i)
+
+		g1X, g1Y = GetGearPosition(CurrentHedgehog)
+		g2X, g2Y = vCircX[i], vCircY[i]
+
+		g1X = g1X - g2X
+		g1Y = g1Y - g2Y
+		dist = (g1X*g1X) + (g1Y*g1Y)
+
+		--DoHorribleThings(i, g1X, g1Y, g2X, g2Y, dist)
+
+		--nw WriteLnToConsole("Calcs done. Dist to CurrentHedgehog is " .. dist)
+
+		-- calculate my real radius if I am an aura
+		if vCircType[i] == 0 then
+			NR = vCircRadius[i]
+		else
+			NR = (48/100*vCircRadius[i])/2
+		end
+
+		if dist <= NR*NR then
+
+			if 	(vCircActive[i] == true) and
+				((vType[i] == "ammo") or (vType[i] == "bonus") )
+			then
+
+				CircleDamaged(i)
+
+			elseif (vCircActive[i] == true) and
+					( (vType[i] == "drone") or (vType[i] == "blueboss") )
+			then
+
+				ss = CircleDamaged(i)
+				WellHeAintGonnaJumpNoMore(GetX(CurrentHedgehog),GetY(CurrentHedgehog))
+
+				if ss == "fatal" then
+
+					if (wepAmmo[0] == 0) and (TimeLeft <= 9) then
+					--if (primShotsLeft == 0) and (TimeLeft <= 9) then
+						AddCaption(loc("Kamikaze Expert!") .. " +15 " .. loc("points") .. "!",0xffba00ff,capgrpMessage)
+						AwardPoints(15)
+					elseif (wepAmmo[0] == 0) then
+						AddCaption(loc("Depleted Kamikaze!") .. " +5 " .. loc("points") .. "!",0xffba00ff,capgrpMessage)
+						AwardPoints(5)
+					elseif TimeLeft <= 9 then
+						AddCaption(loc("Timed Kamikaze!") .. " +10 " .. loc("points") .. "!",0xffba00ff,capgrpMessage)
+						AwardPoints(10)
+					end
+				end
+
+			end
+
+
+		end
+
+	end
+
+	--nw WriteLnToConsole("End of CheckDistances()")
+
+end
+
+function HandleCircles()
+
+	--[[if CirclesAreGo == true then
+
+		--CheckDistances()
+		--runOnGears(CheckVarious)	-- used to be in handletracking for some bizarre reason
+
+		--pTimer = pTimer + 1
+		--if pTimer == 100 then
+		--	pTimer = 0
+		--	runOnGears(ProjectileTrack)
+		--end
+
+	end]]
+
+
+	if rAlpha ~= 255 then
+
+		if GameTime%100 == 0 then
+
+			rAlpha = rAlpha + 5
+			if rAlpha >= 255 then
+				rAlpha = 255
+			end
+		end
+
+	end
+
+	for i = 0,(vCCount-1) do
+
+		--if (vCircActive[i] == true) then
+			SetVisualGearValues(rCirc[i], rCircX[i], rCircY[i], 100, 255, 1, 10, 0, 40, 3, vCircCol[i]-rAlpha)
+		--end
+
+
+
+		vCounter[i] = vCounter[i] + 1
+		if vCounter[i] >= vCounterLim[i] then
+
+			vCounter[i] = 0
+
+			if 	((vType[i] == "drone") or (vType[i] == "blueboss") ) and
+				(vCircActive[i] == true) then
+				AddGear(vCircX[i], vCircY[i], gtShell, 0, 0, 0, 1)
+
+				--WriteLnToConsole("Circle " .. i .. " just fired/added a gtShell")
+				--WriteLnToConsole("The above event occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+
+			--elseif (vType[i] == "bluebottle") and (vCircActive[i] == true) then
+			--	AddGear(vCircX[i], vCircY[i]-vCircRadius[i], gtBall, 0, 0, 0, 1)
+			--	AddGear(vCircX[i], vCircY[i]+vCircRadius[i], gtBall, 0, 0, 0, 1)
+			--	AddGear(vCircX[i]-vCircRadius[i], vCircY[i], gtBall, 0, 0, 0, 1)
+			--	AddGear(vCircX[i]+vCircRadius[i], vCircY[i], gtBall, 0, 0, 0, 1)
+			end
+
+		end
+
+		if (vCircActive[i] == true) then
+
+			vCircRadCounter[i] = vCircRadCounter[i] + 1
+			if vCircRadCounter[i] == 100 then
+
+				vCircRadCounter[i] = 0
+
+				-- make my radius increase/decrease faster if I am an aura
+				if vCircType[i] == 0 then
+					M = 1
+				else
+					M = 10
+				end
+
+				vCircRadius[i] = vCircRadius[i] + vCircRadDir[i]
+				if vCircRadius[i] > vCircRadMax[i] then
+					vCircRadDir[i] = -M
+				elseif vCircRadius[i] < vCircRadMin[i] then
+					vCircRadDir[i] = M
+				end
+
+
+				-- random effect test
+				-- maybe use this to tell the difference between circs
+				-- you can kill by shooting or not
+				--vgtSmoke vgtSmokeWhite
+				--vgtSteam -- nice long trail
+				--vgtDust -- short trail on earthrise
+				--vgtSmokeTrace
+				if vType[i] == "ammo" then
+
+					tempE = AddVisualGear(vCircX[i], vCircY[i], vgtSmoke, 0, true)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)	--0xff00ffff	--0x00ff00ff
+					SetVisualGearValues(tempE, vCircX[i], vCircY[i], g3, g4, g5, g6, g7, g8, g9, vCircCol[i] )
+
+					--AddVisualGear(vCircX[i], vCircY[i], vgtDust, 0, true)
+
+				elseif vType[i] == "bonus" then
+
+					tempE = AddVisualGear(vCircX[i], vCircY[i], vgtDust, 0, true)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)	--0xff00ffff	--0x00ff00ff --vCircCol[i]
+					SetVisualGearValues(tempE, vCircX[i], vCircY[i], g3, g4, g5, g6, g7, 1, g9, 0xff00ffff )
+
+
+				elseif vType[i] == "blueboss" then
+
+					k = 25
+					g = vgtSteam
+					trailColour = 0xae00ffff
+
+					-- 0xffae00ff -- orange
+					-- 0xae00ffff -- purp
+
+					tempE = AddVisualGear(vCircX[i], vCircY[i], g, 0, true)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)	--0xff00ffff	--0x00ff00ff
+					SetVisualGearValues(tempE, vCircX[i], vCircY[i]+k, g3, g4, g5, g6, g7, g8, g9, trailColour-75 )
+
+					tempE = AddVisualGear(vCircX[i], vCircY[i], g, 0, true)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)	--0xff00ffff	--0x00ff00ff
+					SetVisualGearValues(tempE, vCircX[i]+k, vCircY[i]-k, g3, g4, g5, g6, g7, g8, g9, trailColour-75 )
+
+					tempE = AddVisualGear(vCircX[i], vCircY[i], g, 0, true)
+					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)	--0xff00ffff	--0x00ff00ff
+					SetVisualGearValues(tempE, vCircX[i]-k, vCircY[i]-k, g3, g4, g5, g6, g7, g8, g9, trailColour-75 )
+
+
+				end
+
+
+			end
+
+		end
+
+
+	end
+
+	-- alter the circles velocities
+	if GameTime%2000 == 0 then
+
+		for i = 0,(vCCount-1) do
+
+			-- bounce the circles off the edges if they go too far
+			-- or make them move in random directions
+
+			if vCircX[i] > 5500 then
+				vCircDX[i] = -4	--5 circmovchange
+			elseif vCircX[i] < -1500 then
+				vCircDX[i] = 4	--5 circmovchange
+			else
+
+				z = GetRandom(2)
+				if z == 1 then
+					z = 1
+				else
+					z = -1
+				end
+				vCircDX[i] = vCircDX[i] + GetRandom(3)*z	--3 circmovchange
+			end
+
+			if vCircY[i] > 1500 then
+				vCircDY[i] = -4	--5 circmovchange
+			elseif vCircY[i] < -2900 then
+				vCircDY[i] = 4	--5 circmovchange
+			else
+				z = GetRandom(2)
+				if z == 1 then
+					z = 1
+				else
+					z = -1
+				end
+				vCircDY[i] = vCircDY[i] + GetRandom(3)*z	--3 circmovchange
+			end
+
+		end
+
+	end
+
+	-- move the circles according to their current velocities
+	--m2Count = m2Count + 1
+	--if m2Count == 25 then	--25 circmovchange
+
+	--	m2Count = 0
+		for i = 0,(vCCount-1) do
+			vCircX[i] = vCircX[i] + vCircDX[i]
+			vCircY[i] = vCircY[i] + vCircDY[i]
+
+			if (CurrentHedgehog ~= nil) and (rAlpha ~= 255) then
+				DoHorribleThings(i)--(i, g1X, g1Y, g2X, g2Y, dist)
+			end
+
+		end
+
+		if (TimeLeft == 0) and (tumbleStarted == true) then
+
+			FadeAlpha = FadeAlpha + 1
+			if FadeAlpha >= 255 then
+				FadeAlpha = 255
+			end
+
+			--new
+			--if FadeAlpha == 1 then
+			--	AddCaption("GOT IT")
+			--	for i = 0,(vCCount-1) do
+			--		g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(vCirc[i])
+			--		vCircCol[i] = g10
+			--	end
+			--end
+
+		end
+
+
+		-- derp
+		if shockwaveHealth > 0 then
+			shockwaveHealth = shockwaveHealth - 1
+			shockwaveRad = shockwaveRad + 80
+
+			--mrm = ((48/100*shockwaveRad)/2)
+			--AddVisualGear(GetX(CurrentHedgehog)-mrm+GetRandom(mrm*2),GetY(CurrentHedgehog)-mrm+GetRandom(mrm*2), vgtSmoke, 0, false)
+		end
+
+
+
+	--end
+
+	for i = 0,(vCCount-1) do
+		g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(vCirc[i])		-- vCircCol[i] g10
+		SetVisualGearValues(vCirc[i], vCircX[i], vCircY[i], g3, g4, g5, g6, g7, vCircRadius[i], g9, g10)
+	end
+
+	if 	(TimeLeft == 0) or
+		((tumbleStarted == false)) then
+		for i = 0,(vCCount-1) do
+			g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(vCirc[i])		-- vCircCol[i] g10
+			SetVisualGearValues(vCirc[i], vCircX[i], vCircY[i], g3, g4, g5, g6, g7, vCircRadius[i], g9, (vCircCol[i]-FadeAlpha))
+		end
+	end
+
+
+	if (CurrentHedgehog ~= nil) then
+		if beam == true then
+			g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(pShield)
+			--SetVisualGearValues(pShield, GetX(CurrentHedgehog), GetY(CurrentHedgehog), g3, g4, g5, g6, g7, 200, g9, g10 )
+			SetVisualGearValues(pShield, GetX(CurrentHedgehog), GetY(CurrentHedgehog), g3, g4, g5, g6, g7, 200, g9, 0xa800ffff-0x000000ff - -shieldHealth )
+			DrawTag(2)
+		else
+			SetVisualGearValues(pShield, GetX(CurrentHedgehog), GetY(CurrentHedgehog), g3, g4, g5, g6, g7, 0, g9, g10 )
+		end
+
+		if shockwaveHealth > 0 then
+			g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(shockwave)
+			SetVisualGearValues(shockwave, GetX(CurrentHedgehog), GetY(CurrentHedgehog), g3, g4, g5, g6, g7, shockwaveRad, g9, 0xff3300ff-0x000000ff - -shockwaveHealth )
+		else
+			SetVisualGearValues(shockwave, GetX(CurrentHedgehog), GetY(CurrentHedgehog), g3, g4, g5, g6, g7, 0, g9, g10 )
+		end
+
+	end
+
+
+end
+
+function ProjectileTrack(gear)
+
+	if (GetGearType(gear) == gtShell) then
+
+		--nw WriteLnToConsole("ProjectileTrack() for Shell ID: " .. getGearValue(gear,"ID"))
+
+		-- newnew
+		if (GetGearType(gear) == gtShell) then
+			turningSpeed = 0.1*fMod
+		--elseif (GetGearType(gear) == gtBall) then
+		--	turningSpeed = 0.2*fMod
+		end
+
+		dx, dy = GetGearVelocity(gear)
+
+		--WriteLnToConsole("I'm trying to track currenthedge with shell ID: " .. getGearValue(gear,"ID"))
+		--WriteLnToConsole("I just got the velocity of the shell. It is dx: " .. dx .. "; dy: " .. dy)
+		--WriteLnToConsole("CurrentHedgehog is at X: " .. GetX(CurrentHedgehog) .. "; Y: " .. GetY(CurrentHedgehog) )
+
+        if CurrentHedgehog ~= nil then
+            if GetX(gear) > GetX(CurrentHedgehog) then
+                dx = dx - turningSpeed--0.1
+            else
+                dx = dx + turningSpeed--0.1
+            end
+
+            if GetY(gear) > GetY(CurrentHedgehog) then
+                dy = dy - turningSpeed--0.1
+            else
+                dy = dy + turningSpeed--0.1
+            end
+        end
+
+
+		if (GetGearType(gear) == gtShell) then
+			dxlimit = 0.4*fMod
+			dylimit = 0.4*fMod
+		--elseif (GetGearType(gear) == gtBall) then
+		--	dxlimit = 0.5	--  0.5 is about the same
+		--	dylimit = 0.5 -- 0.6 is faster than player
+		end
+
+		if dx > dxlimit then
+			dx = dxlimit
+		end
+		if dy > dylimit then
+			dy = dylimit
+		end
+		if dx < -dxlimit then
+			dx = -dxlimit
+		end
+		if dy < -dylimit then
+			dy = -dylimit
+		end
+
+		SetGearVelocity(gear, dx, dy)
+
+		--WriteLnToConsole("I just SET the velocity of shell towards currenthegdge. It is now dx: " .. dx .. "; dy: " .. dy)
+		--WriteLnToConsole("The above events occured game Time: " .. GameTime .. "; luaTicks: " .. luaGameTicks)
+		--nw WriteLnToConsole("ProjectileTrack() finished successfully")
+
+	end
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/The_Specialists.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/The_Specialists.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,291 @@
+----------------------------------
+-- THE SPECIALISTS MODE 0.7
+-- by mikade
+----------------------------------
+
+-- version history
+-----------------
+-- version 0.1
+-----------------
+-- concept test
+
+----------------
+-- version 0.2
+----------------
+-- added gfRandomOrder to gameflags
+-- removed some deprecated variables/methods
+-- fixed lack of portal reset
+
+----------------
+-- version 0.3
+----------------
+-- added switching on start
+-- removed switch from engineer weaponset
+
+----------------
+-- version 0.4
+----------------
+-- Attempted to:
+-- fix potential switch explit
+-- improve user feedback on start
+
+----------------
+-- version 0.5
+----------------
+-- provision for variable minetimer / demo mines set to 5000ms
+-- don't autoswitch if player only has 1 hog on his team
+
+----------------
+-- version 0.6
+----------------
+-- for the meanwhile, don't drop any crates except health crates
+
+----------------
+-- version 0.7
+----------------
+-- perhogadmsdf :D :D :D :D
+
+--------------------
+--TO DO
+--------------------
+
+-- balance hog health, maybe
+-- add proper gameflag checking, maybe (so that we can throw in a .cfg and let the users break everything)
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+local numhhs = 0
+local hhs = {}
+
+local currName
+local lastName
+local started = false
+local switchStage = 0
+
+local hogCounter
+
+function CountHog(gear)
+	hogCounter = hogCounter +1
+end
+
+function onNewAmmoStore(groupIndex, hogIndex)
+
+	SetAmmo(amSkip, 9, 0, 0, 0)
+
+	if hogIndex == 0 then
+		SetAmmo(amBazooka, 1, 0, 0, 0)
+		SetAmmo(amGrenade, 1, 0, 0, 0)
+		SetAmmo(amShotgun, 1, 0, 0, 0)
+	elseif hogIndex == 1 then
+		SetAmmo(amGirder, 2, 0, 0, 0)
+		SetAmmo(amBlowTorch, 1, 0, 0, 0)
+		SetAmmo(amPickHammer, 1, 0, 0, 0)
+	elseif hogIndex == 2 then
+		SetAmmo(amRope, 9, 0, 0, 0)
+		SetAmmo(amParachute, 9, 0, 0, 0)
+		SetAmmo(amFirePunch, 1, 0, 0, 0)
+	elseif hogIndex == 3 then
+		SetAmmo(amDynamite, 1, 0, 0, 0)
+		SetAmmo(amMine, 1, 0, 0, 0)
+		SetAmmo(amDrill, 1, 0, 0, 0)
+	elseif hogIndex == 4 then
+		SetAmmo(amSniperRifle, 1, 0, 0, 0)
+		SetAmmo(amDEagle, 1, 0, 0, 0)
+		SetAmmo(amPortalGun, 2, 0, 0, 0)
+	elseif hogIndex == 5 then
+		SetAmmo(amSeduction, 9, 0, 0, 0)
+		SetAmmo(amResurrector, 1, 0, 0, 0)
+		SetAmmo(amInvulnerable, 1, 0, 0, 0)
+	elseif hogIndex == 6 then
+		SetAmmo(amFlamethrower, 1, 0, 0, 0)
+		SetAmmo(amMolotov, 1, 0, 0, 0)
+		SetAmmo(amNapalm, 1, 0, 0, 0)
+	elseif hogIndex == 7 then
+		SetAmmo(amBaseballBat, 1, 0, 0, 0)
+		SetAmmo(amGasBomb, 1, 0, 0, 0)
+		SetAmmo(amKamikaze, 1, 0, 0, 0)
+	end
+
+end
+
+function CreateTeam()
+
+	currTeam = ""
+	lastTeam = ""
+	z = 0
+
+	for i = 0, (numhhs-1) do
+
+			currTeam = GetHogTeamName(hhs[i])
+
+			if currTeam == lastTeam then
+					z = z + 1
+			else
+					z = 1
+			end
+
+			if z == 1 then
+
+					SetHogName(hhs[i],"Soldier")
+					SetHogHat(hhs[i], "sf_vega")
+					SetHealth(hhs[i],200)
+
+			elseif z == 2 then
+
+					SetHogHat(hhs[i], "Glasses")
+					SetHogName(hhs[i],"Engineer")
+
+			elseif z == 3 then
+
+					SetHogName(hhs[i],"Ninja")
+					SetHogHat(hhs[i], "NinjaFull")
+					SetHealth(hhs[i],80)
+
+			elseif z == 4 then
+
+					SetHogName(hhs[i],"Demo")
+					SetHogHat(hhs[i], "Skull")
+					SetHealth(hhs[i],200)
+
+			elseif z == 5 then
+
+					SetHogName(hhs[i],"Sniper")
+					SetHogHat(hhs[i], "Sniper")
+					SetHealth(hhs[i],120)
+
+			elseif z == 6 then
+
+					SetHogName(hhs[i],"Saint")
+					SetHogHat(hhs[i], "angel")
+					SetHealth(hhs[i],300)
+
+			elseif z == 7 then
+
+					SetHogName(hhs[i],"Pyro")
+					SetHogHat(hhs[i], "Gasmask")
+					SetHealth(hhs[i],150)
+
+			elseif z == 8 then
+
+					SetHogName(hhs[i],"Loon")
+					SetHogHat(hhs[i], "clown")
+					SetHealth(hhs[i],100)
+
+			end
+
+			lastTeam = GetHogTeamName(hhs[i])
+
+	end
+
+end
+
+function onGameInit()
+	GameFlags = gfRandomOrder + gfResetWeps + gfInfAttack + gfPlaceHog +gfPerHogAmmo
+	Delay = 10
+	HealthCaseProb = 100
+end
+
+function onGameStart()
+
+	CreateTeam()
+
+	ShowMission     (
+                                loc("THE SPECIALISTS"),
+                                loc("a Hedgewars mini-game"),
+
+                                loc("Eliminate the enemy specialists.") .. "|" ..
+                                " " .. "|" ..
+
+                                loc("Game Modifiers: ") .. "|" ..
+                                loc("Per-Hog Ammo") .. "|" ..
+                                loc("Weapons Reset") .. "|" ..
+                                loc("Unlimited Attacks") .. "|" ..
+
+                                "", 4, 4000
+                                )
+
+	trackTeams()
+
+end
+
+
+function onNewTurn()
+	currName = GetHogName(CurrentHedgehog)
+	lastName = GetHogName(CurrentHedgehog)
+	started = true
+	switchStage = 0
+end
+
+function onGameTick20()
+
+	if (CurrentHedgehog ~= nil) then
+
+		currName = GetHogName(CurrentHedgehog)
+
+		if (currName ~= lastName) and (switchStage > 5) then
+			AddCaption(loc("Switched to ") .. currName .. "!")
+		end
+
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) and (switchStage < 5) then
+
+			AddCaption(loc("Prepare yourself") .. ", " .. currName .. "!")
+
+			hogCounter = 0
+			runOnHogsInTeam(CountHog, GetHogTeamName(CurrentHedgehog) )
+
+			if hogCounter > 1 then
+
+				switchStage = switchStage + 1
+
+				if switchStage == 1 then
+					AddAmmo(CurrentHedgehog, amSwitch, 1)
+
+				elseif switchStage == 2 then
+					ParseCommand("setweap " .. string.char(amSwitch))
+				elseif switchStage == 3 then
+					SetGearMessage(CurrentHedgehog,gmAttack)
+				elseif switchStage == 4 then
+					switchStage = 6
+					AddAmmo(CurrentHedgehog, amSwitch, 0)
+				end
+
+			else
+				switchStage = 6
+			end
+
+
+		end
+
+		lastName = currName
+
+	end
+
+end
+
+function onGearAdd(gear)
+
+    if GetGearType(gear) == gtHedgehog then
+		hhs[numhhs] = gear
+		numhhs = numhhs + 1
+	elseif (GetGearType(gear) == gtMine) and (started == true) then
+		SetTimer(gear,5000)
+	end
+
+	if (GetGearType(gear) == gtHedgehog) or (GetGearType(gear) == gtResurrector) then
+		trackGear(gear)
+	end
+
+
+end
+
+function onGearDelete(gear)
+	if (GetGearType(gear) == gtHedgehog) or (GetGearType(gear) == gtResurrector) then
+		trackDeletion(gear)
+	end
+end
+
+function onAmmoStoreInit()
+--
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Tumbler.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Default
+Default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/Tumbler.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,786 @@
+------------------------------------
+-- TUMBLER
+-- v.0.7.1
+------------------------------------
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+
+local fMod = 1000000 -- use this for dev and .16+ games
+
+local leftOn = false
+local rightOn = false
+local upOn = false
+local downOn = false
+local preciseOn = false
+
+local wep = {}
+local wepAmmo = {}
+local wepCol = {}
+local wepIndex = 0
+local wepCount = 0
+local fGears = 0
+
+local mineSpawn
+local barrelSpawn
+
+local roundKills = 0
+local barrelsEaten = 0
+local minesEaten = 0
+
+local moveTimer = 0
+local fireTimer = 0
+local TimeLeftCounter = 0
+local TimeLeft = 0
+local stopMovement = false
+local tumbleStarted = false
+
+local vTag = {}
+
+------------------------
+-- version 0.4
+------------------------
+
+-- removed some old code/comments
+-- removed both shell and mortar as the primary and secondary weapons
+-- the primary weapon is now an explosive(barrel)
+
+-- added support for picking up barrels scattered about the map (backspace)
+-- added support for dragging around mines (enter toggles on/off)
+-- added support for primary fire being onAttackUp
+-- added a trail to indicate when the player has 5s or less left to tumble
+-- updated showmission to reflect changed controls and options
+
+------------------------
+-- version 0.5
+------------------------
+
+-- changed some of the user feedback
+-- i can't remember??
+-- substituted onAttackUp for onPrecise()
+-- brought in line with new velocity changes
+
+------------------------
+-- version 0.6
+------------------------
+
+-- reduced starting "ammo"
+-- randomly spawn new barrels/mines on new turn
+-- updated user feedback
+-- better locs and coloured addcaptions
+-- added tag for turntime
+-- removed tractor beam
+-- added two new weapons and changed ammo handling
+-- health crates now give tumbler time, and wep/utility give flamer ammo
+-- explosives AND mines can be picked up to increase their relative ammo
+-- replaced "no weapon" selected message that hw serves
+-- modified crate frequencies a bit
+-- added some simple kill-based achievements, i think
+
+------------------------
+-- version 0.7
+------------------------
+
+-- a few code optimisations/performance tweaks
+-- removed some deprecated code
+-- fix a potential spawn bug
+
+-- improved HUD (now shows ammo counts)
+-- improved user feedback (less generic messages)
+-- colour-coded addcaptions to match hud :)
+
+-- base tumbling time now equals scheme turntime
+-- tumbling time extension is now based on the amount of health contained in crate
+-- new mines per turn based on minesnum
+-- new barrels per turn based on explosives
+
+-- added 2 more achievements: barrel eater and mine eater (like kills, don't do anything atm)
+-- slightly increased grab distance for explosives/mines
+-- slightly increased flamer velocity
+-- slightly decreased flamer volume
+-- added a flame vaporiser (based on number of flame gears?)
+-- give tumblers an extra 47 health on the start of their tumble to counter the grenade (exp)
+-- refocus camera on tumbler on newturn (not on crates, barrels etc)
+-- increase delay: yes, yes, eat your hearts out
+
+-- commit log
+-- Better HUD
+-- Allow more user customization
+-- Bugfix for new gear spawns
+-- Performance tweaks
+-- Variety of small gameplay changes
+
+------------------------
+-- version 0.7.1
+------------------------
+
+-- redraw HUD on screen resolution change
+
+---------------------------
+-- some other ideas/things
+---------------------------
+--[[
+-- add better gameflag handling
+-- fix flamer "shots remaining" message on start or choose a standard versus %
+-- add more sounds
+-- better barrel/minespawn effects
+-- separate grab distance for mines/barrels
+-- [probably not] make barrels always explode?
+-- [probably not] persistent ammo?
+-- [probably not] dont hurt tumblers and restore their health at turn end?
+]]
+
+
+----------------------------------------------------------------
+----------------------------------------------------------------
+
+local flames = {}
+local fGearValues = {}
+
+function runOnflames(func)
+    for k, gear in ipairs(flames) do
+        func(gear)
+    end
+end
+
+function trackFGear(gear)
+    table.insert(flames, gear)
+end
+
+function trackFGearDeletion(gear)
+    fGearValues[gear] = nil
+    for k, g in ipairs(flames) do
+        if g == gear then
+            table.remove(flames, k)
+            break
+        end
+    end
+end
+
+function getFGearValue(gear, key)
+    if fGearValues[gear] ~= nil then
+        return fGearValues[gear][key]
+    end
+    return nil
+end
+
+function setFGearValue(gear, key, value)
+    found = false
+    for id, values in pairs(fGearValues) do
+        if id == gear then
+            values[key] = value
+            found = true
+        end
+    end
+    if not found then
+        fGearValues[gear] = { [key] = value }
+    end
+end
+
+function decreaseFGearValue(gear, key)
+    for id, values in pairs(fGearValues) do
+        if id == gear then
+            values[key] = values[key] - 1
+        end
+    end
+end
+
+function HandleLife(gear)
+
+	decreaseFGearValue(gear, "L")
+	if getFGearValue(gear, "L") == 0 then
+		AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, false)
+		DeleteGear(gear)
+	end
+
+end
+
+----------------------------------------------------------------
+----------------------------------------------------------------
+
+function HideTags()
+
+	for i = 0, 3 do
+		SetVisualGearValues(vTag[i],0,0,0,0,0,1,0, 0, 240000, 0xffffff00)
+	end
+
+end
+
+function DrawTag(i)
+
+	zoomL = 1.3
+
+	xOffset = 40
+
+	if i == 0 then
+		yOffset = 40
+		tCol = 0xffba00ff --0xffed09ff --0xffba00ff
+		tValue = TimeLeft
+	elseif i == 1 then
+		zoomL = 1.1
+		yOffset = 70
+		tCol = wepCol[0]
+		tValue = wepAmmo[0]
+	elseif i == 2 then
+		zoomL = 1.1
+		xOffset = 40 + 35
+		yOffset = 70
+		tCol = wepCol[1]
+		tValue = wepAmmo[1]
+	elseif i == 3 then
+		zoomL = 1.1
+		xOffset = 40 + 70
+		yOffset = 70
+		tCol = wepCol[2]
+		tValue = wepAmmo[2]
+	end
+
+	DeleteVisualGear(vTag[i])
+	vTag[i] = AddVisualGear(0, 0, vgtHealthTag, 0, false)
+	g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(vTag[i])
+	SetVisualGearValues	(
+				vTag[i], 		--id
+				-(ScreenWidth/2) + xOffset,	--xoffset
+				ScreenHeight - yOffset, --yoffset
+				0, 			--dx
+				0, 			--dy
+				zoomL, 			--zoom
+				1, 			--~= 0 means align to screen
+				g7, 			--frameticks
+				tValue, 		--value
+				240000, 		--timer
+				tCol		--GetClanColor( GetHogClan(CurrentHedgehog) )
+				)
+
+end
+
+function GetGearDistance(gear)
+
+	g1X, g1Y = GetGearPosition(gear)
+	g2X, g2Y = GetGearPosition(CurrentHedgehog)
+
+	q = g1X - g2X
+	w = g1Y - g2Y
+	return( (q*q) + (w*w) )
+
+end
+
+-- add to your ammo ***WHEN YOU PUSH A KEY*** near them
+-- yes that was my justification for a non generic method
+function CheckProximityToExplosives(gear)
+
+	if (GetGearDistance(gear) < 1400) then
+
+		if (GetGearType(gear) == gtExplosives) then
+
+			wepAmmo[0] = wepAmmo[0] + 1
+			PlaySound(sndShotgunReload)
+			DeleteGear(gear)
+			AddCaption(wep[0] .. " " .. loc("ammo extended!"), wepCol[0], capgrpAmmoinfo )
+			DrawTag(1)
+
+			barrelsEaten = barrelsEaten + 1
+			if barrelsEaten == 5 then
+				AddCaption(loc("Achievement Unlocked") .. ": " .. loc("Barrel Eater!"),0xffba00ff,capgrpMessage2)
+			end
+
+		elseif (GetGearType(gear) == gtMine) then
+			wepAmmo[1] = wepAmmo[1] + 1
+			PlaySound(sndShotgunReload)
+			DeleteGear(gear)
+			AddCaption(wep[1] .. " " .. loc("ammo extended!"), wepCol[1], capgrpAmmoinfo )
+			DrawTag(2)
+
+			minesEaten = minesEaten + 1
+			if minesEaten == 5 then
+				AddCaption(loc("Achievement Unlocked") .. ": " .. loc("Mine Eater!"),0xffba00ff,capgrpMessage2)
+			end
+
+		end
+
+	else
+		--AddCaption("There is nothing here...")
+	end
+
+end
+
+-- check proximity on crates
+function CheckProximity(gear)
+
+	dist = GetGearDistance(gear)
+
+	if (dist < 1600) and (GetGearType(gear) == gtCase) then
+
+		if GetHealth(gear) > 0 then
+
+			AddCaption(loc("Tumbling Time Extended!"), 0xffba00ff, capgrpMessage2 )
+
+			TimeLeft = TimeLeft + HealthCaseAmount  --5 --5s
+			DrawTag(0)
+			--PlaySound(sndShotgunReload)
+		else
+			wepAmmo[2] = wepAmmo[2] + 800
+			PlaySound(sndShotgunReload)
+			AddCaption(wep[2] .. " " .. loc("fuel extended!"), wepCol[2], capgrpAmmoinfo )
+			DrawTag(3)
+		end
+
+		DeleteGear(gear)
+
+	end
+
+end
+
+function ChangeWeapon()
+
+	wepIndex = wepIndex + 1
+	if wepIndex == wepCount then
+		wepIndex = 0
+	end
+
+	AddCaption(wep[wepIndex] .. " " .. loc("selected!"), wepCol[wepIndex],capgrpAmmoinfo )
+	AddCaption(wepAmmo[wepIndex] .. " " .. loc("shots remaining."), wepCol[wepIndex],capgrpMessage2)
+
+end
+
+---------------
+-- action keys
+---------------
+
+function onPrecise()
+
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) and (wepAmmo[wepIndex] > 0) then
+
+		wepAmmo[wepIndex] = wepAmmo[wepIndex] - 1
+		AddCaption(wepAmmo[wepIndex] .. " " .. loc("shots remaining."), wepCol[wepIndex],capgrpMessage2)
+
+		if wep[wepIndex] == loc("Barrel Launcher") then
+			morte = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtExplosives, 0, 0, 0, 1)
+			CopyPV(CurrentHedgehog, morte) -- new addition
+			x,y = GetGearVelocity(morte)
+			x = x*2
+			y = y*2
+			SetGearVelocity(morte, x, y)
+			DrawTag(1)
+
+		elseif wep[wepIndex] == loc("Mine Deployer") then
+			morte = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtMine, 0, 0, 0, 0)
+			SetTimer(morte, 1000)
+			DrawTag(2)
+		end
+
+	end
+
+	preciseOn = true
+
+end
+
+function onPreciseUp()
+	preciseOn = false
+end
+
+function onHJump()
+	-- pick up explosives/mines if nearby them
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) and (tumbleStarted == true) then
+		runOnGears(CheckProximityToExplosives)
+	end
+end
+
+function onLJump()
+	ChangeWeapon()
+end
+
+-----------------
+-- movement keys
+-----------------
+
+function onLeft()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		leftOn = true
+	end
+end
+
+function onRight()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		rightOn = true
+	end
+end
+
+function onUp()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		upOn = true
+	end
+end
+
+function onDown()
+	if (CurrentHedgehog ~= nil) and (stopMovement == false) then
+		downOn = true
+	end
+end
+
+function onDownUp()
+	downOn = false
+end
+function onUpUp()
+	upOn = false
+end
+function onLeftUp()
+	leftOn = false
+end
+function onRightUp()
+	rightOn = false
+end
+
+--------------------------
+-- other event handlers
+--------------------------
+
+function onGameInit()
+	CaseFreq = 0
+	HealthCaseProb = 0
+	Delay = 1000
+
+	mineSpawn = MinesNum
+	if mineSpawn > 4 then
+		mineSpawn = 4
+	end
+
+	barrelSpawn = Explosives
+	if barrelSpawn > 4 then
+		barrelSpawn = 4
+	end
+
+	--MinesNum = 0
+	--Explosives = 0
+
+	for i = 0, 3 do
+		vTag[0] = AddVisualGear(0, 0, vgtHealthTag, 0, false)
+	end
+
+	HideTags()
+
+	wep[0] = loc("Barrel Launcher")
+	wep[1] = loc("Mine Deployer")
+	wep[2] = loc("Flamer")
+
+	wepCol[0] = 0x78818eff
+	wepCol[1] = 0xa12a77ff
+	wepCol[2] = 0xf49318ff
+
+	wepCount = 3
+
+end
+
+function onGameStart()
+
+	ShowMission	(
+			"TUMBLER",
+			loc("a Hedgewars mini-game"),
+			loc("Eliminate the enemy hogs to win.") .. "|" ..
+			" " .. "|" ..
+
+			loc("New Mines Per Turn") .. ": " .. (mineSpawn) .. "|" ..
+			loc("New Barrels Per Turn") .. ": " .. (barrelSpawn) .. "|" ..
+			loc("Time Extension") .. ": " .. (HealthCaseAmount) .. loc("sec") .. "|" ..
+			" " .. "|" ..
+
+			loc("Movement: [Up], [Down], [Left], [Right]") .. "|" ..
+			loc("Fire") .. ": " .. loc("[Left Shift]") .. "|" ..
+			loc("Change Weapon") .. ": " .. loc("[Enter]") .. "|" ..
+			loc("Grab Mines/Explosives") .. ": " .. loc("[Backspace]") .. "|" ..
+
+			" " .. "|" ..
+
+			loc("Health crates extend your time.") .. "|" ..
+			loc("Ammo is reset at the end of your turn.") .. "|" ..
+
+			"", 4, 4000
+			)
+
+end
+
+function onScreenResize()
+
+	-- redraw Tags so that their screen locations are updated
+	if (CurrentHedgehog ~= nil) and (tumbleStarted == true) then
+		for i = 0, 3 do
+			DrawTag(i)
+		end
+	end
+
+end
+
+function onNewTurn()
+
+	stopMovement = false
+	tumbleStarted = false
+
+	-- randomly create new barrels mines on the map every turn (can be disabled by setting mine/barrels to 0 in scheme)
+	for i = 0, barrelSpawn-1 do
+		gear = AddGear(100, 100, gtExplosives, 0, 0, 0, 0)
+		SetHealth(gear, 100)
+		if FindPlace(gear, false, 0, LAND_WIDTH, false) ~= nil then
+			tempE = AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+		end
+	end
+	for i = 0, mineSpawn-1 do
+		gear = AddGear(100, 100, gtMine, 0, 0, 0, 0)
+		if FindPlace(gear, false, 0, LAND_WIDTH, false) ~= nil then
+			tempE = AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+		end
+	end
+
+	-- randomly spawn time extension crates / flamer fuel on the map
+	r = GetRandom(100)
+	if r > 50 then
+		gear = SpawnHealthCrate(0, 0)
+	end
+	r = GetRandom(100)
+	if r > 70 then
+		gear = SpawnAmmoCrate(0, 0, amSkip)
+	end
+
+	HideTags()
+
+	--reset ammo counts
+	wepAmmo[0] = 2
+	wepAmmo[1] = 1
+	wepAmmo[2] = 50 -- 50000 -- 50
+	wepIndex = 2
+	ChangeWeapon()
+
+	roundKills = 0
+	barrelsEaten = 0
+	minesEaten = 0
+
+	FollowGear(CurrentHedgehog)
+
+end
+
+
+function DisableTumbler()
+	stopMovement = true
+	upOn = false
+	down = false
+	leftOn = false
+	rightOn = false
+	HideTags()
+end
+
+function onGameTick()
+
+	-- start the player tumbling with a boom once their turn has actually begun
+	if tumbleStarted == false then
+		if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
+			--AddCaption(loc("Good to go!"))
+			tumbleStarted = true
+			TimeLeft = (TurnTime/1000)
+			AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+			SetHealth(CurrentHedgehog, GetHealth(CurrentHedgehog) + 47) -- new
+			for i = 0, 3 do
+				DrawTag(i)
+			end
+		end
+	end
+
+	if (CurrentHedgehog ~= nil) and (tumbleStarted == true) then
+
+		runOnGears(CheckProximity) -- crates
+
+		-- Calculate and display turn time
+		TimeLeftCounter = TimeLeftCounter + 1
+		if TimeLeftCounter == 1000 then
+			TimeLeftCounter = 0
+			TimeLeft = TimeLeft - 1
+
+			if TimeLeft >= 0 then
+				DrawTag(0)
+			end
+
+		end
+
+		if TimeLeft == 0 then
+			DisableTumbler()
+		end
+
+		-- handle movement based on IO
+		moveTimer = moveTimer + 1
+		if moveTimer == 100 then -- 100
+			moveTimer = 0
+
+			runOnflames(HandleLife)
+
+			---------------
+			-- new trail code
+			---------------
+			-- the trail lets you know you have 5s left to pilot, akin to birdy feathers
+			if (TimeLeft <= 5) and (TimeLeft > 0) then
+				tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmoke, 0, false)
+				g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+				SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, GetClanColor(GetHogClan(CurrentHedgehog)) )
+			end
+			--------------
+
+			dx, dy = GetGearVelocity(CurrentHedgehog)
+
+			dxlimit = 0.4*fMod
+			dylimit = 0.4*fMod
+
+			if dx > dxlimit then
+				dx = dxlimit
+			end
+			if dy > dylimit then
+				dy = dylimit
+			end
+			if dx < -dxlimit then
+				dx = -dxlimit
+			end
+			if dy < -dylimit then
+				dy = -dylimit
+			end
+
+
+			if leftOn == true then
+				dx = dx - 0.1*fMod
+			end
+			if rightOn == true then
+				dx = dx + 0.1*fMod
+			end
+
+			if upOn == true then
+				dy = dy - 0.1*fMod
+			end
+			if downOn == true then
+				dy = dy + 0.1*fMod
+			end
+
+			SetGearVelocity(CurrentHedgehog, dx, dy)
+
+		end
+
+		--
+		--flamer
+		--
+		fireTimer = fireTimer + 1
+		if fireTimer == 6 then	-- 5 --10
+			fireTimer = 0
+
+			if (wep[wepIndex] == loc("Flamer") ) and (preciseOn == true) and (wepAmmo[wepIndex] > 0) and (stopMovement == false) and (tumbleStarted == true) then
+
+				wepAmmo[wepIndex] = wepAmmo[wepIndex] - 1
+				AddCaption(
+						loc("Flamer") .. ": " ..
+						(wepAmmo[wepIndex]/800*100) - (wepAmmo[wepIndex]/800*100)%2 .. "%",
+						wepCol[2],
+						capgrpMessage2
+						)
+				DrawTag(3)
+
+				dx, dy = GetGearVelocity(CurrentHedgehog)
+				shell = AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtFlame, 0, 0, 0, 0)
+
+				xdev = 1 + GetRandom(25)	--15
+				xdev = xdev / 100
+
+				r = GetRandom(2)
+				if r == 1 then
+					xdev = xdev*-1
+				end
+
+				ydev = 1 + GetRandom(25)	--15
+				ydev = ydev / 100
+
+				r = GetRandom(2)
+				if r == 1 then
+					ydev = ydev*-1
+				end
+
+				--*13	--8	*-4
+				SetGearVelocity(shell, (dx*4.5)+(xdev*fMod), (dy*4.5)+(ydev*fMod))	--10
+
+			end
+
+		end
+		--
+
+	end
+
+
+end
+
+function isATrackedGear(gear)
+	if 	(GetGearType(gear) == gtExplosives) or
+		(GetGearType(gear) == gtMine) or
+		(GetGearType(gear) == gtCase)
+	then
+		return(true)
+	else
+		return(false)
+	end
+end
+
+--[[function onGearDamage(gear, damage)
+	if gear == CurrentHedgehog then
+		-- You are now tumbling
+	end
+end]]
+
+function onGearAdd(gear)
+
+	if GetGearType(gear) == gtFlame then
+
+		trackFGear(gear)
+
+		fGears = fGears +1
+
+		if fGears < 80 then
+			setFGearValue(gear,"L",30)
+		else
+			setFGearValue(gear,"L",5) --3
+		end
+
+	elseif isATrackedGear(gear) then
+		trackGear(gear)
+	end
+
+end
+
+function onGearDelete(gear)
+
+	if GetGearType(gear) == gtFlame then
+		trackFGearDeletion(gear)
+		fGears = fGears -1
+
+	elseif isATrackedGear(gear) then
+		trackDeletion(gear)
+
+	-- achievements? prototype
+	elseif GetGearType(gear) == gtHedgehog then
+
+		if GetHogTeamName(gear) ~= GetHogTeamName(CurrentHedgehog) then
+
+			roundKills = roundKills + 1
+			if roundKills == 2 then
+				AddCaption(loc("Double Kill!"),0xffba00ff,capgrpMessage2)
+			elseif roundKills == 3 then
+				AddCaption(loc("Killing spree!"),0xffba00ff,capgrpMessage2)
+			elseif roundKills >= 4 then
+				AddCaption(loc("Unstoppable!"),0xffba00ff,capgrpMessage2)
+			end
+
+		elseif gear == CurrentHedgehog then
+			DisableTumbler()
+
+		elseif gear ~= CurrentHedgehog then
+			AddCaption(loc("Friendly Fire!"),0xffba00ff,capgrpMessage2)
+		end
+
+	end
+
+	if CurrentHedgehog ~= nil then
+		FollowGear(CurrentHedgehog)
+	end
+
+end
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/WxW.cfg	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+Shoppa
+Shoppa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Multiplayer/WxW.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,751 @@
+
+----------------------
+-- WALL TO WALL 0.4
+----------------------
+-- a shoppa minigame
+-- by mikade
+
+-- feel free to add map specific walls to LoadConfig, or post additional
+-- wall suggestions on our forum at: http://www.hedgewars.org/forum
+
+----------------
+--0.1
+----------------
+-- concept test
+
+----------------
+--0.2
+----------------
+-- unhardcoded turntimeleft, now uses shoppa default of 45s
+-- changed some things behind the scenes
+-- fixed oooooold radar bug
+-- added radar / script support for multiple crates
+-- tweaked weapons tables
+-- added surfing and changed crate spawn requirements a bit
+
+----------------
+--0.3
+----------------
+-- stuffed dirty clothes into cupboard
+-- improved user feedback
+-- added/improved experimental config system, input masks included :D
+
+----------------
+--0.4
+----------------
+-- for version 0.9.18, now detects border in correct location
+-- fix 0.3 config constraint
+-- remove unnecessary vars
+-- oops, remove hardcoding of minesnum,explosives
+-- ... and unhardcode turntime (again)... man, 30s is hard :(
+-- move some initialisations around
+-- numerous improvements to user feedback
+-- walls disappear after being touched
+-- added backwards compatibility with 0.9.17
+
+----------------
+--TO DO
+----------------
+-- achievements / try detect shoppa moves? :|
+-- maybe add ability for the user to place zones like in Racer?
+-- add more hard-coded values for specific maps
+
+-----------------------------
+-- GO PONIES, GO PONIES, GO!
+-----------------------------
+
+loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+loadfile(GetDataPath() .. "Scripts/Utils.lua")()
+
+-- experimental menu stuff
+local menuIndex = 1
+local menu = {}
+local preMenuCfg
+local postMenuCfg
+local roundN = 0
+
+-- config and wall variables
+local AFR = false
+local allowCrazyWeps = false
+local requireSurfer = true
+local wX = {}
+local wY = {}
+local wWidth = {}
+local wHeight = {}
+local wTouched = {}
+--local margin
+local wallsLeft = 0
+
+local highestY = 0
+local surferTimer = 0
+local hasSurfed = false
+local allWallsHit = false
+
+local gTimer = 1
+local effectTimer = 1
+
+local ropeG = nil
+local crateG = nil
+local allowCrate = true
+
+-- crate radar vars
+local rCirc = {}
+local rAlpha = 255
+local rPingTimer = 0
+local m2Count = 0
+
+local weapons = {}
+
+--[[local unlisted = {amTardis, amLandGun,amExtraTime,amExtraDamage,
+				amVampiric, amSwitch, amInvulnerable, amGirder, amJetpack,
+				amPortalGun, amTeleport, amResurrector, amLaserSight, amLowGravity,
+				amAirAttack, amNapalm, amMineStrike, amDrillStrike,
+				amKamikaze, amSnowball, amSeduction}]]
+
+local crazyWeps = {amWatermelon, amHellishBomb, amBallgun, amRCPlane}
+
+local groundWeps = 	{amBee, amShotgun,amDEagle,amFirePunch, amWhip,
+				amPickHammer, amBaseballBat, amCake,amBallgun,
+				amRCPlane, amSniperRifle, amBirdy, amBlowTorch, amGasBomb,
+				amFlamethrower, amSMine, amMortar, amHammer}
+
+local ropeWeps = {amGrenade, amClusterBomb, amBazooka, amMine, amDynamite,
+				amWatermelon, amHellishBomb, amDrill, amMolotov}
+
+-- 0.9.18+ extra custom data for preset maps
+local MapList =
+	{
+	--name,      						surfer, roof, 	LRwalls
+	{"Atlantis Shoppa", 			    true, 	false, true},
+	{"BambooPlinko", 				    true,	false, true},
+	{"BrickShoppa", 				    false, 	false, true},
+	{"BubbleFlow",   					true, 	false, true},
+	{"Cave",       						false, 	false, true},
+	{"Glass Shoppa",      				true, 	false, true},
+	{"HardIce",      					false, 	false, true},
+	{"Industrial",       				false,	false, true},
+	{"Islands",       					true, 	false, true},
+	{"Hedgelove",       				true, 	false, true},
+	{"NeonStyle",       				false, 	false, true},
+	{"Octorama",       					false, 	false, true},
+	{"red vs blue - Castle",     		true, 	false, true},
+	{"red vs blue - castle2",     		true, 	false, true},
+	{"red vs blue - True Shoppa Sky",   true, 	false, true},
+	{"Ropes",       					false, 	false, true},
+	{"Ropes Rearranged",      			false, 	false, true},
+	{"RopesRevenge Flipped",    		true, 	false, true},
+	{"Ropes Three",      				false, 	false, true},
+	{"RopesTwo",      					false, 	false, true},
+	{"ShapeShoppa1.0",     				true, 	false, true},
+	{"ShappeShoppa Darkhow",      		true, 	false, true},
+	{"ShoppaCave2",      				true, 	false, true},
+	{"ShoppaFun",      					true, 	false, true},
+	{"ShoppaGolf",      				false, 	false,  true},
+	{"ShoppaHell",      				false, 	true,  false},
+	{"ShoppaKing",       				false, 	false, false},
+	{"ShoppaNeon",       				false, 	false, true},
+	{"ShoppaSky",       				false, 	false, true},
+	{"Shoppawall",       				false, 	false, true},
+	{"SkatePark",       				false, 	false, true},
+	{"SloppyShoppa",      				false, 	false, true},
+	{"Sticks",       					true, 	false, true},
+	{"Symmetrical Ropes ",       		false, 	false, true},
+	{"Tetris",       					false, 	false, true},
+	{"TransRopes2",      				false, 	false, true},
+	{"Wildmap",      					false, 	false, true},
+	{"Winter Shoppa",      				false, 	false, true},
+	{"2Cshoppa",      					true, 	false, true}
+	}
+
+function BoolToCfgTxt(p)
+	if p == false then
+		return("Disabled")
+	else
+		return("Enabled")
+	end
+end
+
+function LoadConfig(p)
+
+	margin = 20
+	mapID = nil
+
+	-- 0.9.17
+	if Map == "CHANGE_ME" then
+		AddCaption(loc("For improved features/stability, play 0.9.18+"))
+		--AddWall(10,10,4085,margin)
+		AddWall(10,10,margin,2025)
+		AddWall(4085-margin,10,margin,2025)
+	end
+
+	--0.9.18+
+	for i = 1, #MapList do
+		if Map == MapList[i][1] then
+			mapID = i
+			--AddCaption(MapList[i][1] .. " found. reqSurf is " .. BoolToCfgTxt(MapList[i][2]))
+		end
+	end
+
+	if (p == 1) and (mapID ~= nil) then
+		requireSurfer = MapList[mapID][2]
+	end
+
+	if mapID ~= nil then
+
+		-- add a wall to the roof
+		if MapList[mapID][3] == true then
+			AddWall(LeftX+10,TopY+10,RightX-LeftX-20,margin)
+		end
+
+		-- add walls on the left and right border
+		if MapList[mapID][4] == true then
+			AddWall(LeftX+10,TopY+10,margin,WaterLine)
+			AddWall(RightX-10-margin,TopY+10,margin,WaterLine)
+		end
+
+		-- add map specific walls
+		if Map == "Ropes" then
+			AddWall(1092,934,54,262)
+			AddWall(2822,323,33,137)
+		elseif Map == "ShoppaKing" then
+			AddWall(3777,1520,50,196)
+			AddWall(1658,338,46,670)
+		elseif Map == "ShoppaHell" then
+			AddWall(2035,831,30,263)
+			AddWall(3968,1668,31,383)
+		elseif Map == "ShoppaNeon" then
+			AddWall(980,400,20,300)
+			AddWall(1940,400,20,300)
+			AddWall(3088,565,26,284)
+			AddWall(187,270,28,266)
+		end
+
+	-- if map is unrecognized, add two walls on the side borders
+	-- also, if version of hw is not 0.9.17 or lower
+	elseif Map ~= "CHANGE_ME" then
+		AddWall(LeftX+10,TopY+10,margin,WaterLine)
+		AddWall(RightX-10-margin,TopY+10,margin,WaterLine)
+	end
+
+
+end
+
+function AddWall(zXMin,zYMin, zWidth, zHeight)
+
+	table.insert(wX, zXMin)
+	table.insert(wY, zYMin)
+	table.insert(wWidth, zWidth)
+	table.insert(wHeight, zHeight)
+	table.insert(wTouched, false)
+
+end
+
+function DrawBlip(gear)
+	SetVisualGearValues(getGearValue(gear,"CIRC"), getGearValue(gear,"RX"), getGearValue(gear,"RY"), 100, 255, 1, 10, 0, 40, 3, GetClanColor(GetHogClan(CurrentHedgehog))-rAlpha)
+end
+
+function TrackRadarBlip(gear)
+
+	-- work out the distance to the target
+	g1X, g1Y = GetGearPosition(CurrentHedgehog)
+	g2X, g2Y = GetX(gear), GetY(gear)
+	q = g1X - g2X
+	w = g1Y - g2Y
+	r = math.sqrt( (q*q) + (w*w) )	--alternate
+
+	RCX = getGearValue(gear,"RX")
+	RCY = getGearValue(gear,"RY")
+
+	rCircDistance = r -- distance to circle
+
+	opp = w
+	if opp < 0 then
+		opp = opp*-1
+	end
+
+	-- work out the angle (theta) to the target
+	t = math.deg ( math.asin(opp / r) )
+
+	-- based on the radius of the radar, calculate what x/y displacement should be
+	NR = 150 -- radius at which to draw circs
+	NX = math.cos( math.rad(t) ) * NR
+	NY = math.sin( math.rad(t) ) * NR
+
+	if rCircDistance < NR then
+		RCX = g2X
+	elseif q > 0 then
+		RCX = g1X - NX
+	else
+		RCX = g1X + NX
+	end
+
+	if rCircDistance < NR then
+		RCY = g2Y
+	elseif w > 0 then
+		RCY = g1Y - NY
+	else
+		RCY = g1Y + NY
+	end
+
+	setGearValue(gear, "RX", RCX)
+	setGearValue(gear, "RY", RCY)
+
+end
+
+
+function HandleCircles()
+
+	-- enable this if you want the radar to only show for a few seconds
+	-- after you spawn the crate
+	--[[if rAlpha ~= 255 then
+
+		rPingTimer = rPingTimer + 1
+		if rPingTimer == 100 then
+			rPingTimer = 0
+
+			rAlpha = rAlpha + 5
+			if rAlpha >= 255 then
+				rAlpha = 255
+			end
+		end
+
+	end]]
+
+	runOnGears(DrawBlip)
+
+	m2Count = m2Count + 1
+	if m2Count == 25 then
+		m2Count = 0
+
+		if (CurrentHedgehog ~= nil) and (rAlpha ~= 255) then
+			runOnGears(TrackRadarBlip)
+		end
+
+	end
+
+end
+
+
+function CheckCrateConditions()
+
+	crateSpawn = true
+
+	if requireSurfer == true then
+		if hasSurfed == false then
+			crateSpawn = false
+		end
+	end
+
+	if #wTouched > 0 then
+		if allWallsHit == false then
+			crateSpawn = false
+		end
+	end
+
+	if crateSpawn == true then
+		if allowCrate == true then
+		--if (crateG == nil) and (allowCrate == true) then
+			--AddCaption("")
+			SpawnAmmoCrate(0, 0, weapons[1+GetRandom(#weapons)] )
+			rPingTimer = 0
+			rAlpha = 0
+			PlaySound(sndWarp)
+		end
+	end
+
+end
+
+function CheckSurfer()
+
+	if GetY(CurrentHedgehog) > highestY then
+		highestY = GetY(CurrentHedgehog)
+	end
+
+	if (highestY == (WaterLine-8)) and (hasSurfed == false)  then
+
+		surferTimer = surferTimer +1
+		if (surferTimer == 40) then
+			hasSurfed = true
+			AddCaption(loc("Surfer!"),0xffba00ff,capgrpMessage2)
+		end
+	end
+
+end
+
+
+
+function WallHit(id, zXMin,zYMin, zWidth, zHeight)
+
+	if wTouched[id] == false then
+		tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtBigExplosion, 0, false)
+		PlaySound(sndExplosion)
+		wallsLeft = wallsLeft - 1
+
+		if wallsLeft == 0 then
+			AddCaption(loc("All walls touched!"))
+			allWallsHit = true
+			if (requireSurfer == true) and (hasSurfed == false) then
+				AddCaption(loc("Go surf!"),0xffba00ff,capgrpMessage2)
+			end
+		else
+			AddCaption(loc("Walls Left") .. ": " .. wallsLeft)
+		end
+
+	end
+
+	wTouched[id] = true
+	tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmoke, 0, false)
+	--PlaySound(sndVaporize) -- yeah, this is just annoying as shit
+
+end
+
+function CheckForWallCollision()
+
+	for i = 1, #wTouched do
+		if gearIsInBox(CurrentHedgehog, wX[i],wY[i],wWidth[i],wHeight[i]) then
+			WallHit(i, wX[i],wY[i],wWidth[i],wHeight[i])
+		end
+	end
+
+end
+
+function BorderSpark(zXMin,zYMin, zWidth, zHeight, bCol)
+
+	eX = zXMin + GetRandom(zWidth+10)
+	eY = zYMin + GetRandom(zHeight+10)
+
+	tempE = AddVisualGear(eX, eY, vgtDust, 0, false)
+	if tempE ~= 0 then
+		g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+		SetVisualGearValues(tempE, eX, eY, g3, g4, g5, g6, g7, 1, g9, bCol )
+	end
+
+end
+
+
+function HandleBorderEffects()
+
+	effectTimer = effectTimer + 1
+	if effectTimer > 15 then --25
+
+		effectTimer = 1
+
+		for i = 1, #wTouched do
+			if wTouched[i] == true then
+				--bCol = GetClanColor(GetHogClan(CurrentHedgehog))
+			else
+				--bCol = 0xFFFFFFFF
+				bCol = GetClanColor(GetHogClan(CurrentHedgehog))
+				BorderSpark(wX[i],wY[i],wWidth[i],wHeight[i], bCol)
+			end
+			--BorderSpark(wX[i],wY[i],wWidth[i],wHeight[i], bCol)
+		end
+
+	end
+
+end
+
+function onLJump()
+	if roundN < 2 then
+		roundN = 100
+		SetInputMask(0xFFFFFFFF)
+		TurnTimeLeft = 1
+		AddCaption(loc("Configuration accepted."),0xffba00ff,capgrpMessage)
+		HideMission()
+	end
+end
+
+function onAttack()
+
+	if roundN < 2 then
+
+		if menuIndex == 1 then
+
+			if #wTouched > 0 then
+				for i = 1, #wTouched do
+					wTouched[i] = nil
+					wX[i] = nil
+					wY[i] = nil
+					wWidth[i] = nil
+					wHeight[i] = nil
+				end
+			else
+				LoadConfig(2)
+			end
+
+		elseif menuIndex == 2 then
+			requireSurfer = not(requireSurfer)
+		elseif menuIndex == 3 then
+			AFR = not(AFR)
+		elseif menuIndex == 4 then
+			allowCrazyWeps = not(allowCrazyWeps)
+		end
+
+		UpdateMenu()
+		configureWeapons()
+		HandleStartingStage()
+
+	elseif (AFR == true) then
+
+		if (GetCurAmmoType() ~= amRope) and
+			(GetCurAmmoType() ~= amSkip) and
+			(GetCurAmmoType() ~= amNothing)
+		then
+			AddCaption(loc("You may only attack from a rope!"),0xffba00ff,capgrpMessage2)
+		end
+
+	end
+
+end
+
+function onDown()
+	if roundN < 2 then
+		menuIndex = menuIndex +1
+		if menuIndex > #menu then
+			menuIndex = 1
+		end
+		HandleStartingStage()
+	end
+end
+
+function onUp()
+	if roundN < 2 then
+		menuIndex = menuIndex -1
+		if 	menuIndex == 0 then
+			menuIndex = #menu
+		end
+		HandleStartingStage()
+	end
+end
+
+function onGameInit()
+
+	GameFlags = gfRandomOrder + gfBorder + gfSolidLand --+ gfInfAttack
+	HealthCaseProb = 0
+	CaseFreq = 0
+
+end
+
+function configureWeapons()
+
+	-- reset wep array
+	for i = 1, #weapons do
+		weapons[i] = nil
+	end
+
+	-- add rope weps
+	for i, w in pairs(ropeWeps) do
+        table.insert(weapons, w)
+	end
+
+	-- add ground weps
+	for i, w in pairs(groundWeps) do
+        table.insert(weapons, w)
+	end
+
+	-- remove ground weps if attacking from rope is mandatory
+	if AFR == true then
+		for i = 1, #weapons do
+			for w = 1, #groundWeps do
+				if groundWeps[w] == weapons[i] then
+					table.remove(weapons, i)
+				end
+			end
+		end
+	end
+
+	-- remove crazy weps is crazy weps aren't allowed
+	if allowCrazyWeps == false then
+		for i = 1, #weapons do
+			for w = 1, #crazyWeps do
+				if crazyWeps[w] == weapons[i] then
+					table.remove(weapons, i)
+				end
+			end
+		end
+	end
+
+end
+
+function onGameStart()
+
+	LoadConfig(1)
+	configureWeapons()
+	UpdateMenu()
+	HandleStartingStage()
+
+end
+
+function onNewTurn()
+
+	wallsLeft = #wTouched
+
+	for i = 1, #wTouched do
+		wTouched[i] = false
+	end
+
+	allowCrate = true
+
+	surferTimer = 0
+	hasSurfed = false
+	allWallsHit = false
+	highestY = 0
+
+	crateG = nil
+
+	-- new config stuff
+	roundN = roundN + 1
+	if roundN < 2 then
+		TurnTimeLeft = -1
+		SetInputMask(0)
+		allowCrate = false
+		HandleStartingStage() -- new
+	end
+
+end
+
+function UpdateMenu()
+
+	preMenuCfg = loc("Spawn the crate, and attack!") .. "|"
+	postMenuCfg = loc("Press [Enter] to accept this configuration.")
+
+	menu = 	{
+			loc("Walls Required") .. ": " .. #wTouched .. "|",
+			loc("Surf Before Crate") .. ": " .. BoolToCfgTxt(requireSurfer) .. "|",
+			loc("Attack From Rope") .. ": " .. BoolToCfgTxt(AFR) .. "|",
+			loc("Super Weapons") .. ": " .. BoolToCfgTxt(allowCrazyWeps) .. "|"
+			}
+end
+
+function HandleStartingStage()
+
+	temp = menu[menuIndex]
+	menu[menuIndex] = "--> " .. menu[menuIndex]
+
+	missionComment = ""
+	for i = 1, #menu do
+		missionComment = missionComment .. menu[i]
+	end
+
+	ShowMission	(
+				loc("WALL TO WALL") .. " 0.4",
+				loc("a shoppa minigame"),
+				preMenuCfg..
+				missionComment ..
+				postMenuCfg ..
+				--" " .. "|" ..
+				"", 4, 300000
+				)
+
+	menu[menuIndex] = temp
+
+end
+
+function onGameTick()
+
+	if CurrentHedgehog ~= nil then
+
+		--AddCaption(Map)
+		--AddCaption(RightX ..";" .. GetX(CurrentHedgehog))
+
+		CheckSurfer()
+
+		gTimer = gTimer + 1
+		if gTimer == 25 then
+			gTimer = 1
+
+			CheckForWallCollision()
+			CheckCrateConditions()
+
+			if (crateG == GetFollowGear()) and (crateG ~= nil) then
+				FollowGear(CurrentHedgehog)
+			end
+
+			-- if attackfromrope is set, forbid firing unless using rope
+			if (AFR == true) and (roundN >= 2) then
+				if (GetCurAmmoType() == amRope) or
+					(GetCurAmmoType() == amSkip) or
+					(GetCurAmmoType() == amNothing)
+				then
+					SetInputMask(0xFFFFFFFF)
+				elseif ropeG == nil then
+					SetInputMask(bnot(gmAttack))
+				end
+			end
+
+		end
+
+		HandleBorderEffects()
+		HandleCircles()
+
+	end
+
+end
+
+function onGearAdd(gear)
+
+	if GetGearType(gear) == gtRope then
+		ropeG = gear
+	elseif GetGearType(gear) == gtCase then
+
+		crateG = gear
+		trackGear(gear)
+
+		table.insert(rCirc, AddVisualGear(0,0,vgtCircle,0,true) )
+		setGearValue(gear,"CIRC",rCirc[#rCirc])
+		setGearValue(gear,"RX",0)
+		setGearValue(gear,"RY",0)
+		SetVisualGearValues(rCirc[#rCirc], 0, 0, 100, 255, 1, 10, 0, 40, 3, 0xff00ffff)
+
+		allowCrate = false
+
+		rPingTimer = 0
+		rAlpha = 0
+
+	end
+
+end
+
+function onGearDelete(gear)
+
+	if gear == ropeG then
+		ropeG = nil
+	elseif GetGearType(gear) == gtCase then
+
+		if gear == crateG then
+			crateG = nil
+		--	rAlpha = 255
+		end
+
+		for i = 1, #rCirc do
+			if rCirc[i] == getGearValue(gear,"CIRC") then
+				DeleteVisualGear(rCirc[i])
+				table.remove(rCirc, i)
+			end
+		end
+
+		trackDeletion(gear)
+
+	end
+
+end
+
+function onAmmoStoreInit()
+
+	for i, w in pairs(ropeWeps) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+
+    for i, w in pairs(groundWeps) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+
+    for i, w in pairs(crazyWeps) do
+        SetAmmo(w, 0, 0, 0, 1)
+    end
+
+	SetAmmo(amRope, 9, 0, 0, 0)
+	SetAmmo(amSkip, 9, 0, 0, 0)
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Tracker.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,295 @@
+-- Library for keeping track of gears in the game
+-- and running functions on them
+-- also keeps track of clans and teams
+
+local trackingTeams = false
+local resurrecting = false
+local gears = {}
+local teams = {}
+local clans = {}
+local resurrectedHogs = {}
+local gearValues = {}
+local teamValues = {}
+local clanValues = {}
+
+-- Registers when a gear is added
+function trackGear(gear)
+    table.insert(gears, gear)
+    if trackingTeams and GetGearType(gear) == gtResurrector then
+        resurrecting = true
+    elseif resurrecting and GetGearType(gear) == gtHedgehog then
+        table.insert(resurrectedHogs, gear)
+    end
+end
+
+-- Registers when a gear is deleted
+function trackDeletion(gear)
+    gearValues[gear] = nil
+    for k, g in ipairs(gears) do
+        if g == gear then
+            table.remove(gears, k)
+            break
+        end
+    end
+    if trackingTeams and GetGearType(gear) == gtHedgehog then
+    	hogs = teams[GetHogTeamName(gear)]
+        if hogs ~= nil then
+            if table.maxn(hogs) == 1 then
+                hogs = nil
+            else
+				for k, hog in ipairs(hogs) do
+                    if hog == gear then
+                        table.remove(hogs, k)
+                        break
+                    end
+                end
+            end
+        end
+    elseif resurrecting and GetGearType(gear) == gtResurrector then
+        for k, gear in ipairs(resurrectedHogs) do
+            team = GetHogTeamName(gear)
+            if teams[team] == nil then
+                teams[team] = {}
+            end
+            table.insert(teams[team], gear)
+        end
+        resurrecting = false
+        resurrectedHogs = {}
+    end
+end
+
+-- Start to keep track of teams
+function trackTeams()
+    if not trackingTeams then
+        trackingTeams = true
+        for k, gear in ipairs(gears) do
+            if GetGearType(gear) == gtHedgehog then
+                team = GetHogTeamName(gear)
+                if teams[team] == nil then
+                    teams[team] = { gear }
+                    clans[team] = GetHogClan(gear)
+                else
+                    table.insert(teams[team], gear)
+                end
+            end
+        end
+    end
+end
+
+-- Registers when a hog is hidden
+function trackHiding(gear)
+    for k, g in ipairs(gears) do
+        if g == gear then
+            table.remove(gears, k)
+            break
+        end
+    end
+	
+    if trackingTeams then
+    	hogs = teams[GetHogTeamName(gear)]
+    	
+        if hogs ~= nil then
+            if table.maxn(hogs) == 1 then
+                hogs = nil
+            else
+                for k, hog in ipairs(hogs) do
+                    if hog == gear then
+                        table.remove(hogs, k)
+                        break
+                    end
+                end
+            end
+        end
+    end
+end
+
+-- Registers when a hog is restored
+function trackRestoring(gear)
+	table.insert(gears, gear)
+
+    if trackingTeams then
+        team = GetHogTeamName(gear)
+        if teams[team] == nil then
+            teams[team] = {}
+        end
+        table.insert(teams[team], gear)
+    end
+end
+
+-- Get a value for a specific gear
+function getGearValue(gear, key)
+    if gearValues[gear] ~= nil then
+        return gearValues[gear][key]
+    end
+    return nil
+end
+
+-- Set a value for a specific gear
+function setGearValue(gear, key, value)
+    found = false
+    for id, values in pairs(gearValues) do
+        if id == gear then
+            values[key] = value
+            found = true
+        end
+    end
+    if not found then
+        gearValues[gear] = { [key] = value }
+    end
+end
+
+-- Increase a value for a specific gear
+function increaseGearValue(gear, key)
+    for id, values in pairs(gearValues) do
+        if id == gear then
+            values[key] = values[key] + 1
+        end
+    end
+end
+
+-- Decrease a value for a specific gear
+function decreaseGearValue(gear, key)
+    for id, values in pairs(gearValues) do
+        if id == gear then
+            values[key] = values[key] - 1
+        end
+    end
+end
+
+-- Get a value for a specific team
+function getTeamValue(team, key)
+    if teamValues[team] ~= nil then
+        return teamValues[team][key]
+    end
+    return nil
+end
+
+-- Set a value for a specific team
+function setTeamValue(team, key, value)
+    found = false
+    for name, values in pairs(teamValues) do
+        if name == team then
+            values[key] = value
+            found = true
+        end
+    end
+    if not found then
+        teamValues[team] = { [key] = value }
+    end
+end
+
+-- Increase a value for a specific team
+function increaseTeamValue(team, key)
+    for name, values in pairs(teamValues) do
+        if name == team then
+            values[key] = values[key] + 1
+        end
+    end
+end
+
+-- Decrease a value for a specific team
+function decreaseTeamValue(team, key)
+    for name, values in pairs(teamValues) do
+        if name == team then
+            values[key] = values[key] - 1
+        end
+    end
+end
+
+-- Get a value for a specific clan
+function getClanValue(clan, key)
+    if clanValues[clan] ~= nil then
+        return clanValues[clan][key]
+    end
+    return nil
+end
+
+-- Set a value for a specific clan
+function setClanValue(clan, key, value)
+    found = false
+    for num, values in ipairs(clanValues) do
+        if num == clan then
+            values[key] = value
+            found = true
+        end
+    end
+    if not found then
+        clanValues[clan] = { [key] = value }
+    end
+end
+
+-- Increase a value for a specific clan
+function increaseClanValue(clan, key)
+    for num, values in ipairs(clanValues) do
+        if num == clan then
+            values[key] = values[key] + 1
+        end
+    end
+end
+
+-- Decrease a value for a specific clan
+function decreaseClanValue(clan, key)
+    for num, values in ipairs(clanValues) do
+        if num == clan then
+            values[key] = values[key] - 1
+        end
+    end
+end
+
+-- Run a function on all tracked gears
+function runOnGears(func)
+    for k, gear in ipairs(gears) do
+        func(gear)
+    end
+end
+
+-- Run a function on all tracked hogs
+function runOnHogs(func)
+    for k, hogs in pairs(teams) do
+        for m, hog in ipairs(hogs) do
+            func(hog)
+        end
+    end
+end
+
+-- Run a function on hogs in a team
+function runOnHogsInTeam(func, team)
+    if teams[team] ~= nil then
+        for k, hog in ipairs(teams[team]) do
+            func(hog)
+        end
+    end
+end
+
+-- Run a function on hogs in other teams
+function runOnHogsInOtherTeams(func, team)
+    for k, hogs in pairs(teams) do
+        if k ~= team then
+            for m, hog in ipairs(hogs) do
+                func(hog)
+            end
+        end
+    end
+end
+
+-- Run a function on hogs in a clan
+function runOnHogsInClan(func, clan)
+    for i = 1, table.maxn(clans) do
+        if clans[i] == clan then
+            for k, hog in ipairs(teams[i]) do
+                func(hog)
+            end
+        end
+    end
+end
+
+-- Run a function on hogs in other clans
+function runOnHogsInOtherClans(func, clan)
+    for i = 1, table.maxn(clans) do
+        if clans[i] ~= clan then
+            for k, hog in ipairs(teams[i]) do
+                func(hog)
+            end
+        end
+    end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/Data/Scripts/Utils.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,22 @@
+-- Library for miscellaneous utilitiy functions
+
+-- Check if a gear is inside a box
+function gearIsInBox(gear, x, y, w, h)
+    gx, gy = GetGearPosition(gear)
+    if gx >= x and gy >= y and gx <= x + w and gy <= y + h then
+        return true
+    end
+    return false
+end
+
+-- Check if a gear is inside a circle
+function gearIsInCircle(gear, x, y, r, useRadius)
+    gx, gy = GetGearPosition(gear)
+    if useRadius then
+        r = r + GetGearRadius(gear)
+    end
+    if r ^ 2 >= (x - gx) ^ 2 + (y - gy) ^ 2 then
+        return true
+    end
+    return false
+end
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/TARDIS.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/beep.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/beewater.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Amazing.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Brilliant.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Bugger.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Bungee.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Cutitout.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Drat.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Excellent.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Fire.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Gonnagetyou.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Grenade.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Hmm.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Justyouwait.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Leavemealone.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Ohdear.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Ouch.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Perfect.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Revenge.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Runaway.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Solong.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Thisoneismine.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Watchthis.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Whatthe.ogg has changed
Binary file project_files/Android-build/SDL-android-project/assets/Data/Sounds/voices/Classic/Whoopsee.ogg has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/assets/assetsversion.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,1 @@
+9
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/jni/Android.mk	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/jni/Android.mk	Sun Nov 18 23:10:26 2012 +0400
@@ -6,5 +6,6 @@
 
 include $(CLEAR_VARS)
 include $(JNI_DIR)/../../../../misc/Android.mk
+include $(JNI_DIR)/../../../frontlib/Android.mk
 
 
--- a/project_files/Android-build/SDL-android-project/jni/SDL/src/main/android/SDL_android_main.cpp	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/jni/SDL/src/main/android/SDL_android_main.cpp	Sun Nov 18 23:10:26 2012 +0400
@@ -27,23 +27,20 @@
     char *argv[argc];
     jstring jstringArgv[argc];
     for(int i = 0; i < argc; i++){
-        jstringArgv[i] = (jstring)env->GetObjectArrayElement(strArray, i);  //get the element
-	argv[i] = (char*)malloc(sizeof(char) * env->GetStringLength(jstringArgv[i]));
-	strcpy(argv[i], env->GetStringUTFChars(jstringArgv[i], JNI_FALSE)); //copy it to a mutable location
-	//Don't release memory the JAVA GC will take care of it
-        //env->ReleaseStringChars(jstringArgv[i], (jchar*)argv[i]);           
+		jstringArgv[i] = (jstring)env->GetObjectArrayElement(strArray, i);  //get the element
+		argv[i] = (char*)malloc(env->GetStringUTFLength(jstringArgv[i]) + 1);
+		const char *str = env->GetStringUTFChars(jstringArgv[i], NULL);
+		strcpy(argv[i], str); //copy it to a mutable location
+        env->ReleaseStringUTFChars(jstringArgv[i], str);           
     }
     
     /* Run the application code! */
-    int status;
-    status = SDL_main(argc, argv);
+    int status = SDL_main(argc, argv);
 
     //Clean up argv
     for(int i = 0; i < argc; i++){
+		free(argv[i]);
     }
-
-    /* We exit here for consistency with other platforms. */
-    //exit(status); Xeli: Or lets not crash the entire app.....
 }
 
 /* vi: set ts=4 sw=4 expandtab: */
Binary file project_files/Android-build/SDL-android-project/libs/android-support-v13.jar has changed
Binary file project_files/Android-build/SDL-android-project/libs/armeabi/libjnidispatch.so has changed
Binary file project_files/Android-build/SDL-android-project/libs/jna.jar has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-hdpi/button_local_play.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-hdpi/button_network_play.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-large-mdpi/button_local_play.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-large-mdpi/button_network_play.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/backbutton.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/button.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:state_enabled="true" android:drawable="@drawable/button_focused" />
+    <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/button_focused_disabled" />
+    <item android:state_focused="false" android:state_enabled="true" android:drawable="@drawable/button_normal" />
+    <item android:state_focused="false" android:state_enabled="false" android:drawable="@drawable/button_disabled" />
+</selector>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_focused.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_focused_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/button_normal.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown.9.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:state_enabled="true" android:drawable="@drawable/dropdown_focused" />
+    <item android:state_focused="true" android:state_enabled="false" android:drawable="@drawable/dropdown_focused_disabled" />
+    <item android:state_focused="false" android:state_enabled="true" android:drawable="@drawable/dropdown_normal" />
+    <item android:state_focused="false" android:state_enabled="false" android:drawable="@drawable/dropdown_disabled" />
+</selector>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_focused.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_focused_disabled.9.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/dropdown_normal.9.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,10 @@
+ <level-list xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:maxLevel="1" android:drawable="@drawable/hogcount1" />
+  <item android:maxLevel="2" android:drawable="@drawable/hogcount2" />
+  <item android:maxLevel="3" android:drawable="@drawable/hogcount3" />
+  <item android:maxLevel="4" android:drawable="@drawable/hogcount4" />
+  <item android:maxLevel="5" android:drawable="@drawable/hogcount5" />
+  <item android:maxLevel="6" android:drawable="@drawable/hogcount6" />
+  <item android:maxLevel="7" android:drawable="@drawable/hogcount7" />
+  <item android:maxLevel="8" android:drawable="@drawable/hogcount8" />
+ </level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount1.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount2.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount3.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount4.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount5.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount6.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount7.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount8.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/lightbulb_off.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/lightbulb_on.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/playerlist_player.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/roomlist_ingame.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/roomlist_preparing.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/savebutton.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_local_by_level.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,8 @@
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+	<item android:maxLevel="0" android:drawable="@drawable/human" />
+	<item android:maxLevel="1" android:drawable="@drawable/bot5" />
+	<item android:maxLevel="2" android:drawable="@drawable/bot4" />
+	<item android:maxLevel="3" android:drawable="@drawable/bot3" />
+	<item android:maxLevel="4" android:drawable="@drawable/bot2" />
+	<item android:maxLevel="5" android:drawable="@drawable/bot1" />
+</level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot1.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot2.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot3.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot4.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot5.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_by_level.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,8 @@
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+	<item android:maxLevel="0" android:drawable="@drawable/team_net_human" />
+	<item android:maxLevel="1" android:drawable="@drawable/team_net_bot5" />
+	<item android:maxLevel="2" android:drawable="@drawable/team_net_bot4" />
+	<item android:maxLevel="3" android:drawable="@drawable/team_net_bot3" />
+	<item android:maxLevel="4" android:drawable="@drawable/team_net_bot2" />
+	<item android:maxLevel="5" android:drawable="@drawable/team_net_bot1" />
+</level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_human.png has changed
--- a/project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
- <level-list xmlns:android="http://schemas.android.com/apk/res/android">
-  <item android:maxLevel="0" android:drawable="@drawable/teams_number0" />
-  <item android:maxLevel="1" android:drawable="@drawable/teams_number1" />
-  <item android:maxLevel="2" android:drawable="@drawable/teams_number2" />
-  <item android:maxLevel="3" android:drawable="@drawable/teams_number3" />
-  <item android:maxLevel="4" android:drawable="@drawable/teams_number4" />
-  <item android:maxLevel="5" android:drawable="@drawable/teams_number5" />
-  <item android:maxLevel="6" android:drawable="@drawable/teams_number6" />
-  <item android:maxLevel="7" android:drawable="@drawable/teams_number7" />
-  <item android:maxLevel="8" android:drawable="@drawable/teams_number8" />
-  <item android:maxLevel="9" android:drawable="@drawable/teams_number9" />
- </level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount0.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount1.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount2.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount3.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount4.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount5.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount6.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount7.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount8.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount9.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/teams_number.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,12 @@
+ <level-list xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:maxLevel="0" android:drawable="@drawable/teams_number0" />
+  <item android:maxLevel="1" android:drawable="@drawable/teams_number1" />
+  <item android:maxLevel="2" android:drawable="@drawable/teams_number2" />
+  <item android:maxLevel="3" android:drawable="@drawable/teams_number3" />
+  <item android:maxLevel="4" android:drawable="@drawable/teams_number4" />
+  <item android:maxLevel="5" android:drawable="@drawable/teams_number5" />
+  <item android:maxLevel="6" android:drawable="@drawable/teams_number6" />
+  <item android:maxLevel="7" android:drawable="@drawable/teams_number7" />
+  <item android:maxLevel="8" android:drawable="@drawable/teams_number8" />
+  <item android:maxLevel="9" android:drawable="@drawable/teams_number9" />
+ </level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-small-hdpi/button_local_play.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-small-hdpi/button_network_play.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/activity_lobby.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools"
+  	android:layout_width="fill_parent"
+	android:layout_height="fill_parent">
+	<include layout="@layout/background"/>
+
+	<LinearLayout
+	    android:layout_width="match_parent"
+	    android:layout_height="match_parent"
+	    android:orientation="vertical"
+	    android:padding="5dp" >
+	
+	    <FrameLayout
+	        android:layout_width="fill_parent"
+	        android:layout_height="0dp"
+	        android:layout_marginBottom="10dp"
+	        android:layout_weight="0.4"
+	        android:background="@drawable/box" >
+	
+	        <fragment
+	            android:id="@+id/roomListFragment"
+	            android:layout_width="fill_parent"
+	            android:layout_height="fill_parent"
+	            class="org.hedgewars.hedgeroid.RoomlistFragment"
+	            tools:layout="@layout/fragment_roomlist" />
+	    </FrameLayout>
+	
+	    <RelativeLayout
+	        android:layout_width="fill_parent"
+	        android:layout_height="0dp"
+	        android:layout_weight="0.6"
+	        android:baselineAligned="false"
+	        android:orientation="horizontal" >
+	
+	        <FrameLayout
+	            android:id="@+id/playerFrame"
+	            android:layout_width="250dp"
+	            android:layout_height="fill_parent"
+	            android:layout_alignParentRight="true"
+	            android:background="@drawable/box" >
+	
+	            <fragment
+	                android:id="@+id/playerListFragment"
+	                android:layout_width="fill_parent"
+	                android:layout_height="fill_parent"
+	                class="org.hedgewars.hedgeroid.LobbyPlayerlistFragment"
+	                tools:layout="@layout/fragment_playerlist" />
+	        </FrameLayout>
+	        
+	        <FrameLayout
+	            android:layout_width="0dp"
+	            android:layout_height="fill_parent"
+	            android:layout_alignParentLeft="true"
+	            android:layout_toLeftOf="@id/playerFrame"
+	            android:layout_marginRight="10dp"
+	            android:background="@drawable/box" >
+	
+	            <fragment
+	                android:id="@+id/chatFragment"
+	                android:layout_width="fill_parent"
+	                android:layout_height="fill_parent"
+	                class="org.hedgewars.hedgeroid.ChatFragment"
+	                tools:layout="@layout/fragment_chat" />
+	        </FrameLayout>
+	    </RelativeLayout>
+	
+	</LinearLayout>
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/activity_localroom.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="2dp" >
+
+        <LinearLayout
+            android:id="@+id/upperFrame"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:layout_marginBottom="4dp"
+            android:layout_above="@+id/startGame"
+            android:baselineAligned="false"
+            android:minHeight="200dp" >
+
+            <FrameLayout
+                android:id="@+id/mapFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/settingsFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/teamsFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/teamsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+                    tools:layout="@layout/fragment_teamlist" />
+            </FrameLayout>
+        </LinearLayout>
+
+        <Button
+            android:id="@id/startGame"
+            android:layout_width="200dp"
+            android:layout_height="67dp"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:background="@drawable/startgamebutton" />
+    </RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/activity_netroom.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:padding="2dp" >
+
+        <LinearLayout
+            android:id="@+id/upperFrame"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:layout_marginBottom="4dp"
+            android:baselineAligned="false"
+            android:minHeight="200dp" >
+            
+            <FrameLayout
+                android:id="@+id/mapFrame"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/settingsFrame"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="4dp"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+            </FrameLayout>
+
+            <FrameLayout
+                android:id="@+id/teamsFrame"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1"
+                android:background="@drawable/box" >
+
+                <fragment
+                    android:id="@+id/teamsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+                    tools:layout="@layout/fragment_teamlist" />
+            </FrameLayout>
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/playerFrame"
+            android:layout_width="200dp"
+            android:layout_height="fill_parent"
+            android:layout_above="@+id/startGame"
+            android:layout_alignParentRight="true"
+            android:layout_below="@id/upperFrame"
+            android:background="@drawable/box" >
+
+            <fragment
+                android:id="@+id/playerListFragment"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                class="org.hedgewars.hedgeroid.RoomPlayerlistFragment"
+                tools:layout="@layout/fragment_playerlist" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:layout_width="0dp"
+            android:layout_height="fill_parent"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:layout_below="@id/upperFrame"
+            android:layout_marginRight="4dp"
+            android:layout_toLeftOf="@id/playerFrame"
+            android:background="@drawable/box" >
+
+            <fragment
+                android:id="@+id/chatFragment"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                class="org.hedgewars.hedgeroid.ChatFragment"
+                tools:layout="@layout/fragment_chat" />
+        </FrameLayout>
+
+        <Button
+            android:id="@id/startGame"
+            android:layout_width="200dp"
+            android:layout_height="67dp"
+            android:layout_marginTop="4dp"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:background="@drawable/startgamebutton" />
+
+    </RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/fragment_roomlist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <FrameLayout
+        android:id="@+id/listHeader"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+	    <include layout="@layout/listview_room_header" />
+    </FrameLayout>
+
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_alignParentBottom="true"
+        android:layout_below="@+id/listHeader"
+        android:cacheColorHint="@android:color/transparent"
+        android:drawSelectorOnTop="false"
+        tools:listitem="@layout/listview_room" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="true"
+        android:text="@string/no_rooms_in_list" />
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-large/listview_room.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+	android:layout_width="fill_parent"
+	android:layout_height="wrap_content" 
+	android:paddingTop="4dp"
+	android:paddingBottom="4dp">
+	
+<TextView
+    android:id="@+id/roomname"
+    android:layout_width="0dp"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:layout_weight="1.5"
+    android:padding="3dp"
+    android:drawablePadding="5dp"
+    android:gravity="left|center_vertical"
+    android:singleLine="true"
+    android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+<include layout="@layout/roomlist_player_team_count" />
+
+<TextView
+    android:id="@+id/owner"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="left"
+	android:layout_gravity="center_vertical"
+	android:singleLine="true"/>
+
+<TextView
+    android:id="@+id/map"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="left"
+	android:layout_gravity="center_vertical"
+	android:singleLine="true"/>
+
+<TextView
+    android:id="@+id/scheme"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="left"
+	android:layout_gravity="center_vertical"
+	android:singleLine="true"/>
+
+<TextView
+    android:id="@+id/weapons"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="left"
+	android:layout_gravity="center_vertical"
+	android:singleLine="true"/>
+
+</LinearLayout>
+    
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-xlarge/roomlist_player_team_count.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+    
+	<TextView
+	    android:id="@+id/playercount"
+		android:layout_width="20dp"
+		android:layout_height="wrap_content"
+		android:padding="3dp"
+		android:gravity="center" 
+		android:layout_gravity="center_vertical"
+		android:singleLine="true"/>
+	
+	<TextView
+	    android:id="@+id/teamcount"
+		android:layout_width="20dp"
+		android:layout_height="wrap_content"
+		android:padding="3dp"
+		android:gravity="center"
+		android:layout_gravity="center_vertical"
+		android:singleLine="true"/>
+</merge>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout-xlarge/roomlist_player_team_count_header.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+    
+	<TextView
+	    android:id="@+id/playercount"
+		android:layout_width="20dp"
+		android:layout_height="wrap_content"
+		android:padding="3dp"
+		android:gravity="center" 
+		android:singleLine="true"
+		android:textAppearance="?android:attr/textAppearanceMedium"
+		android:text="@string/roomlist_header_clients"/>
+	
+	<TextView
+	    android:id="@+id/teamcount"
+		android:layout_width="20dp"
+		android:layout_height="wrap_content"
+		android:padding="3dp"
+		android:gravity="center"
+		android:singleLine="true"
+		android:textAppearance="?android:attr/textAppearanceMedium"
+		android:text="@string/roomlist_header_teams" />
+</merge>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_lobby.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" >
+
+            <TabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_weight="0" />
+
+            <FrameLayout
+                android:id="@android:id/tabcontent"
+                android:layout_width="0dip"
+                android:layout_height="match_parent"
+                android:layout_weight="1" >
+
+                <fragment
+                    android:id="@+id/roomListFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.RoomlistFragment"
+                    tools:layout="@layout/fragment_roomlist" />
+
+                <fragment
+                    android:id="@+id/chatFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.ChatFragment"
+                    tools:layout="@layout/fragment_chat" />
+
+                <fragment
+                    android:id="@+id/playerListFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.LobbyPlayerlistFragment"
+                    tools:layout="@layout/fragment_playerlist" />
+            </FrameLayout>
+        </LinearLayout>
+    </TabHost>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_localroom.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" >
+
+            <TabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_weight="0" />
+
+            <FrameLayout
+                android:id="@android:id/tabcontent"
+                android:layout_width="0dip"
+                android:layout_height="match_parent"
+                android:layout_weight="1" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+
+                
+                <LinearLayout
+                    android:id="@+id/teamlistContainer"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    android:orientation="vertical" >
+	                <fragment
+	                    android:id="@+id/teamlistFragment"
+	                    android:layout_width="fill_parent"
+	                    android:layout_height="0dp"
+	                    android:layout_weight="1"
+	                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+	                    tools:layout="@layout/fragment_teamlist" />
+
+                    <Button
+                        android:id="@+id/startGame"
+                        android:layout_width="120dp"
+                        android:layout_height="40dp"
+                        android:layout_gravity="right"
+                        android:layout_marginTop="4dp"
+                        android:background="@drawable/startgamebutton" />
+                </LinearLayout>
+            </FrameLayout>
+        </LinearLayout>
+    </TabHost>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_main.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" >
+
+        <View
+            android:id="@+id/placeholder"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_centerInParent="true" />
+
+        <FrameLayout
+            android:id="@+id/frameLayout1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentTop="true"
+            android:layout_toLeftOf="@id/placeholder" >
+
+            <Button
+                android:id="@+id/startGame"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:drawableTop="@drawable/button_local_play"
+                android:text="@string/main_button_localplay" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentTop="true"
+            android:layout_toRightOf="@id/placeholder" >
+
+            <Button
+                android:id="@+id/joinLobby"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:drawableTop="@drawable/button_network_play"
+                android:text="@string/main_button_netplay" />
+        </FrameLayout>
+    </RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <include layout="@layout/background" />
+
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal" >
+
+            <TabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_weight="0" />
+
+            <FrameLayout
+                android:id="@android:id/tabcontent"
+                android:layout_width="0dip"
+                android:layout_height="match_parent"
+                android:layout_weight="1" >
+
+                <fragment
+                    android:id="@+id/mapFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.MapFragment"
+                    tools:layout="@layout/fragment_map" />
+
+                <fragment
+                    android:id="@+id/settingsFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.SettingsFragment"
+                    tools:layout="@layout/fragment_settings" />
+
+                <fragment
+                    android:id="@+id/teamlistFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.TeamlistFragment"
+                    tools:layout="@layout/fragment_teamlist" />
+
+                <fragment
+                    android:id="@+id/chatFragment"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    class="org.hedgewars.hedgeroid.ChatFragment"
+                    tools:layout="@layout/fragment_chat" />
+
+                <LinearLayout
+                    android:id="@+id/playerListContainer"
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent"
+                    android:orientation="vertical" >
+
+                    <fragment
+                        android:id="@+id/playerListFragment"
+                        android:layout_width="fill_parent"
+                        android:layout_height="0dp"
+                        android:layout_weight="1"
+                        class="org.hedgewars.hedgeroid.RoomPlayerlistFragment"
+                        tools:layout="@layout/fragment_playerlist" />
+
+                    <Button
+                        android:id="@+id/startGame"
+                        android:layout_width="120dp"
+                        android:layout_height="40dp"
+                        android:layout_gravity="right"
+                        android:layout_marginTop="4dp"
+                        android:background="@drawable/startgamebutton" />
+                </LinearLayout>
+            </FrameLayout>
+        </LinearLayout>
+    </TabHost>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_schemelist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ListView 
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" 
+        android:cacheColorHint="@android:color/transparent" />
+
+	<Button
+        android:id="@+id/addButton"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/schemelist_add_button_text"
+        android:background="@drawable/button" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_teamlist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+  xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="fill_parent"
+  android:layout_height="fill_parent">
+  
+  <include layout="@layout/background"/>
+
+  <TextView
+    android:id="@android:id/empty"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:text="@string/teamlist_empty" />
+  
+  <ListView
+  	android:id="@android:id/list"
+  	android:layout_height="fill_parent"
+  	android:layout_width="wrap_content"
+  	android:layout_margin="3dp"
+  	android:background="@drawable/box" />
+
+  <ImageButton
+   	android:id="@+id/btnAdd"
+   	android:layout_width="wrap_content"
+   	android:layout_height="50dip"
+   	android:layout_alignParentBottom="true"
+   	android:layout_alignParentRight="true"
+   	android:adjustViewBounds="true"
+   	android:scaleType="centerInside"
+   	android:background="@android:color/transparent"
+   	android:src="@drawable/settings"
+   	android:contentDescription="@string/teamlist_add_content_description"/>
+
+</RelativeLayout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_weaponsetlist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="@string/weaponsetlist_empty" />
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:cacheColorHint="@android:color/transparent" />
+
+    <Button
+        android:id="@+id/addButton"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/button"
+        android:text="@string/weaponsetlist_add_button_text" />
+
+</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/backbutton.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <ImageButton
-    	android:id="@+id/btnBack"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:layout_alignParentBottom="true"
-    	android:layout_alignParentLeft="true"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/backbutton"/>
-</merge>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/config.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
-    	
-    <ListView
-    	android:id="@+id/listView"
-    	android:layout_width="wrap_content"
-    	android:layout_height="fill_parent"/>
-    	
-</RelativeLayout>
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_chat.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ListView 
+        android:id="@+id/chatConsole"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" 
+        android:clickable="false"
+        android:cacheColorHint="@android:color/transparent"
+        android:transcriptMode="normal"
+        android:focusableInTouchMode="false"
+        android:focusable="false"
+        android:longClickable="false"
+        android:stackFromBottom="true"
+        />
+
+	<EditText
+        android:id="@+id/chatInput"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="@string/chat_hint"
+        android:imeOptions="actionSend"
+        android:inputType="text" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_map.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="3dp"
+    android:paddingLeft="5dp"
+    android:paddingRight="3dp"
+    android:paddingTop="3dp" >
+
+    <ImageView
+        android:id="@+id/mapPreview"
+        android:layout_width="256dip"
+        android:layout_height="128dip"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:background="@drawable/box"
+        android:scaleType="fitCenter"
+        android:src="@drawable/roomlist_preparing" />
+
+    <TableLayout
+        android:id="@+id/gameOptions"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/mapPreview"
+        android:stretchColumns="1" >
+
+        <TableRow android:layout_marginTop="5dip" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/map_gen" />
+
+            <Spinner
+                android:id="@+id/spinMapType"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/rowMapName"
+            android:layout_marginTop="5dip" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/map_name" />
+
+            <Spinner
+                android:id="@+id/spinMapName"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/rowTemplateFilter"
+            android:layout_marginTop="5dip"
+            android:visibility="gone" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/map_template" />
+
+            <Spinner
+                android:id="@+id/spinTemplateFilter"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/rowMazeSize"
+            android:layout_marginTop="5dip"
+            android:visibility="gone" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/map_maze_size" />
+
+            <Spinner
+                android:id="@+id/spinMazeSize"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft = "5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+
+        <Button
+            android:id="@+id/btnEditDrawnMap"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:background="@drawable/button"
+            android:enabled="false"
+            android:text="@string/map_button_editdrawnmap"
+            android:visibility="gone" />
+    </TableLayout>
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_playerlist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:drawSelectorOnTop="false"
+        android:cacheColorHint="@android:color/transparent"
+        tools:listitem="@layout/listview_player" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="@string/no_players_in_list" />
+</FrameLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_roomlist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingLeft="8dp"
+    android:paddingRight="8dp" >
+
+    <ListView
+        android:id="@id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:drawSelectorOnTop="false"
+        android:cacheColorHint="@android:color/transparent"
+        tools:listitem="@layout/listview_room" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:text="@string/no_rooms_in_list" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_settings.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingBottom="3dp"
+    android:paddingLeft="5dp"
+    android:paddingRight="3dp"
+    android:paddingTop="3dp" >
+
+    <TableLayout
+        android:id="@+id/gameOptions"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:stretchColumns="1" >
+
+        <TableRow>
+
+            <TextView
+                android:id="@+id/txtGameplay"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/start_gameplay" />
+
+            <Spinner
+                android:id="@+id/spinGameplay"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+
+        <TableRow android:layout_marginTop="5dip" >
+
+            <TextView
+                android:id="@+id/txtGamescheme"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/start_gamescheme" />
+
+            <Spinner
+                android:id="@+id/spinGamescheme"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+
+        <TableRow android:layout_marginTop="5dip" >
+
+            <TextView
+                android:id="@+id/txtweapons"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/start_weapons" />
+
+            <Spinner
+                android:id="@+id/spinweapons"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="5dip"
+                android:background="@drawable/dropdown" />
+        </TableRow>
+    </TableLayout>
+
+    <ImageView
+        android:id="@+id/imgTheme"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@+id/spinTheme"
+        android:layout_alignLeft="@id/gameOptions"
+        android:layout_alignTop="@id/spinTheme"
+        android:adjustViewBounds="true" />
+
+    <Spinner
+        android:id="@id/spinTheme"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_below="@id/gameOptions"
+        android:layout_marginTop="5dip"
+        android:layout_toRightOf="@+id/imgTheme"
+        android:background="@drawable/dropdown" />
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_teamlist.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="3dp"
+    android:paddingLeft="5dp"
+    android:paddingRight="3dp"
+    android:paddingTop="3dp" >
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:cacheColorHint="@android:color/transparent" />
+
+    <TextView
+        android:id="@id/android:empty"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:text="@string/no_teams_in_list" />
+    
+    <Button
+        android:id="@+id/addTeamButton"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/button"
+        android:text="@string/teamlist_addteam" />
+
+</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/listview_item.xml	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_item.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
 	android:layout_width="fill_parent"
 	android:layout_height="wrap_content"
 	android:textSize="10dip"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_player.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="4dp"
+	android:paddingBottom="4dp"
+    android:drawablePadding="5dp"
+    android:drawableLeft="@drawable/playerlist_player"
+    android:gravity="center_vertical|left"
+    android:singleLine="true"
+    android:textAppearance="?android:attr/textAppearanceMedium" />
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_room.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:mode="twoLine"
+    android:paddingTop="4dp"
+	android:paddingBottom="4dp">
+
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:drawablePadding="5dp"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <TextView
+        android:id="@android:id/text2"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignLeft="@android:id/text1"
+        android:layout_below="@android:id/text1"
+        android:textAppearance="?android:attr/textAppearanceSmall" />
+
+</TwoLineListItem>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_room_header.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+	android:layout_width="fill_parent"
+	android:layout_height="wrap_content" >
+	
+<TextView
+    android:id="@+id/roomname"
+    android:layout_width="0dp"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:layout_weight="1.5"
+    android:padding="3dp"
+    android:gravity="center"
+    android:singleLine="true"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:text="@string/roomlist_header_roomname" />
+
+<include layout="@layout/roomlist_player_team_count_header" />
+
+<TextView
+    android:id="@+id/owner"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="center"
+	android:singleLine="true"
+	android:textAppearance="?android:attr/textAppearanceMedium"
+	android:text="@string/roomlist_header_owner" />
+
+<TextView
+    android:id="@+id/map"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="center"
+	android:singleLine="true"
+	android:textAppearance="?android:attr/textAppearanceMedium"
+	android:text="@string/roomlist_header_map" />
+
+<TextView
+    android:id="@+id/scheme"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="center"
+	android:singleLine="true"
+	android:textAppearance="?android:attr/textAppearanceMedium"
+	android:text="@string/roomlist_header_scheme" />
+
+<TextView
+    android:id="@+id/weapons"
+	android:layout_width="0dp"
+	android:layout_height="wrap_content"
+	android:layout_weight="0.5"
+	android:padding="3dp"
+	android:gravity="center"
+	android:singleLine="true"
+	android:textAppearance="?android:attr/textAppearanceMedium"
+	android:text="@string/roomlist_header_weapons" />
+
+</LinearLayout>
+    
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_team.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="4dp"
+	android:paddingBottom="4dp" >
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical|left"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:drawablePadding="5dp"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <ImageButton
+        android:id="@+id/colorButton"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_gravity="center_vertical|right"
+        android:src="#fff"
+        android:padding="8dp"
+        android:contentDescription="@string/teamlist_color_button_description" />
+    
+    <ImageButton
+        android:id="@+id/hogCountButton"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_gravity="center_vertical|right"
+        android:src="@drawable/hogcount"
+        android:scaleType="centerCrop"
+        android:padding="0dp"
+        android:contentDescription="@string/teamlist_hogcount_button_description" />
+</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/main.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
-	xmlns:android="http://schemas.android.com/apk/res/android"
-  	android:layout_width="fill_parent"
-	android:layout_height="fill_parent">
-	<include layout="@layout/background"/>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    >    
-    <Button
-    	android:id="@+id/downloader"
-    	android:layout_width="wrap_content"
-    	android:layout_height="wrap_content"
-    	android:text="downloader"/>
-    	
-    <Button
-    	android:id="@+id/startGame"
-    	android:layout_width="wrap_content"
-    	android:layout_height="wrap_content"
-    	android:text="startgame"/>
-    	
-</LinearLayout>
-</FrameLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/savebutton.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <ImageButton
-    	android:id="@+id/btnSave"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:layout_alignParentBottom="true"
-    	android:layout_alignParentRight="true"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/savebutton"/>
-</merge>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/starting_game.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
-    <include
-    	layout="@layout/background"/>
-     
-    <ImageView
-    	android:id="@+id/mapPreview"
-    	android:layout_width="256dip"
-    	android:layout_height="128dip"
-    	android:layout_margin="5dip"
-    	android:scaleType="fitXY"
-    	android:background="@drawable/box"
-    	android:src="@drawable/backbutton"/>
-    
-    <Spinner 
-       	android:id="@+id/spinMaps"
-       	android:layout_height="wrap_content"
-       	android:layout_width="wrap_content"    
-       	android:layout_below="@id/mapPreview"
-       	android:layout_alignRight="@id/mapPreview"
-       	android:layout_toRightOf="@+id/txtMap"
-       	android:background="@drawable/dropdown"/>
-    <TextView
-		android:id="@id/txtMap"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:text="@string/start_map"
-		android:layout_alignTop="@id/spinMaps"
-		android:layout_alignBottom="@id/spinMaps"
-		android:layout_alignLeft="@id/mapPreview"
-		android:gravity="center"/>	
-   	
-    <TableLayout 
-       	android:id="@+id/gameOptions" 
-       	android:layout_height="wrap_content" 
-       	android:layout_width="wrap_content"
-       	android:layout_centerHorizontal="true"
-       	android:layout_toRightOf="@id/mapPreview" 
-       	android:layout_alignParentRight="true"
-       	android:padding="3dip"
-       	android:layout_margin="5dip"
-       	android:background="@drawable/box"
-       	android:stretchColumns="0,2"
-       	android:shrinkColumns="1">
-	       	
-       	<TableRow>
-        	 <TextView 
-		        android:id="@+id/txtGameplay"
-		        android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:text="@string/start_gameplay"/>
-        	<Spinner
-	        	android:id="@+id/spinGameplay"
-	        	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/dropdown"
-		        />
-		</TableRow>  
-		<TableRow>
-		    <TextView 
-		        android:id="@+id/txtGamescheme"
-		        android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:text="@string/start_gamescheme"/>
-		    <Spinner
-		       	android:id="@+id/spinGamescheme"
-		       	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/dropdown"/>
-		    <ImageButton
-		    	android:id="@+id/btnGamescheme"
-		    	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/edit"
-		        android:adjustViewBounds="true"
-		        android:scaleType="centerInside"
-		        android:layout_gravity="center"
-		        android:padding="3dip"/>
-		 </TableRow>
-		 <TableRow>    
-		     <TextView 
-		        android:id="@+id/txtweapons"
-		        android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:layout_below="@id/txtGamescheme"
-		        android:layout_marginTop="5dip"
-		        android:text="@string/start_weapons"/>
-	        
-	        <Spinner
-	        	android:id="@+id/spinweapons"
-	        	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/dropdown"/>
-		    
-		    <ImageButton
-		    	android:id="@+id/btnweapons"
-		    	android:layout_height="wrap_content"
-		        android:layout_width="wrap_content"
-		        android:background="@drawable/edit"
-		        android:adjustViewBounds="true"
-		        android:scaleType="centerInside"
-		        android:layout_gravity="center"
-		        android:padding="3dip"/>
-        </TableRow>	
-    </TableLayout>
-        
-    <ImageView 
-       	android:id="@+id/imgTheme"
-       	android:layout_height="wrap_content" 
-       	android:layout_width="wrap_content"
-       	android:layout_alignTop="@+id/spinTheme"
-       	android:layout_alignBottom="@id/spinTheme"
-       	android:layout_alignLeft="@id/gameOptions"
-       	android:adjustViewBounds="true"/>
-       
-    <Spinner
-        android:id="@id/spinTheme"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content" 
-        android:layout_toRightOf="@+id/imgTheme"
-        android:layout_alignParentRight="true"
-       	android:layout_below="@id/gameOptions"
-       	android:background="@drawable/dropdown"/>
-        
-	<include layout="@layout/backbutton"/>
-    
-    <LinearLayout
-    	android:layout_width="wrap_content"
-    	android:layout_height="wrap_content"
-    	android:layout_alignParentBottom="true"
-    	android:layout_centerHorizontal="true"
-    	android:orientation="horizontal">
-    <ImageButton
-    	android:id="@+id/btnTeams"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/teams"/>
-    <ImageView
-    	android:id="@+id/imgTeamsCount"
-    	android:layout_width="40dip"
-    	android:layout_height="40dip"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/teamcount"/>
-        
-    </LinearLayout>
-
-    <ImageButton
-    	android:id="@+id/btnStart"
-    	android:layout_width="120dip"
-    	android:layout_height="40dip"
-    	android:layout_alignParentBottom="true"
-    	android:layout_alignParentRight="true"
-    	android:adjustViewBounds="true"
-    	android:scaleType="centerInside"
-    	android:background="@android:color/transparent"
-    	android:src="@drawable/startgamebutton"/>
-
-</RelativeLayout>
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/tab_indicator_vertical.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,23 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="0dp"
+    android:layout_weight="1"
+    android:orientation="vertical"
+    android:background="@drawable/box">
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+    />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:scrollHorizontally="false"
+        android:padding="4dp"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        style="?android:attr/tabWidgetStyle"
+    />
+</RelativeLayout>
--- a/project_files/Android-build/SDL-android-project/res/layout/team_creation.xml	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/res/layout/team_creation.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -15,8 +15,6 @@
 	  	android:layout_width="fill_parent"
 	  	android:layout_height="fill_parent"
 	  	android:layout_weight="1">
-	  	<include layout="@layout/backbutton"/>
-	  	<include layout="@layout/savebutton"/>
 	  	<ScrollView
 		  	android:layout_width="fill_parent"
 		  	android:layout_height="fill_parent"
--- a/project_files/Android-build/SDL-android-project/res/layout/team_selection_dialog.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
-  xmlns:android="http://schemas.android.com/apk/res/android"
-  android:orientation="vertical"
-  android:layout_width="wrap_content"
-  android:layout_height="wrap_content">
-  <TextView
-  	android:id="@+id/team_selection_dialog_select"
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="@string/select"/>
-  <TextView
-  	android:id="@+id/team_selection_dialog_edit"
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="@string/edit"/>
-  <TextView
-  	android:id="@+id/team_selection_dialog_delete"
-  	android:layout_width="wrap_content"
-  	android:layout_height="wrap_content"
-  	android:text="@string/delete"/>
-</LinearLayout>
--- a/project_files/Android-build/SDL-android-project/res/layout/team_selection_entry.xml	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/res/layout/team_selection_entry.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -31,7 +31,7 @@
   	android:layout_alignBottom="@id/imgDifficulty"
   	android:adjustViewBounds="true"
   	android:scaleType="centerInside"
-  	android:src="@drawable/teamcount7"/>
+  	android:src="@drawable/hogcount"/>
   <TextView
   	android:id="@+id/txtName"
   	android:layout_height="fill_parent"
--- a/project_files/Android-build/SDL-android-project/res/layout/team_selector.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout
-  xmlns:android="http://schemas.android.com/apk/res/android"
-  android:layout_width="fill_parent"
-  android:layout_height="fill_parent">
-  
-  <include layout="@layout/background"/>
- 
-  <include layout="@layout/backbutton"/>
-
-  <ImageButton
-   	android:id="@+id/btnAdd"
-   	android:layout_width="wrap_content"
-   	android:layout_height="50dip"
-   	android:layout_alignParentBottom="true"
-   	android:layout_alignParentRight="true"
-   	android:adjustViewBounds="true"
-   	android:scaleType="centerInside"
-   	android:background="@android:color/transparent"
-   	android:src="@drawable/settings"/>
- <TextView
-  	android:id="@+id/txtInfo"
-  	android:layout_height="wrap_content"
-  	android:layout_width="fill_parent"
-  	android:layout_alignParentBottom="true"
-  	android:layout_toRightOf="@id/btnBack"
-  	android:layout_toLeftOf="@id/btnAdd"
-  	android:layout_alignTop="@id/btnBack"
-  	android:layout_margin="3dp"
-  	android:gravity="center"
-  	android:background="@drawable/box"/>
-  	
-  
-
-  <LinearLayout
-  	android:orientation="horizontal"
-  	android:layout_width="fill_parent"
-  	android:layout_height="fill_parent"
-  	android:layout_above="@id/txtInfo"
-  	android:layout_margin="3dp">
-  	
-	  <ListView
-	  	android:id="@+id/selectedTeams"
-	  	android:layout_height="fill_parent"
-	  	android:layout_width="wrap_content"
-	  	android:layout_margin="3dp"
-	  	android:background="@drawable/box"
-	  	android:layout_weight="1"/>
-	  	
-	  <ListView
-	  	android:id="@+id/availableTeams"
-	  	android:layout_height="fill_parent"
-	  	android:layout_width="wrap_content"
-	  	android:layout_margin="3dp"
-	  	android:background="@drawable/box"
-	  	android:layout_weight="1"/>
-  </LinearLayout>
-</RelativeLayout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/menu/lobby_options.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:id="@+id/room_create"
+        android:title="@string/lobby_roomlistmenu_create"
+        android:showAsAction="ifRoom" />
+    <item
+        android:id="@+id/disconnect"
+        android:title="@string/lobby_menu_disconnect"
+        android:showAsAction="ifRoom" />
+</menu>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/menu/lobby_playerlist_context.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:id="@+id/player_info"
+        android:title="@string/lobby_playerlist_contextmenu_info">
+    </item>
+    <item
+        android:id="@+id/player_follow"
+        android:title="@string/lobby_playerlist_contextmenu_follow">
+    </item>
+</menu>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/menu/main_options.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,20 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:id="@+id/download"
+        android:title="@string/main_menu_downloader"
+        android:icon="@android:drawable/ic_menu_save"
+        android:showAsAction="ifRoom|withText" />
+    <item
+        android:id="@+id/preferences"
+        android:title="@string/main_menu_preferences"
+        android:icon="@android:drawable/ic_menu_preferences"
+        android:showAsAction="ifRoom|withText" />
+    <item
+        android:id="@+id/edit_teams"
+        android:title="@string/edit_teams_menu"
+        android:showAsAction="ifRoom|withText" />
+    <item
+        android:id="@+id/edit_weaponsets"
+        android:title="@string/edit_weaponsets_menu"
+        android:showAsAction="ifRoom|withText" />
+</menu>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/menu/room_playerlist_chief_context.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,6 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:id="@+id/player_kick"
+        android:title="@string/playerlist_contextmenu_kick">
+    </item>
+</menu>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/menu/room_playerlist_context.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,6 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:id="@+id/player_info"
+        android:title="@string/lobby_playerlist_contextmenu_info">
+    </item>
+</menu>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/basicflags.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,390 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<basicflags>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$damagepct</string>
-        </command>
-        <default>
-            <integer>100</integer>
-        </default>
-        <image>
-            <string>Damage</string>
-        </image>
-        <max>
-            <integer>300</integer>
-        </max>
-        <min>
-            <integer>10</integer>
-        </min>
-        <title>
-            <string>Damage Modifier</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>true</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>true</boolean>
-        </times1000>
-        <command>
-            <string>e$turntime</string>
-        </command>
-        <default>
-            <integer>45</integer>
-        </default>
-        <image>
-            <string>Time</string>
-        </image>
-        <max>
-            <integer>100</integer>
-        </max>
-        <min>
-            <integer>1</integer>
-        </min>
-        <title>
-            <string>Turn Time</string>
-        </title>
-    </flag>
-    <flag>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>inithealth</string>
-        </command>
-        <default>
-            <integer>200</integer>
-        </default>
-        <image>
-            <string>Health</string>
-        </image>
-        <max>
-            <integer>200</integer>
-        </max>
-        <min>
-            <integer>50</integer>
-        </min>
-        <title>
-            <string>Initial Health</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>true</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$sd_turns</string>
-        </command>
-        <default>
-            <integer>15</integer>
-        </default>
-        <image>
-            <string>SuddenDeath</string>
-        </image>
-        <max>
-            <integer>50</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Sudden Death Timeout</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$casefreq</string>
-        </command>
-        <default>
-            <integer>5</integer>
-        </default>
-        <image>
-            <string>Box</string>
-        </image>
-        <max>
-            <integer>9</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Crate Drop Turns</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>true</boolean>
-        </times1000>
-        <command>
-            <string>e$minestime</string>
-        </command>
-        <default>
-            <integer>3</integer>
-        </default>
-        <image>
-            <string>Time</string>
-        </image>
-        <max>
-            <integer>5</integer>
-        </max>
-        <min>
-            <integer>-1</integer>
-        </min>
-        <title>
-            <string>Mines Time</string>
-        </title>
-    </flag>
-   <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$minesnum</string>
-        </command>
-        <default>
-            <integer>4</integer>
-        </default>
-        <image>
-            <string>Mine</string>
-        </image>
-        <max>
-            <integer>80</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Mines Number</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$minedudpct</string>
-        </command>
-        <default>
-            <integer>0</integer>
-        </default>
-        <image>
-            <string>Dud</string>
-        </image>
-        <max>
-            <integer>100</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Dud Mines Probability (%)</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$explosives</string>
-        </command>
-        <default>
-            <integer>2</integer>
-        </default>
-        <image>
-            <string>Damage</string>
-        </image>
-        <max>
-            <integer>40</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Explosives</string>
-        </title>
-    </flag>
-        <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$healthprob</string>
-        </command>
-        <default>
-            <integer>35</integer>
-        </default>
-        <image>
-            <string>Health</string>
-        </image>
-        <max>
-            <integer>100</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Health Kit Probability (%)</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$hcaseamount</string>
-        </command>
-        <default>
-            <integer>25</integer>
-        </default>
-        <image>
-            <string>Health</string>
-        </image>
-        <max>
-            <integer>200</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Health Amount in Kit</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$waterrise</string>
-        </command>
-        <default>
-            <integer>47</integer>
-        </default>
-        <image>
-            <string>SuddenDeath</string>
-        </image>
-        <max>
-            <integer>100</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Water Rise Amount</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$healthdec</string>
-        </command>
-        <default>
-            <integer>5</integer>
-        </default>
-        <image>
-            <string>SuddenDeath</string>
-        </image>
-        <max>
-            <integer>100</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Health Decrease</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$ropepct</string>
-        </command>
-        <default>
-            <integer>100</integer>
-        </default>
-        <image>
-            <string>Rope</string>
-        </image>
-        <max>
-            <integer>999</integer>
-        </max>
-        <min>
-            <integer>25</integer>
-        </min>
-        <title>
-            <string>Rope Length (%)</string>
-        </title>
-    </flag>
-    <flag>
-        <checkOverMax>
-            <boolean>false</boolean>
-        </checkOverMax>
-        <times1000>
-            <boolean>false</boolean>
-        </times1000>
-        <command>
-            <string>e$getawaytime</string>
-        </command>
-        <default>
-            <integer>100</integer>
-        </default>
-        <image>
-            <string>Time</string>
-        </image>
-        <max>
-            <integer>999</integer>
-        </max>
-        <min>
-            <integer>0</integer>
-        </min>
-        <title>
-            <string>Get Away Time (%)</string>
-        </title>
-    </flag>
-</basicflags>
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_barrelmayhem.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Barrel Mayhem</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>30</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>80</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_cleanslate.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Clean Slate</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>45</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>5</integer>
-		<integer>3</integer>
-		<integer>4</integer>
-		<integer>0</integer>
-		<integer>2</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_default_scheme.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Default</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>45</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>5</integer>
-		<integer>3</integer>
-		<integer>4</integer>
-		<integer>0</integer>
-		<integer>2</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_fortmode.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Fort Mode</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>45</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>5</integer>
-		<integer>3</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_kingmode.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>King Mode</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>45</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>5</integer>
-		<integer>3</integer>
-		<integer>4</integer>
-		<integer>0</integer>
-		<integer>2</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_minefield.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Minefield</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>30</integer>
-		<integer>50</integer>
-		<integer>15</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>80</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-        <integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_promode.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Pro Mode</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>0</integer>
-		<integer>3</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>2</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_shoppa.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Shoppa</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>30</integer>
-		<integer>100</integer>
-		<integer>50</integer>
-		<integer>1</integer>
-		<integer>3</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_thinkingwithportals.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Thinking with Portals</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>45</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>2</integer>
-		<integer>3</integer>
-		<integer>5</integer>
-		<integer>0</integer>
-		<integer>5</integer>
-		<integer>25</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_timeless.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Timeless</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>9999</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>5</integer>
-		<integer>3</integer>
-		<integer>5</integer>
-		<integer>10</integer>
-		<integer>2</integer>
-		<integer>35</integer>
-		<integer>30</integer>
-		<integer>0</integer>
-		<integer>0</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/scheme_tunnelhogs.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scheme>
-	<name>Tunnelhogs</name>
-	<basicflags>
-		<integer>100</integer>
-		<integer>30</integer>
-		<integer>100</integer>
-		<integer>15</integer>
-		<integer>5</integer>
-		<integer>3</integer>
-		<integer>10</integer>
-		<integer>10</integer>
-		<integer>10</integer>
-		<integer>35</integer>
-		<integer>25</integer>
-		<integer>47</integer>
-		<integer>5</integer>
-		<integer>100</integer>
-		<integer>100</integer>
-	</basicflags>
-	<gamemod>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<true/>
-		<false/>
-		<false/>
-		<true/>
-		<true/>
-		<true/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-		<false/>
-	</gamemod>
-</scheme>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/raw/schemes_builtin.ini	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,456 @@
+
+[schemes]
+size                           = 11
+1\name                         = Default
+1\fortsmode                    = false
+1\divteams                     = false
+1\solidland                    = false
+1\border                       = false
+1\lowgrav                      = false
+1\laser                        = false
+1\invulnerability              = false
+1\resethealth                  = false
+1\vampiric                     = false
+1\karma                        = false
+1\artillery                    = false
+1\randomorder                  = false
+1\king                         = false
+1\placehog                     = false
+1\sharedammo                   = false
+1\disablegirders               = false
+1\disablelandobjects           = false
+1\aisurvival                   = false
+1\infattack                    = false
+1\resetweps                    = false
+1\perhogammo                   = false
+1\disablewind                  = false
+1\morewind                     = false
+1\tagteam                      = false
+1\bottomborder                 = false
+1\damagefactor                 = 100
+1\turntime                     = 45
+1\health                       = 100
+1\suddendeath                  = 15
+1\caseprobability              = 5
+1\minestime                    = 3
+1\minesnum                     = 4
+1\minedudpct                   = 0
+1\explosives                   = 2
+1\healthprobability            = 35
+1\healthcaseamount             = 25
+1\waterrise                    = 47
+1\healthdecrease               = 5
+1\ropepct                      = 100
+1\getawaytime                  = 100
+2\name                         = Pro Mode
+2\fortsmode                    = false
+2\divteams                     = false
+2\solidland                    = false
+2\border                       = false
+2\lowgrav                      = false
+2\laser                        = false
+2\invulnerability              = false
+2\resethealth                  = false
+2\vampiric                     = false
+2\karma                        = false
+2\artillery                    = false
+2\randomorder                  = true
+2\king                         = false
+2\placehog                     = false
+2\sharedammo                   = false
+2\disablegirders               = false
+2\disablelandobjects           = false
+2\aisurvival                   = false
+2\infattack                    = false
+2\resetweps                    = false
+2\perhogammo                   = false
+2\disablewind                  = false
+2\morewind                     = false
+2\tagteam                      = false
+2\bottomborder                 = false
+2\damagefactor                 = 100
+2\turntime                     = 45
+2\health                       = 100
+2\suddendeath                  = 15
+2\caseprobability              = 5
+2\minestime                    = 3
+2\minesnum                     = 4
+2\minedudpct                   = 0
+2\explosives                   = 2
+2\healthprobability            = 35
+2\healthcaseamount             = 25
+2\waterrise                    = 47
+2\healthdecrease               = 5
+2\ropepct                      = 100
+2\getawaytime                  = 100
+3\name                         = Shoppa
+3\fortsmode                    = false
+3\divteams                     = false
+3\solidland                    = false
+3\border                       = false
+3\lowgrav                      = false
+3\laser                        = false
+3\invulnerability              = false
+3\resethealth                  = false
+3\vampiric                     = false
+3\karma                        = false
+3\artillery                    = false
+3\randomorder                  = true
+3\king                         = false
+3\placehog                     = false
+3\sharedammo                   = true
+3\disablegirders               = false
+3\disablelandobjects           = false
+3\aisurvival                   = false
+3\infattack                    = false
+3\resetweps                    = false
+3\perhogammo                   = false
+3\disablewind                  = false
+3\morewind                     = false
+3\tagteam                      = false
+3\bottomborder                 = false
+3\damagefactor                 = 100
+3\turntime                     = 15
+3\health                       = 100
+3\suddendeath                  = 15
+3\caseprobability              = 0
+3\minestime                    = 3
+3\minesnum                     = 0
+3\minedudpct                   = 0
+3\explosives                   = 2
+3\healthprobability            = 35
+3\healthcaseamount             = 25
+3\waterrise                    = 47
+3\healthdecrease               = 5
+3\ropepct                      = 100
+3\getawaytime                  = 100
+4\name                         = Clean Slate
+4\fortsmode                    = false
+4\divteams                     = false
+4\solidland                    = true
+4\border                       = true
+4\lowgrav                      = false
+4\laser                        = false
+4\invulnerability              = false
+4\resethealth                  = false
+4\vampiric                     = false
+4\karma                        = false
+4\artillery                    = false
+4\randomorder                  = true
+4\king                         = false
+4\placehog                     = false
+4\sharedammo                   = true
+4\disablegirders               = true
+4\disablelandobjects           = false
+4\aisurvival                   = false
+4\infattack                    = false
+4\resetweps                    = true
+4\perhogammo                   = false
+4\disablewind                  = false
+4\morewind                     = false
+4\tagteam                      = false
+4\bottomborder                 = false
+4\damagefactor                 = 100
+4\turntime                     = 30
+4\health                       = 100
+4\suddendeath                  = 50
+4\caseprobability              = 1
+4\minestime                    = 3
+4\minesnum                     = 0
+4\minedudpct                   = 0
+4\explosives                   = 0
+4\healthprobability            = 0
+4\healthcaseamount             = 25
+4\waterrise                    = 47
+4\healthdecrease               = 5
+4\ropepct                      = 100
+4\getawaytime                  = 100
+5\name                         = Minefield
+5\fortsmode                    = false
+5\divteams                     = false
+5\solidland                    = false
+5\border                       = false
+5\lowgrav                      = false
+5\laser                        = false
+5\invulnerability              = false
+5\resethealth                  = true
+5\vampiric                     = false
+5\karma                        = false
+5\artillery                    = false
+5\randomorder                  = true
+5\king                         = false
+5\placehog                     = false
+5\sharedammo                   = false
+5\disablegirders               = false
+5\disablelandobjects           = false
+5\aisurvival                   = false
+5\infattack                    = true
+5\resetweps                    = true
+5\perhogammo                   = false
+5\disablewind                  = false
+5\morewind                     = false
+5\tagteam                      = false
+5\bottomborder                 = false
+5\damagefactor                 = 100
+5\turntime                     = 45
+5\health                       = 100
+5\suddendeath                  = 15
+5\caseprobability              = 5
+5\minestime                    = 3
+5\minesnum                     = 4
+5\minedudpct                   = 0
+5\explosives                   = 2
+5\healthprobability            = 35
+5\healthcaseamount             = 25
+5\waterrise                    = 47
+5\healthdecrease               = 5
+5\ropepct                      = 100
+5\getawaytime                  = 100
+6\name                         = Barrel Mayhem
+6\fortsmode                    = false
+6\divteams                     = false
+6\solidland                    = false
+6\border                       = false
+6\lowgrav                      = false
+6\laser                        = false
+6\invulnerability              = false
+6\resethealth                  = false
+6\vampiric                     = false
+6\karma                        = false
+6\artillery                    = false
+6\randomorder                  = true
+6\king                         = false
+6\placehog                     = false
+6\sharedammo                   = true
+6\disablegirders               = true
+6\disablelandobjects           = false
+6\aisurvival                   = false
+6\infattack                    = false
+6\resetweps                    = false
+6\perhogammo                   = false
+6\disablewind                  = false
+6\morewind                     = false
+6\tagteam                      = false
+6\bottomborder                 = false
+6\damagefactor                 = 100
+6\turntime                     = 30
+6\health                       = 50
+6\suddendeath                  = 15
+6\caseprobability              = 0
+6\minestime                    = 0
+6\minesnum                     = 80
+6\minedudpct                   = 0
+6\explosives                   = 0
+6\healthprobability            = 35
+6\healthcaseamount             = 25
+6\waterrise                    = 47
+6\healthdecrease               = 5
+6\ropepct                      = 100
+6\getawaytime                  = 100
+7\name                         = Tunnel Hogs
+7\fortsmode                    = false
+7\divteams                     = false
+7\solidland                    = false
+7\border                       = false
+7\lowgrav                      = false
+7\laser                        = false
+7\invulnerability              = false
+7\resethealth                  = false
+7\vampiric                     = false
+7\karma                        = false
+7\artillery                    = false
+7\randomorder                  = true
+7\king                         = false
+7\placehog                     = false
+7\sharedammo                   = true
+7\disablegirders               = false
+7\disablelandobjects           = false
+7\aisurvival                   = false
+7\infattack                    = false
+7\resetweps                    = false
+7\perhogammo                   = false
+7\disablewind                  = false
+7\morewind                     = false
+7\tagteam                      = false
+7\bottomborder                 = false
+7\damagefactor                 = 100
+7\turntime                     = 30
+7\health                       = 100
+7\suddendeath                  = 15
+7\caseprobability              = 0
+7\minestime                    = 0
+7\minesnum                     = 0
+7\minedudpct                   = 0
+7\explosives                   = 80
+7\healthprobability            = 35
+7\healthcaseamount             = 25
+7\waterrise                    = 47
+7\healthdecrease               = 5
+7\ropepct                      = 100
+7\getawaytime                  = 100
+8\name                         = Fort Mode
+8\fortsmode                    = false
+8\divteams                     = false
+8\solidland                    = false
+8\border                       = true
+8\lowgrav                      = false
+8\laser                        = false
+8\invulnerability              = false
+8\resethealth                  = false
+8\vampiric                     = false
+8\karma                        = false
+8\artillery                    = false
+8\randomorder                  = true
+8\king                         = false
+8\placehog                     = false
+8\sharedammo                   = true
+8\disablegirders               = true
+8\disablelandobjects           = true
+8\aisurvival                   = false
+8\infattack                    = false
+8\resetweps                    = false
+8\perhogammo                   = false
+8\disablewind                  = false
+8\morewind                     = false
+8\tagteam                      = false
+8\bottomborder                 = false
+8\damagefactor                 = 100
+8\turntime                     = 30
+8\health                       = 100
+8\suddendeath                  = 15
+8\caseprobability              = 5
+8\minestime                    = 3
+8\minesnum                     = 10
+8\minedudpct                   = 10
+8\explosives                   = 10
+8\healthprobability            = 35
+8\healthcaseamount             = 25
+8\waterrise                    = 47
+8\healthdecrease               = 5
+8\ropepct                      = 100
+8\getawaytime                  = 100
+9\name                         = Timeless
+9\fortsmode                    = true
+9\divteams                     = true
+9\solidland                    = false
+9\border                       = false
+9\lowgrav                      = true
+9\laser                        = false
+9\invulnerability              = false
+9\resethealth                  = false
+9\vampiric                     = false
+9\karma                        = false
+9\artillery                    = false
+9\randomorder                  = true
+9\king                         = false
+9\placehog                     = false
+9\sharedammo                   = false
+9\disablegirders               = false
+9\disablelandobjects           = false
+9\aisurvival                   = false
+9\infattack                    = false
+9\resetweps                    = false
+9\perhogammo                   = false
+9\disablewind                  = false
+9\morewind                     = false
+9\tagteam                      = false
+9\bottomborder                 = false
+9\damagefactor                 = 100
+9\turntime                     = 45
+9\health                       = 100
+9\suddendeath                  = 15
+9\caseprobability              = 5
+9\minestime                    = 3
+9\minesnum                     = 0
+9\minedudpct                   = 0
+9\explosives                   = 0
+9\healthprobability            = 35
+9\healthcaseamount             = 25
+9\waterrise                    = 47
+9\healthdecrease               = 5
+9\ropepct                      = 100
+9\getawaytime                  = 100
+10\name                        = Thinking with Portals
+10\fortsmode                   = false
+10\divteams                    = false
+10\solidland                   = false
+10\border                      = false
+10\lowgrav                     = false
+10\laser                       = false
+10\invulnerability             = false
+10\resethealth                 = false
+10\vampiric                    = false
+10\karma                       = false
+10\artillery                   = false
+10\randomorder                 = true
+10\king                        = false
+10\placehog                    = false
+10\sharedammo                  = false
+10\disablegirders              = false
+10\disablelandobjects          = false
+10\aisurvival                  = false
+10\infattack                   = false
+10\resetweps                   = false
+10\perhogammo                  = true
+10\disablewind                 = false
+10\morewind                    = false
+10\tagteam                     = false
+10\bottomborder                = false
+10\damagefactor                = 100
+10\turntime                    = 9999
+10\health                      = 100
+10\suddendeath                 = 15
+10\caseprobability             = 5
+10\minestime                   = 3
+10\minesnum                    = 5
+10\minedudpct                  = 10
+10\explosives                  = 2
+10\healthprobability           = 35
+10\healthcaseamount            = 30
+10\waterrise                   = 0
+10\healthdecrease              = 0
+10\ropepct                     = 100
+10\getawaytime                 = 100
+11\name                        = King Mode
+11\fortsmode                   = false
+11\divteams                    = false
+11\solidland                   = false
+11\border                      = false
+11\lowgrav                     = false
+11\laser                       = false
+11\invulnerability             = false
+11\resethealth                 = false
+11\vampiric                    = false
+11\karma                       = false
+11\artillery                   = true
+11\randomorder                 = true
+11\king                        = false
+11\placehog                    = false
+11\sharedammo                  = false
+11\disablegirders              = false
+11\disablelandobjects          = false
+11\aisurvival                  = false
+11\infattack                   = false
+11\resetweps                   = false
+11\perhogammo                  = false
+11\disablewind                 = false
+11\morewind                    = false
+11\tagteam                     = false
+11\bottomborder                = false
+11\damagefactor                = 100
+11\turntime                    = 45
+11\health                      = 100
+11\suddendeath                 = 15
+11\caseprobability             = 2
+11\minestime                   = 3
+11\minesnum                    = 5
+11\minedudpct                  = 0
+11\explosives                  = 5
+11\healthprobability           = 25
+11\healthcaseamount            = 25
+11\waterrise                   = 47
+11\healthdecrease              = 5
+11\ropepct                     = 100
+11\getawaytime                 = 100
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/raw/team_one.hwt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,74 @@
+[Team]
+Name=Team 1
+Grave=Bone
+Fort=Lego
+Voicepack=Classic
+Flag=hedgewars
+Difficulty=0
+Rounds=0
+Wins=0
+CampaignProgress=0
+
+[Hedgehog0]
+Name=Leonidas
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog1]
+Name=Pipo
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog2]
+Name=Sonic
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog3]
+Name=Xin
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog4]
+Name=Arnold
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog5]
+Name=Jack
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog6]
+Name=Tom
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog7]
+Name=Goldie
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
--- a/project_files/Android-build/SDL-android-project/res/raw/team_one.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
-<team>
-  <name>Team 1</name>
-  <flag>hedgewars</flag>
-  <fort>Lego</fort>
-  <grave>Bone</grave>
-  <voice>Classic</voice>
-  <hash>0</hash>
-  <hog>
-    <name>Leonidas</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Pipo</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Sonic</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Xin</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Arnold</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Jack</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Tom</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-  <hog>
-    <name>Goldie</name>
-    <hat>NoHat</hat>
-    <level>0</level>
-  </hog>
-</team>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/raw/team_two.hwt	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,74 @@
+[Team]
+Name=Team 2
+Grave=Bone
+Fort=Lego
+Voicepack=Classic
+Flag=cm_binary
+Difficulty=2
+Rounds=0
+Wins=0
+CampaignProgress=0
+
+[Hedgehog0]
+Name=Paris
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog1]
+Name=Knut
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog2]
+Name=Ash
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog3]
+Name=Woad
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog4]
+Name=Bob
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog5]
+Name=Corky
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog6]
+Name=Bea
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
+
+[Hedgehog7]
+Name=Silvia
+Hat=NoHat
+Rounds=0
+Kills=0
+Deaths=0
+Suicides=0
--- a/project_files/Android-build/SDL-android-project/res/raw/team_two.xml	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
-<team>
-  <name>Team 2</name>
-  <flag>cm_binary</flag>
-  <fort>Lego</fort>
-  <grave>Bone</grave>
-  <voice>Classic</voice>
-  <hash>0</hash>
-  <hog>
-    <name>Paris</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Knut</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Ash</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Woad</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Bob</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Corky</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Bea</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-  <hog>
-    <name>Silvia</name>
-    <hat>NoHat</hat>
-    <level>2</level>
-  </hog>
-</team>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_clean	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Clean</name>
-    <QT>
-    101000900001000001100000000000000000000000000000100000
-    </QT>
-    <probability>
-    040504054160065554655446477657666666615551010111541111
-    </probability>
-    <delay>
-    000000000000000000000000000000000000000000000000000000
-    </delay>
-    <crate>
-    131111031211111112311411111111111111121111110111111111
-    </crate>
-</weapon>
-
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_crazy	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Crazy</name>
-    <QT>
-    999999999999999999299999999999999929999999990999999229
-    </QT>
-    <probability>
-    111111011111111111111111111111111111111111110111111111
-    </probability>
-    <delay>
-    000000000000000000000000000000000000000000000000000000
-    </delay>
-    <crate>
-    131111031211111112311411111111111111121111010111111111
-    </crate>
-</weapon>
-
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_default	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Default</name>
-    <QT>
-    939192942219912103223511100120100000021111010101111991
-    </QT>
-    <probability>
-    040504054160065554655446477657666666615551010111541111
-    </probability>
-    <delay>
-    000000000000020550000004000700400000000022000000060000
-    </delay>
-    <crate>
-    131111031211111112311411111111111111121111110111111111
-    </crate>
-</weapon>
-
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_mines	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Mines</name>
-    <QT>
-    000000990009000000030000000000000000000000000000000000
-    </QT>
-    <probability>
-    000000000000000000000000000000000000000000000000000000
-    </probability>
-    <delay>
-    000000000000020550000004000700400000000020000000060000
-    </delay>
-    <crate>
-    111111111111111111111111111111111111111111110111111111
-    </crate>
-</weapon>
-
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_portals	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Portals</name>
-    <QT>
-    900000900200000000210000000000000011000009000000000000
-    </QT>
-    <probability>
-    040504054160065554655446477657666666615551010111541111
-    </probability>
-    <delay>
-    000000000000020550000004000700400000000020000000060000
-    </delay>
-    <crate>
-    131111031211111112311411111111111111121111110111111111
-    </crate>
-</weapon>
-
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_promode	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Pro Mode</name>
-    <QT>
-    909000900000000000000900000000000000000000000000000000
-    </QT>
-    <probability>
-    000000000000000000000000000000000000000000000000000000
-    </probability>
-    <delay>
-    000000000000020550000004000700400000000020000000000000
-    </delay>
-    <crate>
-    111111111111111111111111111111111111111110010111111111
-    </crate>
-</weapon>
-
--- a/project_files/Android-build/SDL-android-project/res/raw/weapon_shoppa	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<weapon>
-    <name>Shoppa</name>
-    <QT>
-    000000990000000000000000000000000000000000000000000000
-    </QT>
-    <probability>
-    444441004424440221011212122242200000000200040001001111
-    </probability>
-    <delay>
-    000000000000000000000000000000000000000000000000000000
-    </delay>
-    <crate>
-    111111111111111111111111111111111111111110110111111111
-    </crate>
-</weapon>
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/raw/weapons_builtin.ini	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,8 @@
+[General]
+%44efault=9391929422199121032235111001201000000211110101011111011040504054160065554655446477657666666615551010111541101100000000000002055000000400070040000000002200000006000001311110312111111123114111111111111111211111101111111010
+%43razy=9999999999999999992999999999999999299999999909999992099111111011111111111111111111111111111111111110111111101100000000000000000000000000000000000000000000000000000001311110312111111123114111111111111111211110101111111011
+%50ro%20%4dode=9090009000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002055000000400070040000000002000000000000001111111111111111111111111111111111111111100101111111011
+%53hoppa=0000009900000000000000000000000000000000000000000000000444441004424440221011212122242200000000200040001001100000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111101101111111001
+%43lean%20%53late=1010009000010000011000000000000000000000000000001000000040504054160065554655446477657666666615551010111541101100000000000000000000000000000000000000000000000000000001311110312111111123114111111111111111211111101111111011
+%4dinefield=0000009900090000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002055000000400070040000000002000000006000001111111111111111111111111111111111111111111101111111011
+%54hinking%20with%20%50ortals=9000009002000000002100000000000000110000090000000000000040504054160065554655446477657666666615551010111541101100000000000002055000000400070040000000002000000006000001311110312111111123114111111111111111211111101111111011
--- a/project_files/Android-build/SDL-android-project/res/values/frontend_data_pointers.xml	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/res/values/frontend_data_pointers.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -1,34 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-
-<array name="schemes">
-	<item>@raw/basicflags</item>
-	<item>@raw/scheme_default_scheme</item>
-	<item>@raw/scheme_barrelmayhem</item>
-	<item>@raw/scheme_cleanslate</item>
-	<item>@raw/scheme_fortmode</item>
-	<item>@raw/scheme_kingmode</item>
-	<item>@raw/scheme_minefield</item>
-	<item>@raw/scheme_promode</item>
-	<item>@raw/scheme_shoppa</item>
-	<item>@raw/scheme_thinkingwithportals</item>
-	<item>@raw/scheme_timeless</item>
-	<item>@raw/scheme_tunnelhogs</item>
-</array>
-
-<array name="weapons">
-    <item>@raw/weapon_default</item>
-    <item>@raw/weapon_clean</item>
-    <item>@raw/weapon_crazy</item>
-    <item>@raw/weapon_mines</item>
-    <item>@raw/weapon_portals</item>
-    <item>@raw/weapon_promode</item>
-    <item>@raw/weapon_shoppa</item>
-</array>
-
 <array name="teams">
 	<item>@raw/team_one</item>
 	<item>@raw/team_two</item>
-
+</array>
+<array name="teamFilenames">
+	<item>Team 1.hwt</item>
+	<item>Team 2.hwt</item>
 </array>
 </resources>
--- a/project_files/Android-build/SDL-android-project/res/values/strings.xml	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/res/values/strings.xml	Sun Nov 18 23:10:26 2012 +0400
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
+
     <string name="app_name">Hedgewars</string>
-    
     <string name="select">Select</string>
     <string name="edit">Edit</string>
     <string name="delete">Delete</string>
     <string name="saved">Saved succesfully</string>
-    
+
     <!-- SDCARD -->
     <string name="sdcard_not_mounted_title">Sorry! Could not find the SDCard</string>
     <string name="sdcard_not_mounted">There\'s been an error when accessing the SDcard. Please check if there is an SDcard present in the device (internal or external) and if the SDcard is not mounted (via usb to your computer for example). Hedgewars for Android will now quit</string>
-        
+
     <!-- Notification -->
-    <string name="notification_title">Downloading hedgewars files...</string>
+    <string name="notification_title">Downloading hedgewars files&#8230;</string>
     <string name="notification_done">Successfully downloaded: </string>
-    
+
     <!-- Download Activity -->
     <string name="download_background">Continue in background</string>
     <string name="download_cancel">Cancel</string>
@@ -22,28 +22,31 @@
     <string name="download_back">Back to main menu</string>
     <string name="download_tryagain">Try again</string>
     <string name="download_failed">The download has failed because of: </string>
-    <string name="download_userexplain">Before starting the game we must download some extra files...</string>
-    
+    <string name="download_userexplain">Before starting the game we must download some extra files&#8230;</string>
     <string name="download_areyousure">Are you sure you want to download this package?</string>
     <string name="download_alreadydownloaded">You\'ve already downloaded this package, are you sure you want to download it again?</string>
     <string name="download_downloadnow">Download now!</string>
-    
     <string name="download_queued">This download has been queued</string>
+
+    <!-- main activity -->
+    <string name="main_button_localplay">Local Game</string>
+    <string name="main_button_netplay">Network Game</string>
+    <string name="main_menu_downloader">Downloader</string>
+    <string name="main_menu_preferences">Preferences</string>
     
     <!-- start game -->
-    
     <string name="start_gameplay">Style</string>
-    <string name="start_gamescheme">Game scheme</string>
+    <string name="start_gamescheme">Scheme</string>
     <string name="start_weapons">Weapons</string>
     <string name="start_map">Map</string>
     <string name="start_filter">Filter</string>
-    <string name="start_themes">Themes</string>
-    
-    
+
+    <!-- Teams -->
+    <string name="not_enough_teams">You need at least two teams.</string>
+    <string name="not_enough_clans">You need at least two different team colors (clans).</string>
+    <string name="teamlist_empty">No teams</string>
+    <string name="teamlist_add_content_description">New team</string>
     
-    <!-- Teams -->
-    <string name="not_enough_teams">Not enough teams</string>
-    <string name="teams_info_template">Selected teams = %d</string>
     <!-- Settings -->
     <string name="name">Name</string>
     <string name="name_default">Unnamed</string>
@@ -52,7 +55,7 @@
     <string name="flag">Flag</string>
     <string name="voice">Voice</string>
     <string name="fort">Fort</string>
-    
+
     <!-- Difficulty levels -->
     <string name="human">Human</string>
     <string name="bot5">Level 5</string>
@@ -60,5 +63,131 @@
     <string name="bot3">Level 3</string>
     <string name="bot2">Level 2</string>
     <string name="bot1">Level 1</string>
+
+    <string name="title_activity_lobby">Hedgewars Server Lobby</string>
+    <string name="title_activity_room">Room</string>
+    <string name="title_activity_weaponset_list">User-defined Weaponsets</string>
+    <string name="title_activity_weaponset_creator">Weaponset Editor</string>
+    <string name="title_activity_scheme_list">User-defined Schemes</string>
+    <string name="title_activity_scheme_creator">Scheme Editor</string>
     
+    <string name="chat_hint">Type here to chat</string>
+
+    <!-- Map settings -->
+    <string name="map_gen">Map</string>
+    <string name="map_name">Name</string>
+    <string name="map_template">Type</string>
+    <string name="map_maze_size">Type</string>
+    <string name="map_mission_prefix">Mission: </string>
+    <string name="map_button_editdrawnmap">Edit drawn map</string>
+    <string-array name="map_types">
+        <item>Generated map</item>
+        <item>Generated maze</item>
+        <item>Hand-drawn map</item>
+        <item>Map file</item>
+    </string-array>
+    <string-array name="map_templates">
+        <item>Random</item>
+        <item>Small</item>
+        <item>Medium</item>
+        <item>Large</item>
+        <item>Cavern</item>
+        <item>Wacky</item>
+    </string-array>
+    <string-array name="map_maze_sizes">
+        <item>Small tunnels</item>
+        <item>Medium tunnels</item>
+        <item>Large tunnels</item>
+        <item>Small floating islands</item>
+        <item>Medium floating islands</item>
+        <item>Large floating islands</item>
+    </string-array>
+    
+    <!-- Player list -->
+    <string name="no_players_in_list">No players</string>
+    
+    <!-- Teamlist -->
+    <string name="teamlist_addteam">Add team</string>
+    <string name="teamlist_color_button_description">Team color</string>
+    <string name="teamlist_hogcount_button_description">Hog count</string>
+    <string name="no_teams_in_list">No teams</string>
+    <string name="edit_teams_menu">Edit Teams</string>
+    
+    <!-- Roomlist -->
+    <string name="roomlist_header_roomname">Room Name</string>
+    <string name="roomlist_header_clients">C</string>
+    <string name="roomlist_header_teams">T</string>
+    <string name="roomlist_header_owner">Owner</string>
+    <string name="roomlist_header_map">Map</string>
+    <string name="roomlist_header_scheme">Rules</string>
+    <string name="roomlist_header_weapons">Weapons</string>
+    <string name="no_rooms_in_list">No rooms</string>
+    
+    <string name="roomlist_owner">by %1$s</string>
+    <string name="roomlist_map">Map: %1$s</string>
+    <string name="roomlist_scheme">Scheme: %1$s</string>
+    <string name="map_regular">Random map</string>
+    <string name="map_maze">Random maze</string>
+    <string name="map_drawn">Drawn map</string>
+    
+    <!-- Chatlog messages -->
+    <string name="log_player_join">%1$s has joined.</string>
+    <string name="log_player_leave">%1$s has left.</string>
+    <string name="log_player_leave_with_msg">%1$s has left (%2$s).</string>
+    
+    <!-- Start netgame dialog -->
+    <string name="start_netgame_dialog_title">Connect</string>
+    <string name="start_netgame_dialog_message">Please select a username.</string>
+    <string name="start_netgame_dialog_playername_hint">Username</string>
+    
+    <string name="playerlist_contextmenu_kick">Kick</string>
+    <string name="lobby_playerlist_contextmenu_info">Info (shown in chat)</string>
+    <string name="lobby_playerlist_contextmenu_follow">Follow</string>
+    <string name="lobby_roomlistmenu_create">Create room</string>
+    <string name="lobby_roomlistmenu_refresh">Refresh</string>
+    <string name="lobby_menu_disconnect">Disconnect</string>
+    <string name="lobby_tab_rooms">Rooms</string>
+    <string name="lobby_tab_chat">Chat</string>
+    <string name="lobby_tab_players">Users</string>
+    
+    <string name="not_implemented_yet">Sorry, not implemented yet. :(</string>
+    
+    <!-- Errors -->
+    <string name="error_connection_failed">Unable to connect to the server.</string>
+    <string name="error_unexpected">An unexpected error has occurred: %1$s</string>
+    <string name="error_server_too_old">The server you tried to connect to is using an incompatible protocol.</string>
+    <string name="error_auth_failed">Unable to authenticate for your username.</string>
+    <string name="error_connection_lost">The connection to the server was lost.</string>
+    <string name="error_save_failed">Saving has failed.</string>
+    <string name="error_missing_sdcard_or_files">Error: Either the sdcard is not available, or files are missing from the Data directory.</string>
+    <string name="error_team_attribute_not_found">Error: This team uses assets which we do not have. Try downloading the big data package from the main menu.</string>
+    
+    <!-- Dialogs -->
+    <string name="dialog_connecting_title">Please wait</string>
+    <string name="dialog_connecting_message">Connecting to the server&#8230;</string>
+    <string name="dialog_password_title">Password required</string>
+    <string name="dialog_password_message">The server has requested a password to connect as "%1$s".</string>
+    <string name="dialog_password_hint">Password</string>
+    <string name="dialog_password_remember">remember password</string>
+    <string name="dialog_create_room_hint">Room name</string>
+    <string name="dialog_create_room_title">Create new room</string>
+    <string name="dialog_addteam_title">Add team</string>
+    
+    <string name="toast_disconnected">Disconnected: %1$s</string>
+    <string name="toast_room_abandoned">The room was closed because the owner left.</string>
+    <string name="toast_kicked">You were kicked from the room.</string>
+    
+    <!-- Weaponset editor -->
+    <string name="weaponsetlist_add_button_text">New Weaponset</string>
+    <string name="weaponsetlist_empty">No weaponsets</string>
+    <string name="edit_weaponsets_menu">Edit Weaponsets</string>
+    
+    <string name="schemelist_add_button_text">New Scheme</string>
+    
+    <!-- Room activity tabs -->
+    <string name="room_tab_map">Map</string>
+    <string name="room_tab_settings">Game</string>
+    <string name="room_tab_teams">Teams</string>
+    <string name="room_tab_chat">Chat</string>
+    <string name="room_tab_players">Users</string>
 </resources>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/BasicRoomState.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,161 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import static org.hedgewars.hedgeroid.util.ObjectUtils.equal;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.hedgewars.hedgeroid.RoomStateManager;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+/**
+ * Common base implementation for a roomstate that will call listeners on every
+ * change. The derived classes have to coordinate how state is changed to
+ * complete the implementation of the RoomStateManager interface.
+ * 
+ * See {@link RoomStateManager} for a description of what this is for.
+ */
+public abstract class BasicRoomState implements RoomStateManager {
+	private final List<RoomStateManager.Listener> observers = new LinkedList<RoomStateManager.Listener>();
+	
+	private boolean chief;
+	private String gameStyle;
+	private Scheme scheme;
+	private MapRecipe map;
+	private Weaponset weaponset;
+	private Map<String, TeamInGame> teams = Collections.emptyMap();
+	
+	public final MapRecipe getMapRecipe() {
+		return map;
+	}
+
+	public final boolean getChiefStatus() {
+		return chief;
+	}
+
+	public final Scheme getScheme() {
+		return scheme;
+	}
+
+	public final String getGameStyle() {
+		return gameStyle;
+	}
+
+	public final Weaponset getWeaponset() {
+		return weaponset;
+	}
+	
+	public final Map<String, TeamInGame> getTeams() {
+		return teams;
+	}
+	
+	public final void setWeaponset(Weaponset weaponset) {
+		if(!equal(weaponset, this.weaponset)) {
+			this.weaponset = weaponset;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onWeaponsetChanged(weaponset);
+			}
+		}
+	}
+	
+	public final void setMapRecipe(MapRecipe map) {
+		if(!equal(map, this.map)) { 
+			this.map = map;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onMapChanged(map);
+			}
+		}
+	}
+	
+	public final void setGameStyle(String gameStyle) {
+		if(!equal(gameStyle, this.gameStyle)) {
+			this.gameStyle = gameStyle;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onGameStyleChanged(gameStyle);
+			}
+		}
+	}
+	
+	public final void setScheme(Scheme scheme) {
+		if(!equal(scheme, this.scheme)) {
+			this.scheme = scheme;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onSchemeChanged(scheme);
+			}
+		}
+	}
+	
+	public final void setChief(boolean chief) {
+		if(chief != this.chief) {
+			this.chief = chief;
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onChiefStatusChanged(chief);
+			}
+		}
+	}
+	
+	public final void putTeam(TeamInGame team) {
+		TeamInGame oldEntry = teams.get(team.team.name);
+		if(!equal(team, oldEntry)) {
+			Map<String, TeamInGame> changedMap = new TreeMap<String, TeamInGame>(teams);
+			changedMap.put(team.team.name, team);
+			teams = Collections.unmodifiableMap(changedMap);
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onTeamsChanged(teams);
+			}
+		}
+	}
+	
+	public final void removeTeam(String teamname) {
+		if(teams.containsKey(teamname)) {
+			Map<String, TeamInGame> changedMap = new TreeMap<String, TeamInGame>(teams);
+			changedMap.remove(teamname);
+			teams = Collections.unmodifiableMap(changedMap);
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onTeamsChanged(teams);
+			}
+		}
+	}
+	
+	public final void setTeams(Map<String, TeamInGame> newTeams) {
+		if(!newTeams.equals(teams)) {
+			teams = Collections.unmodifiableMap(new TreeMap<String, TeamInGame>(newTeams));
+			for(RoomStateManager.Listener observer : observers) {
+				observer.onTeamsChanged(teams);
+			}
+		}
+	}
+	
+	public final void addListener(Listener observer) {
+		observers.add(observer);
+	}
+
+	public final void removeListener(Listener observer) {
+		observers.remove(observer);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,99 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.netplay.MessageLog;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+/**
+ * This fragment displays a chatlog and text input field for chatting in either
+ * the lobby or a room.
+ */
+public class ChatFragment extends Fragment {
+	private ChatlogAdapter adapter;
+	private Netplay netplay;
+	private MessageLog messageLog;
+	private boolean inRoom;
+	
+	public void setInRoom(boolean inRoom) {
+		this.inRoom = inRoom;
+	}
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+		adapter = new ChatlogAdapter(getActivity());
+	}
+	
+	@Override
+	public void onStart() {
+		super.onStart();
+		messageLog = inRoom ? netplay.roomChatlog : netplay.lobbyChatlog;
+    	adapter.setLog(messageLog.getLog());
+    	messageLog.addListener(adapter);
+	}
+	
+	@Override
+	public void onStop() {
+		super.onStop();
+		messageLog.removeListener(adapter);
+	}
+	
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		View view = inflater.inflate(R.layout.fragment_chat, container, false);
+		
+		ListView listView = (ListView) view.findViewById(R.id.chatConsole);
+		listView.setAdapter(adapter);
+		listView.setDivider(null);
+		listView.setDividerHeight(0);
+		listView.setVerticalFadingEdgeEnabled(true);
+		
+		EditText editText = (EditText) view.findViewById(R.id.chatInput);
+        editText.setOnEditorActionListener(new ChatSendListener());
+        
+		return view;
+	}
+	
+	private final class ChatSendListener implements OnEditorActionListener {
+		public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+			String text = v.getText().toString();
+			if(text.length()>0) {
+				v.setText("");
+				netplay.sendChat(text);
+			}
+			return true;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatlogAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,121 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.netplay.MessageLog;
+
+import android.content.Context;
+import android.text.method.LinkMovementMethod;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView.LayoutParams;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * Optimization: ListView is smart enough to try re-using the same view for an item
+ * with the same ID, but it still calls getView for those items when the list changes.
+ * Since lines with a given ID never change in our chatlog, we can avoid the effort
+ * of TextView.setText in many cases by checking if the view is already set up for the
+ * line with the right ID - but to do that, the view needs to remember the ID it's
+ * holding the text for. That's what the LoglineView does. 
+ */
+class LoglineView extends TextView {
+	long chatlogId = -1;
+	
+	public LoglineView(Context context) {
+		super(context);
+	}
+}
+
+/**
+ * For performance reasons, the chatlog is implemented as ListView instead of a
+ * single TextView (although I later learned that TextView might also have
+ * facilities for efficient appending with limited backlog... oh well, this
+ * works). Every chat line is a line in the ListView, and this adapter prepares
+ * the textviews from a messagelog in an efficient way.
+ */
+public class ChatlogAdapter extends BaseAdapter implements MessageLog.Listener {
+	long idOffset = 0;
+	private List<CharSequence> log = new ArrayList<CharSequence>();
+	private Context context;
+	
+	public ChatlogAdapter(Context context) {
+		this.context = context;
+	}
+	
+	public int getCount() {
+		return log.size();
+	}
+
+	public Object getItem(int position) {
+		return log.get(position);
+	}
+
+	public long getItemId(int position) {
+		return position+idOffset;
+	}
+
+	public boolean hasStableIds() {
+		return true;
+	}
+
+	public void clear() {
+		idOffset += log.size();
+		log.clear();
+		notifyDataSetChanged();
+	}
+	
+	public void lineAdded(CharSequence text) {
+		log.add(text);
+		notifyDataSetChanged();
+	}
+	
+	public void lineRemoved() {
+		log.remove(0);
+		idOffset += 1;
+		notifyDataSetChanged();
+	}
+	
+	public void setLog(Collection<CharSequence> log) {
+		idOffset += log.size();
+		this.log = new ArrayList<CharSequence>(log);
+		notifyDataSetChanged();
+	}
+	
+	public View getView(int position, View convertView, ViewGroup parent) {
+		LoglineView v = (LoglineView)convertView;
+		if (v == null) {
+			v = new LoglineView(context);
+			v.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
+			v.setMovementMethod(LinkMovementMethod.getInstance());
+		}
+		long id = getItemId(position);
+		if(id != v.chatlogId) {
+			v.setText(log.get(position));
+			v.chatlogId = id;
+		}
+		return v;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectingDialog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,94 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+import android.widget.Toast;
+
+/**
+ * Indeterminate progress dialog that is shown in the MainActivity while trying
+ * to connect to the server. If the connection fails (disconnect before we reach
+ * lobby state), an error toast with the disconnect message is shown.
+ * 
+ */
+public class ConnectingDialog extends ConnectionDependendDialogFragment {
+	@Override
+	public void onStart() {
+		super.onStart();
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).registerReceiver(connectedReceiver, new IntentFilter(Netplay.ACTION_CONNECTED));
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).registerReceiver(disconnectedReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
+		
+		if(Netplay.getAppInstance(getActivity().getApplicationContext()).getState() != State.CONNECTING) {
+			dismiss();
+		}
+	}
+	
+	@Override
+	public void onStop() {
+		super.onStop();
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).unregisterReceiver(connectedReceiver);
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).unregisterReceiver(disconnectedReceiver);
+	}
+	
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+		ProgressDialog dialog = new ProgressDialog(getActivity());
+		dialog.setIndeterminate(true);
+		dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+		dialog.setTitle(R.string.dialog_connecting_title);
+		dialog.setMessage(getString(R.string.dialog_connecting_message));
+		return dialog;
+	}
+	
+	private BroadcastReceiver connectedReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			Dialog dialog = getDialog();
+			if(dialog != null) {
+				dialog.dismiss();
+			} else {
+				dismiss();
+			}
+		}
+	};
+	
+	private BroadcastReceiver disconnectedReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			Toast.makeText(getActivity(), intent.getExtras().getString(Netplay.EXTRA_MESSAGE), Toast.LENGTH_LONG).show();
+		}
+	};
+	
+	public void onCancel(DialogInterface dialog) {
+		super.onCancel(dialog);
+		Netplay.getAppInstance(getActivity().getApplicationContext()).disconnect();
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ConnectionDependendDialogFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,65 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.content.LocalBroadcastManager;
+
+/**
+ * Helper class for DialogFragments that are supposed to be dismissed when the
+ * network connection is lost. This is used for some dialog fragments that
+ * appear during connecting (e.g. username input)
+ */
+public class ConnectionDependendDialogFragment extends DialogFragment {
+	@Override
+	public void onStart() {
+		super.onStart();
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).registerReceiver(dismissReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
+		if(Netplay.getAppInstance(getActivity().getApplicationContext()).getState() == State.NOT_CONNECTED) {
+			dismiss();
+		}
+	}
+	
+	@Override
+	public void onStop() {
+		super.onStop();
+		LocalBroadcastManager.getInstance(getActivity().getApplicationContext()).unregisterReceiver(dismissReceiver);
+	}
+	
+	private BroadcastReceiver dismissReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			Dialog dialog = getDialog();
+			if(dialog != null) {
+				dialog.dismiss();
+			} else {
+				dismiss();
+			}
+		}
+	};
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/FrontendDataUtils.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/FrontendDataUtils.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,12 @@
 /*
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,95 +15,89 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 package org.hedgewars.hedgeroid.Datastructures;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Utils;
-import org.hedgewars.hedgeroid.Datastructures.Map.MapType;
+import org.hedgewars.hedgeroid.util.FileUtils;
 
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import java.nio.ByteBuffer;
 
 public class FrontendDataUtils {
 
-
-	public static ArrayList<Map> getMaps(Context c){
-		File[] files = Utils.getFilesFromRelativeDir(c,"Maps");
-		ArrayList<Map> ret = new ArrayList<Map>();
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Maps directory doesn't exist
+	 */
+	public static List<MapFile> getMaps(Context c) throws FileNotFoundException {
+		File[] files = FileUtils.getFilesFromRelativeDir(c,"Maps");
+		List<MapFile> ret = new ArrayList<MapFile>();
 
-		for(File f : files){
-			if(Utils.hasFileWithSuffix(f, ".lua")){
-				ret.add(new Map(f,MapType.TYPE_MISSION, c));
-			}else{
-				ret.add(new Map(f, MapType.TYPE_DEFAULT,c));
-			}
+		for(File f : files) {
+			boolean isMission = FileUtils.hasFileWithSuffix(f, ".lua");
+			ret.add(new MapFile(f.getName(), isMission));
 		}
-		Collections.sort(ret);
 
 		return ret;
 	}
 
-	public static List<String> getGameplay(Context c){
-		String[] files = Utils.getFileNamesFromRelativeDir(c, "Scripts/Multiplayer");
-		ArrayList<String> ret = new ArrayList<String>();
-		
-		for(int i = 0; i < files.length; i++){
-			if(files[i].endsWith(".lua")){
-				ret.add(files[i].replace('_', ' ').substring(0, files[i].length()-4)); //replace _ by a space and removed the last four characters (.lua)
+	/**
+	 * Returns a list of all multiplayer scripts (game styles)
+	 * @throws FileNotFoundException if the sdcard isn't available or the Scripts/Multiplayer directory doesn't exist
+	 */
+	public static List<String> getGameStyles(Context c) throws FileNotFoundException {
+		File[] files = FileUtils.getFilesFromRelativeDir(c, "Scripts/Multiplayer");
+		List<String> ret = new ArrayList<String>();
+		/*
+		 * Caution: It is important that the "empty" style has this exact name, because
+		 * it will be interpreted as "don't load a script" by the frontlib, and also by
+		 * the QtFrontend in a netgame. This should probably be improved some time
+		 * (maybe TODO add a dummy script called "Normal" to the MP scripts?) 
+		 */
+		ret.add("Normal");
+		for(int i = 0; i < files.length; i++) {
+			String name = files[i].getName();
+			if(name.endsWith(".lua")){
+				//replace _ by a space and removed the last four characters (.lua)
+				ret.add(name.replace('_', ' ').substring(0, name.length()-4));
 			}
 		}
-		ret.add(0,"None");
-		Collections.sort(ret);
-		return ret;	
+		return ret;
 	}
 
-	public static List<String> getThemes(Context c){
-		List<String> list = Utils.getDirsWithFileSuffix(c, "Themes", "icon.png");
-		Collections.sort(list);
-		return list;
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Themes directory doesn't exist
+	 */
+	public static List<String> getThemes(Context c) throws FileNotFoundException {
+		return FileUtils.getDirsWithFileSuffix(c, "Themes", "icon.png");
 	}
 
-	public static List<Scheme> getSchemes(Context c){
-		List<Scheme> list = Scheme.getSchemes(c);
-		Collections.sort(list);
-		return list;
-	}
-
-	public static List<Weapon> getWeapons(Context c){
-		List<Weapon> list = Weapon.getWeapons(c);
-		Collections.sort(list);
-		return list;
-	}
-
-	public static ArrayList<HashMap<String, ?>> getGraves(Context c){
-		String pathPrefix = Utils.getDataPath(c) + "Graphics/Graves/";
-		ArrayList<String> names = Utils.getFilesFromDirWithSuffix(c,"Graphics/Graves", ".png", true);
-		ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(names.size());
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Graphics/Graves directory doesn't exist
+	 */
+	public static List<Map<String, ?>> getGraves(Context c) throws FileNotFoundException {
+		File gravePath = FileUtils.getDataPathFile(c, "Graphics", "Graves");
+		List<String> names = FileUtils.getFileNamesFromDirWithSuffix(c,"Graphics/Graves", ".png", true);
+		List<Map<String, ?>> data = new ArrayList<Map<String, ?>>(names.size());
 
 		for(String s : names){
 			HashMap<String, Object> map = new HashMap<String, Object>();
 			map.put("txt", s);
-			Bitmap b = BitmapFactory.decodeFile(pathPrefix + s + ".png");//create a full path - decode to to a bitmap
+			Bitmap b = BitmapFactory.decodeFile(new File(gravePath, s + ".png").getAbsolutePath());
 			int width = b.getWidth();
-			if(b.getHeight() > width){//some pictures contain more 'frames' underneath each other, if so we only use the first frame
-                                Bitmap tmp = Bitmap.createBitmap(width, width, b.getConfig());
-                                int[] pixels = new int[width * width];
-                                b.getPixels(pixels, 0,width,0,0,width,width);
-				tmp.setPixels(pixels,0,width,0,0,width,width);
-                                b.recycle();
-				b = tmp;
+			if(b.getHeight() > width){
+				// some pictures contain more 'frames' underneath each other, if so we only use the first frame
+				b = Bitmap.createBitmap(b, 0, 0, width, width);
 			}
 			map.put("img", b);
 			data.add(map);
@@ -109,24 +105,30 @@
 		return data;
 	}
 
-	public static ArrayList<HashMap<String, ?>> getFlags(Context c){
-		String pathPrefix = Utils.getDataPath(c) + "Graphics/Flags/";
-		ArrayList<String> names = Utils.getFilesFromDirWithSuffix(c, "Graphics/Flags", ".png", true);
-		ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(names.size());
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Graphics/Graves directory doesn't exist
+	 */
+	public static List<Map<String, ?>> getFlags(Context c) throws FileNotFoundException {
+		File flagsPath = FileUtils.getDataPathFile(c, "Graphics", "Flags");
+		List<String> names = FileUtils.getFileNamesFromDirWithSuffix(c, "Graphics/Flags", ".png", true);
+		List<Map<String, ?>> data = new ArrayList<Map<String, ?>>(names.size());
 
 		for(String s : names){
-			HashMap<String, Object> map = new HashMap<String, Object>();
+			Map<String, Object> map = new HashMap<String, Object>();
 			map.put("txt", s);
-			Bitmap b = BitmapFactory.decodeFile(pathPrefix + s + ".png");//create a full path - decode to to a bitmap
+			Bitmap b = BitmapFactory.decodeFile(new File(flagsPath, s + ".png").getAbsolutePath());
 			map.put("img", b);
 			data.add(map);
 		}
 		return data;
 	}
 
-	public static ArrayList<String> getVoices(Context c){
-		File[] files = Utils.getFilesFromRelativeDir(c, "Sounds/voices");
-		ArrayList<String> ret = new ArrayList<String>();
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Sounds/voices directory doesn't exist
+	 */
+	public static List<String> getVoices(Context c) throws FileNotFoundException {
+		File[] files = FileUtils.getFilesFromRelativeDir(c, "Sounds/voices");
+		List<String> ret = new ArrayList<String>();
 
 		for(File f : files){
 			if(f.isDirectory()) ret.add(f.getName());
@@ -134,35 +136,43 @@
 		return ret;
 	}
 
-	public static ArrayList<String> getForts(Context c){
-		return Utils.getFilesFromDirWithSuffix(c,"Forts", "L.png", true);
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Forts directory doesn't exist
+	 */
+	public static List<String> getForts(Context c) throws FileNotFoundException {
+		return FileUtils.getFileNamesFromDirWithSuffix(c,"Forts", "L.png", true);
 	}
-	public static ArrayList<HashMap<String, ?>> getTypes(Context c){
-		ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(6);
+	
+	public static List<Map<String, ?>> getTypes(Context c){
+		List<Map<String, ?>> data = new ArrayList<Map<String, ?>>(6);
 		String[] levels = {c.getString(R.string.human), c.getString(R.string.bot5), c.getString(R.string.bot4), c.getString(R.string.bot3), c.getString(R.string.bot2), c.getString(R.string.bot1)};
 		int[] images = {R.drawable.human, R.drawable.bot5, R.drawable.bot4, R.drawable.bot3, R.drawable.bot2, R.drawable.bot1};
 
 		for(int i = 0; i < levels.length; i++){
-			HashMap<String, Object> map = new HashMap<String, Object>();
+			Map<String, Object> map = new HashMap<String, Object>();
 			map.put("txt", levels[i]);
 			map.put("img", images[i]);
+			map.put("level", i);
+			
 			data.add(map);
 		}
 
 		return data;
 	}
 
-	public static ArrayList<HashMap<String, ?>> getHats(Context c){
-		ArrayList<String> files = Utils.getFilesFromDirWithSuffix(c,"Graphics/Hats", ".png", true);
-		String pathPrefix = Utils.getDataPath(c) + "Graphics/Hats/";
+	/**
+	 * @throws FileNotFoundException if the sdcard isn't available or the Graphics/Hats directory doesn't exist
+	 */
+	public static List<Map<String, ?>> getHats(Context c) throws FileNotFoundException {
+		List<String> files = FileUtils.getFileNamesFromDirWithSuffix(c,"Graphics/Hats", ".png", true);
+		File hatsPath = FileUtils.getDataPathFile(c, "Graphics", "Hats");
 		int size = files.size();
-		ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(size);
+		List<Map<String, ?>> data = new ArrayList<Map<String, ?>>(size);
 
-		HashMap<String, Object> hashmap; 
 		for(String s : files){
-			hashmap = new HashMap<String, Object>();
+			Map<String, Object> hashmap = new HashMap<String, Object>();
 			hashmap.put("txt", s);
-			Bitmap b = BitmapFactory.decodeFile(pathPrefix + s + ".png");//create a full path - decode to to a bitmap
+			Bitmap b = BitmapFactory.decodeFile(new File(hatsPath, s + ".png").getAbsolutePath());
 			b = Bitmap.createBitmap(b, 0,0,b.getWidth()/2, b.getWidth()/2);
 			hashmap.put("img", b);
 			data.add(hashmap);
@@ -171,50 +181,21 @@
 		return data;
 	}
 
-	public static List<HashMap<String, Object>> getTeams(Context c){
-		List<HashMap<String, Object>> ret = new ArrayList<HashMap<String, Object>>();
-
-		File teamsDir = new File(c.getFilesDir().getAbsolutePath() + '/' + Team.DIRECTORY_TEAMS);
+	public static List<Team> getTeams(Context c) {
+		List<Team> ret = new ArrayList<Team>();
+		
+		File teamsDir = new File(c.getFilesDir(), Team.DIRECTORY_TEAMS);
 		File[] teamFileNames = teamsDir.listFiles();
 		if(teamFileNames != null){
-			for(File s : teamFileNames){
-				Team t = Team.getTeamFromXml(s.getAbsolutePath());
-				if(t != null){
-					t.file = s.getName();
-					ret.add(teamToMap(t));
+			for(File file : teamFileNames){
+				if(file.getName().endsWith(".hwt")) {
+					Team team = Team.load(file);
+					if(team != null){
+						ret.add(team);
+					}
 				}
 			}
 		}
 		return ret;
 	}
-
-	public static HashMap<String, Object> teamToMap(Team t){
-		HashMap<String, Object> hashmap = new HashMap<String, Object>();
-		hashmap.put("team", t);
-		hashmap.put("txt", t.name);
-		hashmap.put("color", t.color);
-		hashmap.put("count", t.hogCount);
-		switch(t.levels[0]){
-		case 0:
-			hashmap.put("img", R.drawable.human);
-			break;
-		case 1:
-			hashmap.put("img", R.drawable.bot5);
-			break;
-		case 2:
-			hashmap.put("img", R.drawable.bot4);
-			break;
-		case 3:
-			hashmap.put("img", R.drawable.bot3);
-			break;
-		case 4:
-			hashmap.put("img", R.drawable.bot2);
-			break;
-		default:
-		case 5:
-			hashmap.put("img", R.drawable.bot1);
-			break;
-		}
-		return hashmap;
-	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/GameConfig.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,62 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * Game configuration from the point of view of the UI. This differs slightly from the
+ * frontlib view, because the engine allows setting a separate initial health and weapon set
+ * for each hog, while the Android UI currently only supports both attributes on a per-game
+ * basis (initial health is contained in the scheme).
+ * 
+ * This difference means that creating a GameConfig object from a frontlib object can, in
+ * theory, lose information. This does not cause problems at the moment because for now
+ * weaponset and initial health are always per-game, but that might change in the future.
+ */
+public final class GameConfig {
+	public static final String DEFAULT_STYLE = "Normal";
+	public static final String DEFAULT_SCHEME = "Default";
+	public static final String DEFAULT_WEAPONSET = "Default";
+	public static final String DEFAULT_THEME = "Bamboo";
+	
+	public final String style;
+	public final Scheme scheme;
+	public final MapRecipe map;
+	public final List<TeamInGame> teams;
+	public final Weaponset weaponset;
+	
+	public GameConfig(String style, Scheme scheme, MapRecipe map, List<TeamInGame> teams, Weaponset weaponset) {
+		this.style = style;
+		this.scheme = scheme;
+		this.map = map;
+		this.teams = Collections.unmodifiableList(new ArrayList<TeamInGame>(teams));
+		this.weaponset = weaponset;
+	}
+
+	@Override
+	public String toString() {
+		return "GameConfig [style=" + style + ", scheme=" + scheme + ", map="
+				+ map + ", teams=" + teams + ", weaponset=" + weaponset + "]";
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/GameMode.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-
-package org.hedgewars.hedgeroid.Datastructures;
-
-public enum GameMode {
-		MODE_LOCAL, MODE_DEMO, MODE_NET, MODE_SAVE
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Grave.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-
-package org.hedgewars.hedgeroid.Datastructures;
-
-public class Grave{
-
-	public final String name;
-	public final String path;
-	
-	public Grave(String _name, String _path) {
-		name = _name;
-		path = _path;
-	}
-
-	public String toString(){
-		return name;
-	}
-	
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Hog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,36 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+public final class Hog {
+	public final String name, hat;
+	public final int level;
+	
+	public Hog(String name, String hat, int level) {
+		this.name = name;
+		this.hat = hat;
+		this.level = level;
+	}
+
+	@Override
+	public String toString() {
+		return "Hog [name=" + name + ", hat=" + hat + ", level=" + level + "]";
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Map.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-package org.hedgewars.hedgeroid.Datastructures;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
-
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class Map implements Comparable<Map>, Parcelable{
-
-	private static final String MISSION_PREFIX = "Mission: ";
-
-	private String name;
-	private String path;
-	private String previewPath;
-	private MapType type;
-
-	public Map(File mapDir, MapType _type, Context c){
-		type = _type;
-
-		name = mapDir.getName();
-		path = mapDir.getAbsolutePath();
-		previewPath = path + "/preview.png";
-		
-		/*switch(type){
-		case TYPE_DEFAULT:
-			
-			break;
-		case TYPE_GENERATED:
-			//TODO
-			break;
-		case TYPE_MISSION:
-			name = MISSION_PREFIX + mapDir.getName();
-			path = mapDir.getAbsolutePath();
-			break;
-		}*/
-
-		
-	}
-	
-	public Map(Parcel in){
-		readFromParcel(in);
-	}
-
-	public String toString(){
-		switch(type){
-		default:
-		case TYPE_DEFAULT:
-			return name;
-		case TYPE_GENERATED:
-			return "bla";
-		case TYPE_MISSION:
-			return MISSION_PREFIX + name;
-		}
-	}
-	
-	public void sendToEngine(EngineProtocolNetwork epn) throws IOException{
-		epn.sendToEngine(String.format("emap %s",name));
-	}
-	
-	public MapType getType(){
-		return type;
-	}
-
-	public Drawable getDrawable(){
-		switch(type){
-		case TYPE_MISSION:
-		case TYPE_DEFAULT:
-			return Drawable.createFromPath(previewPath);
-		case TYPE_GENERATED:
-
-		default:
-			return null;
-		}
-	}
-
-	public int compareTo(Map another) {
-		switch(type){
-		case TYPE_GENERATED:
-			switch(another.getType()){
-			case TYPE_GENERATED:
-				return name.compareTo(another.name);
-			case TYPE_MISSION:
-				return -1;
-			case TYPE_DEFAULT:
-				return -1;
-			}
-		case TYPE_MISSION:
-			switch(another.getType()){
-			case TYPE_GENERATED:
-				return 1;
-			case TYPE_MISSION:
-				return name.compareTo(another.name);
-			case TYPE_DEFAULT:
-				return -1;
-			}
-		case TYPE_DEFAULT:
-			switch(another.getType()){
-			case TYPE_GENERATED:
-				return 1;
-			case TYPE_MISSION:
-				return 1;
-			case TYPE_DEFAULT:
-				return name.compareTo(another.name);
-			}
-		}
-		return 0;//default case this should never happen
-	}
-
-	public enum MapType{
-		TYPE_DEFAULT, TYPE_MISSION, TYPE_GENERATED
-	}
-
-	public int describeContents() {
-		return 0;
-	}
-	
-	public void writeToParcel(Parcel dest, int flags) {
-		dest.writeString(name);
-		dest.writeString(path);
-		dest.writeString(previewPath);
-		dest.writeString(type.name());
-	}
-	
-	private void readFromParcel(Parcel src){
-		name = src.readString();
-		path = src.readString();
-		previewPath = src.readString();
-		type = MapType.valueOf(src.readString());
-	}
-	public static final Parcelable.Creator<Map> CREATOR = new Parcelable.Creator<Map>() {
-		public Map createFromParcel(Parcel source) {
-			return new Map(source);
-		}
-		public Map[] newArray(int size) {
-			return new Map[size];
-		}
-		
-	};
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MapFile.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,86 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.util.FileUtils;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+/**
+ * Represents a map from the data directory
+ */
+public final class MapFile {
+	public static final String MAP_DIRECTORY = "Maps";
+	
+	public final String name;
+	public final boolean isMission;
+	
+	public MapFile(String name, boolean isMission) {
+		this.name = name;
+		this.isMission = isMission;
+	}
+	
+	/**
+	 * @throws FileNotFoundException if the sdcard is not available. Does NOT throw if the requested map file does not exist.
+	 */
+	public static File getFileForMapname(Context ctx, String mapname) throws FileNotFoundException {
+		return FileUtils.getDataPathFile(ctx, MAP_DIRECTORY, mapname);
+	}
+	
+	public static final Comparator<MapFile> MISSIONS_FIRST_NAME_ORDER = new Comparator<MapFile>() {
+		public int compare(MapFile lhs, MapFile rhs) {
+			if(lhs.isMission != rhs.isMission) {
+				return lhs.isMission && !rhs.isMission ? -1 : 1;
+			} else {
+				return lhs.name.compareToIgnoreCase(rhs.name);
+			}
+		}
+	};
+	
+	@Override
+	public String toString() {
+		return "MapFile [name=" + name + ", isMission=" + isMission + "]";
+	}
+
+	public File getPreviewFile(Context c) throws FileNotFoundException {
+		return getPreviewFile(c, name);
+	}
+	
+	public static File getPreviewFile(Context c, String mapName) throws FileNotFoundException {
+		return FileUtils.getDataPathFile(c, MAP_DIRECTORY, mapName, "preview.png");
+	}
+	
+	public static List<String> toDisplayNameList(List<MapFile> mapFiles, Resources res) {
+		String missionPrefix = res.getString(R.string.map_mission_prefix);
+		List<String> result = new ArrayList<String>();
+		for(MapFile mapFile : mapFiles) {
+			result.add((mapFile.isMission ? missionPrefix : "") + mapFile.name);
+		}
+		return result;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MapRecipe.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,203 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.Arrays;
+import java.util.UUID;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+
+import android.content.res.Resources;
+
+public final class MapRecipe {
+	public static final String MAPNAME_REGULAR = "+rnd+";
+	public static final String MAPNAME_MAZE = "+maze+";
+	public static final String MAPNAME_DRAWN = "+drawn+";
+
+	public final int mapgen;			// Frontlib.MAPGEN_xxx
+	public final int templateFilter;	// Frontlib.TEMPLATEFILTER_xxx, only used when mapgen==MAPGEN_REGULAR
+	public final int mazeSize;			// Frontlib.MAZE_SIZE_xxx, only used when mapgen==MAPGEN_MAZE
+	public final String name, seed, theme;
+	
+	private final byte[] drawData;		// For drawn maps, can be null.
+
+	public MapRecipe(int mapgen, int templateFilter, int mazeSize, String name, String seed, String theme, byte[] drawData) {
+		this.mapgen = mapgen;
+		this.templateFilter = templateFilter;
+		this.mazeSize = mazeSize;
+		this.name = name;
+		this.seed = seed;
+		this.theme = theme;
+		this.drawData = drawData==null ? null : drawData.clone();
+	}
+	
+	public static MapRecipe makeMap(String name, String seed, String theme) {
+		return new MapRecipe(Frontlib.MAPGEN_NAMED, 0, 0, name, seed, theme, null);
+	}
+	
+	public static MapRecipe makeRandomMap(int templateFilter, String seed, String theme) {
+		return new MapRecipe(Frontlib.MAPGEN_REGULAR, templateFilter, 0, MAPNAME_REGULAR, seed, theme, null);
+	}
+	
+	public static MapRecipe makeRandomMaze(int mazeSize, String seed, String theme) {
+		return new MapRecipe(Frontlib.MAPGEN_MAZE, 0, mazeSize, MAPNAME_MAZE, seed, theme, null);
+	}
+	
+	public static MapRecipe makeDrawnMap(String seed, String theme, byte[] drawData) {
+		return new MapRecipe(Frontlib.MAPGEN_DRAWN, 0, 0, MAPNAME_DRAWN, seed, theme, drawData);
+	}
+	
+	public byte[] getDrawData() {
+		return drawData==null ? null : drawData.clone();
+	}
+	
+	public MapRecipe withMapgen(int mapgen) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public MapRecipe withTemplateFilter(int templateFilter) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public MapRecipe withMazeSize(int mazeSize) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public MapRecipe withName(String name) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public MapRecipe withSeed(String seed) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public MapRecipe withTheme(String theme) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public MapRecipe withDrawData(byte[] drawData) {
+		return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+	}
+	
+	public static String formatMapName(Resources res, String map) {
+		if(map.charAt(0)=='+') {
+			if(map.equals(MAPNAME_REGULAR)) {
+				return res.getString(R.string.map_regular);
+			} else if(map.equals(MAPNAME_MAZE)) {
+				return res.getString(R.string.map_maze);
+			} else if(map.equals(MAPNAME_DRAWN)) {
+				return res.getString(R.string.map_drawn);
+			}
+		}
+		return map;
+	}
+
+	/**
+	 * Returns the mapname corresponding to the map generator (e.g. "+rnd+" for regular maps)
+	 * If the mapgen does not have a unique name (MAPGEN_NAMED) or is not known, the def
+	 * value is returned.
+	 */
+	public static String mapnameForGenerator(int mapgen, String def) {
+		switch(mapgen) {
+		case Frontlib.MAPGEN_REGULAR: return MAPNAME_REGULAR;
+		case Frontlib.MAPGEN_MAZE: return MAPNAME_MAZE;
+		case Frontlib.MAPGEN_DRAWN: return MAPNAME_DRAWN;
+		default: return def;
+		}
+	}
+	
+	/**
+	 * In a sense this is the inverse of mapnameForGenerator. Returns the mapgen that uses
+	 * mapName as special identifier, or MAPGEN_NAMED if there is none.
+	 */
+	public static int generatorForMapname(String mapName) {
+		if(MapRecipe.MAPNAME_REGULAR.equals(mapName)) {
+			return Frontlib.MAPGEN_REGULAR;
+		} else if(MapRecipe.MAPNAME_MAZE.equals(mapName)) {
+			return Frontlib.MAPGEN_MAZE;
+		} else if(MapRecipe.MAPNAME_DRAWN.equals(mapName)) {
+			return Frontlib.MAPGEN_DRAWN;
+		} else {
+			return Frontlib.MAPGEN_NAMED;
+		}
+	}
+	
+	@Override
+	public String toString() {
+		return "MapRecipe [mapgen=" + mapgen + ", templateFilter="
+				+ templateFilter + ", mazeSize=" + mazeSize + ", name=" + name
+				+ ", seed=" + seed + ", theme=" + theme + ", drawData="
+				+ Arrays.toString(drawData) + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + Arrays.hashCode(drawData);
+		result = prime * result + mapgen;
+		result = prime * result + mazeSize;
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		result = prime * result + ((seed == null) ? 0 : seed.hashCode());
+		result = prime * result + templateFilter;
+		result = prime * result + ((theme == null) ? 0 : theme.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		MapRecipe other = (MapRecipe) obj;
+		if (!Arrays.equals(drawData, other.drawData))
+			return false;
+		if (mapgen != other.mapgen)
+			return false;
+		if (mazeSize != other.mazeSize)
+			return false;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		if (seed == null) {
+			if (other.seed != null)
+				return false;
+		} else if (!seed.equals(other.seed))
+			return false;
+		if (templateFilter != other.templateFilter)
+			return false;
+		if (theme == null) {
+			if (other.theme != null)
+				return false;
+		} else if (!theme.equals(other.theme))
+			return false;
+		return true;
+	}
+
+	public static String makeRandomSeed() {
+		return "{"+UUID.randomUUID().toString()+"}";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MetaScheme.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,82 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.frontlib.Flib;
+
+public final class MetaScheme {
+	public static final MetaScheme INSTANCE = Flib.INSTANCE.flib_get_metascheme().deref();
+	
+	public static final class Mod {
+		public final String name;
+		public final int bitmaskIndex;
+		
+		public Mod(String name, int bitmaskIndex) {
+			this.name = name;
+			this.bitmaskIndex = bitmaskIndex;
+		}
+
+		@Override
+		public String toString() {
+			return "MetaScheme$Mod [name=" + name + ", bitmaskIndex=" + bitmaskIndex + "]";
+		}
+	}
+	
+	public static final class Setting {
+		public final String name, engineCommand;
+		public final boolean maxMeansInfinity, times1000;
+		public final int min, max, def;
+		
+		public Setting(String name, String engineCommand, boolean maxMeansInfinity, boolean times1000, int min, int max, int def) {
+			this.name = name;
+			this.engineCommand = engineCommand;
+			this.maxMeansInfinity = maxMeansInfinity;
+			this.times1000 = times1000;
+			this.min = min;
+			this.max = max;
+			this.def = def;
+		}
+
+		@Override
+		public String toString() {
+			return "MetaScheme$Setting [name=" + name + ", engineCommand=" + engineCommand
+					+ ", maxMeansInfinite=" + maxMeansInfinity + ", times1000="
+					+ times1000 + ", min=" + min + ", max=" + max + ", def="
+					+ def + "]";
+		}
+	}
+	
+	public final List<Mod> mods;
+	public final List<Setting> settings;
+	
+	public MetaScheme(List<Mod> mods, List<Setting> settings) {
+		this.mods = Collections.unmodifiableList(new ArrayList<Mod>(mods));
+		this.settings = Collections.unmodifiableList(new ArrayList<Setting>(settings));
+	}
+
+	@Override
+	public String toString() {
+		return "MetaScheme [\nmods=" + mods + ", \nsettings=" + settings + "\n]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Player.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,52 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.Comparator;
+
+/**
+ * Basic information about a player on a server.
+ */
+public final class Player {
+	public final String name;
+	public final boolean registered, admin;
+	
+	public Player(String name, boolean registered, boolean admin) {
+		this.name = name;
+		this.registered = registered;
+		this.admin = admin;
+	}
+
+	@Override
+	public String toString() {
+		return "Player [name=" + name + ", registered=" + registered
+				+ ", admin=" + admin + "]";
+	}
+
+	public static Comparator<Player> ADMIN_NAME_ORDER = new Comparator<Player>() {
+		public int compare(Player lhs, Player rhs) {
+			if(lhs.admin != rhs.admin) {
+				return lhs.admin ? -1 : 1;
+			} else {
+				return lhs.name.compareToIgnoreCase(rhs.name);
+			}
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/PlayerInRoom.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,37 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+public final class PlayerInRoom {
+	public final Player player;
+	public final boolean ready, roomChief;
+	
+	public PlayerInRoom(Player player, boolean ready, boolean roomChief) {
+		this.player = player;
+		this.ready = ready;
+		this.roomChief = roomChief;
+	}
+
+	@Override
+	public String toString() {
+		return "PlayerInRoom [player=" + player + ", ready=" + ready
+				+ ", roomChief=" + roomChief + "]";
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Room.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,55 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import android.content.res.Resources;
+
+/**
+ * A room as presented in the roomlist in a server lobby.
+ */
+public final class Room {
+	public final String name, map, scheme, weapons, owner;
+	public final int playerCount, teamCount;
+	public final boolean inProgress;
+	
+	public Room(String name, String map, String scheme, String weapons,
+			String owner, int playerCount, int teamCount, boolean inProgress) {
+		this.name = name;
+		this.map = map;
+		this.scheme = scheme;
+		this.weapons = weapons;
+		this.owner = owner;
+		this.playerCount = playerCount;
+		this.teamCount = teamCount;
+		this.inProgress = inProgress;
+	}
+	
+	public String formatMapName(Resources res) {
+		return MapRecipe.formatMapName(res, map);
+	}
+
+	@Override
+	public String toString() {
+		return "RoomlistRoom [name=" + name + ", map=" + map + ", scheme="
+				+ scheme + ", weapons=" + weapons + ", owner=" + owner
+				+ ", playerCount=" + playerCount + ", teamCount=" + teamCount
+				+ ", inProgress=" + inProgress + "]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/RoomWithId.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,43 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.Comparator;
+
+public final class RoomWithId {
+	public final Room room;
+	public final long id;
+	
+	public RoomWithId(Room room, long id) {
+		this.room = room;
+		this.id = id;
+	}
+
+	@Override
+	public String toString() {
+		return "RoomWithId [room=" + room + ", id=" + id + "]";
+	}
+	
+	public static final Comparator<RoomWithId> NEWEST_FIRST_ORDER = new Comparator<RoomWithId>() {
+		public int compare(RoomWithId lhs, RoomWithId rhs) {
+			return rhs.id<lhs.id ? -1 : rhs.id>lhs.id ? 1 : 0;
+		}
+	};
+}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,11 @@
 /*
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,356 +14,93 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 package org.hedgewars.hedgeroid.Datastructures;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-
-import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
 
-import android.content.Context;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class Scheme implements Parcelable, Comparable<Scheme>{
-
-	public static final String DIRECTORY_SCHEME = "schemes";
-
-	private String name;
-	//private ArrayList<Integer> basic;
-	private Integer gamemod;
-	private ArrayList<Integer> basic;;
-	private static ArrayList<LinkedHashMap<String, ?>> basicflags = new ArrayList<LinkedHashMap<String, ?>>();//TODO why is it static?
-	public int health;
-	
-	public Scheme(String _name, ArrayList<Integer> _basic, int _gamemod){
-		name = _name;
-		gamemod = _gamemod;
-		basic = _basic;
+public final class Scheme {
+	public final String name;
+	public final Map<String, Integer> settings;
+	public final Map<String, Boolean> mods;
+		
+	public Scheme(String name, Map<String, Integer> settings, Map<String, Boolean> mods) {
+		this.name = name;
+		this.settings = Collections.unmodifiableMap(new HashMap<String, Integer>(settings));
+		this.mods = Collections.unmodifiableMap(new HashMap<String, Boolean>(mods));
 	}
 	
-	public Scheme(Parcel in){
-		readFromParcel(in);
-	}
-
-	public void sendToEngine(EngineProtocolNetwork epn)throws IOException{ 
-		epn.sendToEngine(String.format("e$gmflags %d", gamemod));
-
-		for(int pos = 0; pos < basic.size(); pos++){
-			LinkedHashMap<String, ?> basicflag = basicflags.get(pos);
-			
-			String command = (String)basicflag.get("command");
-			Integer value = basic.get(pos);
-			
-			if(command.equals("inithealth")){//Health is a special case, it doesn't need to be send 				                             
-				health = value;              //to the engine yet, we'll do that with the other HH info
-				continue;
-			}
-			
-			Boolean checkOverMax = (Boolean) basicflag.get("checkOverMax");
-			Boolean times1000 = (Boolean) basicflag.get("times1000");
-			Integer max = (Integer) basicflag.get("max");
-			
-			if(checkOverMax && value >= max) value = max;
-			if(times1000) value *= 1000;
-			
-			epn.sendToEngine(String.format("%s %d", command, value));
-		}
-	}
-	public String toString(){
-		return name;
+	public int getHealth() {
+		Integer health = settings.get("health");
+		return health==null ? 100 : health.intValue();
 	}
 
-
-	public static final int STATE_START = 0;
-	public static final int STATE_ROOT = 1;
-	public static final int STATE_NAME = 2;
-	public static final int STATE_BASICFLAGS = 3;
-	public static final int STATE_GAMEMOD = 4;
-	public static final int STATE_BASICFLAG_INTEGER = 5;
-	public static final int STATE_GAMEMOD_TRUE = 6;
-	public static final int STATE_GAMEMOD_FALSE = 7;
-
-	public static ArrayList<Scheme> getSchemes(Context c) throws IllegalArgumentException{
-		String dir = c.getFilesDir().getAbsolutePath() + '/' + DIRECTORY_SCHEME + '/';
-		String[] files = new File(dir).list(fnf);
-		if(files == null) files = new String[]{};
-		Arrays.sort(files);
-		ArrayList<Scheme> schemes = new ArrayList<Scheme>();
-
-		try {
-			XmlPullParserFactory xmlPullFactory = XmlPullParserFactory.newInstance();
-			XmlPullParser xmlPuller = xmlPullFactory.newPullParser();
-
-			for(String file : files){
-				BufferedReader br = new BufferedReader(new FileReader(dir + file), 1024);
-				xmlPuller.setInput(br);
-				String name = null;
-				ArrayList<Integer> basic = new ArrayList<Integer>();
-				Integer gamemod = 0;
-				int health = 0;
-				int mask = 0x000000004;
-
-				int eventType = xmlPuller.getEventType();
-				int state = STATE_START;
-				while(eventType != XmlPullParser.END_DOCUMENT){
-					switch(state){
-					case STATE_START:
-						if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().equals("scheme")) state = STATE_ROOT;
-						else if(eventType != XmlPullParser.START_DOCUMENT) throwException(file, eventType);
-						break;
-					case STATE_ROOT:
-						if(eventType == XmlPullParser.START_TAG){
-							if(xmlPuller.getName().equals("basicflags")) state = STATE_BASICFLAGS;
-							else if(xmlPuller.getName().toLowerCase().equals("gamemod")) state = STATE_GAMEMOD;
-							else if(xmlPuller.getName().toLowerCase().equals("name")) state = STATE_NAME;
-							else throwException(file, eventType);
-						}else if(eventType == XmlPullParser.END_TAG) state = STATE_START;
-						else throwException(xmlPuller.getText(), eventType);
-						break;
-					case STATE_BASICFLAGS:
-						if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().toLowerCase().equals("integer")) state = STATE_BASICFLAG_INTEGER;
-						else if(eventType == XmlPullParser.END_TAG)	state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_GAMEMOD:
-						if(eventType == XmlPullParser.START_TAG){
-							if(xmlPuller.getName().toLowerCase().equals("true")) state = STATE_GAMEMOD_TRUE;
-							else if(xmlPuller.getName().toLowerCase().equals("false")) state = STATE_GAMEMOD_FALSE;
-							else throwException(file, eventType);
-						}else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_NAME:
-						if(eventType == XmlPullParser.TEXT) name = xmlPuller.getText().trim();
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_BASICFLAG_INTEGER:
-						if(eventType == XmlPullParser.TEXT) basic.add(Integer.parseInt(xmlPuller.getText().trim()));
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_BASICFLAGS;
-						else throwException(file, eventType);
-						break;
-					case STATE_GAMEMOD_FALSE:
-						if(eventType == XmlPullParser.TEXT) gamemod <<= 1;
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_GAMEMOD;
-						else throwException(file, eventType);
-						break;
-					case STATE_GAMEMOD_TRUE:
-						if(eventType == XmlPullParser.TEXT){
-							gamemod |= mask;
-							gamemod <<= 1;
-						}else if(eventType == XmlPullParser.END_TAG) state = STATE_GAMEMOD;
-						else throwException(file, eventType);
-						break;
-					}
-					eventType = getEventType(xmlPuller);
-				}//end while(eventtype != END_DOCUMENT
-				schemes.add(new Scheme(name, basic, gamemod));
-			}//end for(string file : files
-			return schemes;
-		} catch (XmlPullParserException e) {
-			e.printStackTrace();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
+	public static Scheme createDefaultScheme(MetaScheme meta) {
+		String name = GameConfig.DEFAULT_SCHEME;
+		Map<String, Integer> settings = new TreeMap<String, Integer>();
+		Map<String, Boolean> mods = new TreeMap<String, Boolean>();
+		for(MetaScheme.Setting setting : meta.settings) {
+			settings.put(setting.name, setting.def);
 		}
-		return new ArrayList<Scheme>();//TODO handle correctly
+		for(MetaScheme.Mod mod : meta.mods) {
+			mods.put(mod.name, Boolean.FALSE);
+		}
+		return new Scheme(name, settings, mods);
+	}
+	
+	@Override
+	public String toString() {
+		return "Scheme [name=" + name + ", settings=" + settings + ", mods="
+				+ mods + "]";
 	}
 	
-	private static FilenameFilter fnf = new FilenameFilter(){
-		public boolean accept(File dir, String filename) {
-			return filename.toLowerCase().startsWith("scheme_");
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		result = prime * result + ((mods == null) ? 0 : mods.hashCode());
+		result = prime * result
+				+ ((settings == null) ? 0 : settings.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Scheme other = (Scheme) obj;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		if (mods == null) {
+			if (other.mods != null)
+				return false;
+		} else if (!mods.equals(other.mods))
+			return false;
+		if (settings == null) {
+			if (other.settings != null)
+				return false;
+		} else if (!settings.equals(other.settings))
+			return false;
+		return true;
+	}
+
+	public static final Comparator<Scheme> NAME_ORDER = new Comparator<Scheme>() {
+		public int compare(Scheme lhs, Scheme rhs) {
+			return String.CASE_INSENSITIVE_ORDER.compare(lhs.name, rhs.name);
 		}
 	};
-
-	/**
-	 * This method will parse the basic flags from a prespecified xml file.
-	 * I use a raw xml file rather than one parsed by aatp at compile time
-	 * to keep it generic with other frontends, ie in the future we could 
-	 * use one provided by the Data folder.
-	 */
-	public static void parseBasicFlags(Context c){
-		String filename = String.format("%s/%s/basicflags", c.getFilesDir().getAbsolutePath(), DIRECTORY_SCHEME);
-
-		XmlPullParser xmlPuller = null;
-		BufferedReader br = null;
-		try {
-			XmlPullParserFactory xmlPullFactory = XmlPullParserFactory.newInstance();
-			xmlPuller = xmlPullFactory.newPullParser();
-			br = new BufferedReader(new FileReader(filename), 1024);
-			xmlPuller.setInput(br);
-
-			int eventType = getEventType(xmlPuller);
-			boolean continueParsing = true;
-			do{
-				switch(eventType){
-				
-				case XmlPullParser.START_TAG:
-					if(xmlPuller.getName().toLowerCase().equals("flag")){
-						basicflags.add(parseFlag(xmlPuller));
-					}else if(xmlPuller.getName().toLowerCase().equals("basicflags")){
-						eventType = getEventType(xmlPuller);
-					}else{
-						skipCurrentTag(xmlPuller);
-						eventType = getEventType(xmlPuller);
-					}
-					break;
-				case XmlPullParser.START_DOCUMENT://ignore all tags not being "flag"
-				case XmlPullParser.END_TAG:
-				case XmlPullParser.TEXT:
-				default:
-					continueParsing = true;
-				case XmlPullParser.END_DOCUMENT:
-					continueParsing = false;
-				}
-			}while(continueParsing);
-
-		}catch(IOException e){
-			e.printStackTrace();
-		}catch (XmlPullParserException e) {
-			e.printStackTrace();
-		}finally{
-			if(br != null)
-				try {
-					br.close();
-				} catch (IOException e) {}
-		}
-
-	}
-
-	/*
-	 * * Parses a Tag structure from xml as example we use
-	 *<flag>
-	 *   <checkOverMax>
-	 *       <boolean>false</boolean>
-	 *   </checkOverMax>
-	 *</flag>
-	 *
-	 * It returns a LinkedHashMap with key/value pairs
-	 */
-	private static LinkedHashMap<String, Object> parseFlag(XmlPullParser xmlPuller)throws XmlPullParserException, IOException{
-		LinkedHashMap<String, Object> hash = new LinkedHashMap<String, Object>();
-
-		int eventType = xmlPuller.getEventType();//Get the event type which triggered this method
-		if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().toLowerCase().equals("flag")){//valid start of flag tag
-			String lcKey = null;
-			String lcType = null;
-			String value = null;
-
-			eventType = getEventType(xmlPuller);//<checkOverMax>
-			while(eventType == XmlPullParser.START_TAG){
-				lcKey = xmlPuller.getName();//checkOverMax
-				if(getEventType(xmlPuller) == XmlPullParser.START_TAG){//<boolean>
-					lcType = xmlPuller.getName().toLowerCase();
-					if(getEventType(xmlPuller) == XmlPullParser.TEXT){
-						value = xmlPuller.getText();
-						if(getEventType(xmlPuller) == XmlPullParser.END_TAG && //</boolean> 
-								getEventType(xmlPuller) == XmlPullParser.END_TAG){//</checkOverMax>
-							if(lcType.equals("boolean")) hash.put(lcKey, new Boolean(value));
-							else if(lcType.equals("string"))hash.put(lcKey, value);							
-							else if(lcType.equals("integer")){
-								try{
-									hash.put(lcKey, new Integer(value));
-								}catch (NumberFormatException e){
-									throw new XmlPullParserException("Wrong integer value in xml file");
-								}
-							}else{
-								throwException("basicflags", eventType);
-							}
-						}//</boolean> / </checkOverMax>
-					}//if TEXT
-				}//if boolean
-				eventType = getEventType(xmlPuller);//start new loop
-			}
-			eventType = getEventType(xmlPuller);//</flag>
-		}
-
-		return hash;
-	}
-
-	private static void skipCurrentTag(XmlPullParser xmlPuller) throws XmlPullParserException, IOException{
-		int eventType = xmlPuller.getEventType();
-		if(eventType != XmlPullParser.START_TAG)return;
-		String tag = xmlPuller.getName().toLowerCase();
-
-		while(true){
-			eventType = getEventType(xmlPuller);//getNext()
-			switch(eventType){
-			case XmlPullParser.START_DOCUMENT://we're inside of a start tag so START_ or END_DOCUMENT is just wrong
-			case XmlPullParser.END_DOCUMENT:
-				throw new XmlPullParserException("invalid xml file");
-			case XmlPullParser.START_TAG://if we get a new tag recursively handle it
-				skipCurrentTag(xmlPuller);
-				break;
-			case XmlPullParser.TEXT:
-				break;
-			case XmlPullParser.END_TAG:
-				if(!xmlPuller.getName().toLowerCase().equals(tag)){//if the end tag doesn't match the start tag
-					throw new XmlPullParserException("invalid xml file");
-				}else{
-					return;//skip completed	
-				}
-
-			}
-		}
-	}
-
-	/**
-	 * Skips whitespaces..
-	 */
-	private static int getEventType(XmlPullParser xmlPuller)throws XmlPullParserException, IOException{
-		int eventType = xmlPuller.next();
-		while(eventType == XmlPullParser.TEXT && xmlPuller.isWhitespace()){
-			eventType = xmlPuller.next();
-		}
-		return eventType;
-	}
-	private static void throwException(String file, int eventType){
-		throw new IllegalArgumentException(String.format("Xml file: %s malformed with error: %d.", file, eventType));
-	}
-
-	public int describeContents() {
-		return 0;
-	}
-
-	public void writeToParcel(Parcel dest, int flags) {
-		dest.writeString(name);
-		dest.writeInt(gamemod);
-		dest.writeList(basic);
-	}
-	
-	public void readFromParcel(Parcel src){
-		name = src.readString();
-		gamemod = src.readInt();
-		basic = src.readArrayList(ArrayList.class.getClassLoader());
-	}
-
-	public static final Parcelable.Creator<Scheme> CREATOR = new Parcelable.Creator<Scheme>() {
-		public Scheme createFromParcel(Parcel source) {
-			return new Scheme(source);
-		}
-		public Scheme[] newArray(int size) {
-			return new Scheme[size];
-		}
-		
-	};
-
-	public int compareTo(Scheme another) {
-		return name.compareTo(another.name);
-	}
-}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Schemes.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,75 @@
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.SchemelistPtr;
+
+import android.content.Context;
+
+/**
+ * Functions for handling the persistent list of schemes.
+ * Schemes in that list are identified by name (case sensitive).
+ */
+public final class Schemes {
+	private Schemes() {
+		throw new AssertionError("This class is not meant to be instantiated");
+	}
+	
+	public static File getUserSchemesFile(Context c) {
+		return new File(c.getFilesDir(), "schemes_user.ini");
+	}
+	
+	public static File getBuiltinSchemesFile(Context c) {
+		return new File(c.getFilesDir(), "schemes_builtin.ini");
+	}
+	
+	public static List<Scheme> loadAllSchemes(Context c) throws IOException {
+		List<Scheme> result = loadBuiltinSchemes(c);
+		result.addAll(loadUserSchemes(c));
+		return result;
+	}
+	
+	public static List<Scheme> loadUserSchemes(Context c) throws IOException {
+		return loadSchemes(c, getUserSchemesFile(c));
+	}
+	
+	public static List<Scheme> loadBuiltinSchemes(Context c) throws IOException {
+		return loadSchemes(c, getBuiltinSchemesFile(c));
+	}
+	
+	public static List<Scheme> loadSchemes(Context c, File schemeFile) throws IOException {
+		if(!schemeFile.isFile()) {
+			// No schemes file == no schemes, no error
+			return new ArrayList<Scheme>();
+		}
+		SchemelistPtr schemeListPtr = null;
+		try {
+			schemeListPtr = Flib.INSTANCE.flib_schemelist_from_ini(schemeFile.getAbsolutePath());
+			if(schemeListPtr == null) {
+				throw new IOException("Unable to read schemelist");
+			}
+			return schemeListPtr.deref();
+		} finally {
+			if(schemeListPtr != null) {
+				Flib.INSTANCE.flib_schemelist_destroy(schemeListPtr);
+			}
+		}
+	}
+	
+	public static void saveUserSchemes(Context c, List<Scheme> schemes) throws IOException {
+		SchemelistPtr ptr = SchemelistPtr.createJavaOwned(schemes);
+		Flib.INSTANCE.flib_schemelist_to_ini(getUserSchemesFile(c).getAbsolutePath(), ptr);
+	}
+	
+	public static List<String> toNameList(List<Scheme> schemes) {
+		List<String> result = new ArrayList<String>();
+		for(Scheme scheme : schemes) {
+			result.add(scheme.name);
+		}
+		return result;
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Team.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Team.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,12 @@
 /*
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,356 +15,77 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-
 package org.hedgewars.hedgeroid.Datastructures;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
 
-import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-import org.xmlpull.v1.XmlSerializer;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamPtr;
+import org.hedgewars.hedgeroid.util.FileUtils;
 
 import android.content.Context;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Xml;
 
-public class Team implements Parcelable{
-
+public final class Team {
 	public static final String DIRECTORY_TEAMS = "teams";
-	private static final Integer[] TEAM_COLORS = {
-		0xd12b42, /* red    */ 
-		0x4980c1, /* blue   */ 
-		0x6ab530, /* green  */ 
-		0xbc64c4, /* purple */ 
-		0xe76d14, /* orange */ 
-		0x3fb6e6, /* cyan   */ 
-		0xe3e90c, /* yellow */ 
-		0x61d4ac, /* mint   */ 
-		0xf1c3e1, /* pink   */ 
-		/* add new colors here */
-	};
+
+	public static final int HEDGEHOGS_PER_TEAM = Flib.INSTANCE.flib_get_hedgehogs_per_team();
+	public static final int maxNumberOfTeams = PascalExports.HWgetMaxNumberOfTeams();
+
+	public final String name, grave, flag, voice, fort;
+	public final List<Hog> hogs;
 
-//	private static final Integer[] TEAM_COLORS = {
-//		0xff0000, /* red    */ 
-//		0x00ff00, /* blue   */ 
-//		0x0000ff, /* green  */ 
-//	};
-
-	private static final int STATE_START = 0;
-	private static final int STATE_ROOT = 1;
-	private static final int STATE_HOG_ROOT = 2;
-
-	public String name, grave, flag, voice, fort, hash;
-	public String file = null;
-
-	public static int maxNumberOfHogs = 0;
-	public static int maxNumberOfTeams = 0;
-
-	static{
-		maxNumberOfHogs = PascalExports.HWgetMaxNumberOfHogs();
-		maxNumberOfTeams = PascalExports.HWgetMaxNumberOfTeams();
-	}
-	public String[] hats = new String[maxNumberOfHogs];
-	public String[] hogNames = new String[maxNumberOfHogs];
-	public int[] levels = new int[maxNumberOfHogs];
-
-	public int hogCount = 4;
-	public int color = TEAM_COLORS[0];
-
-	public Team(){
+	public Team(String name, String grave, String flag, String voice, String fort, List<Hog> hogs) {
+		if(hogs.size() != HEDGEHOGS_PER_TEAM) {
+			throw new IllegalArgumentException("A team must consist of "+HEDGEHOGS_PER_TEAM+" hogs.");
+		}
+		this.name = name;
+		this.grave = grave;
+		this.flag = flag;
+		this.voice = voice;
+		this.fort = fort;
+		this.hogs = Collections.unmodifiableList(new ArrayList<Hog>(hogs));
 	}
 
-	public Team(Parcel in){
-		readFromParcel(in);
-	}
-
-	public boolean equals(Object o){
-		if(super.equals(o)) return true;
-		else if(o instanceof Team){
-			Team t = (Team)o;
-			boolean ret = name.equals(t.name);
-			ret &= grave.equals(t.grave);
-			ret &= flag.equals(t.flag);
-			ret &= voice.equals(t.voice);
-			ret &= fort.equals(t.fort);
-			ret &= hash.equals(t.hash);
-			return ret;
-		}else{
-			return false;
+	public void save(File f) throws IOException {
+		TeamPtr teamPtr = TeamPtr.createJavaOwned(this);
+		if(Flib.INSTANCE.flib_team_to_ini(f.getAbsolutePath(), teamPtr) != 0) {
+			throw new IOException("Error saving team "+name);
 		}
 	}
 
-	public void setRandomColor(int[] illegalcolors){
-		Integer[] colorsToPickFrom = TEAM_COLORS;
-		if(illegalcolors != null){
-			ArrayList<Integer> colors = new ArrayList<Integer>();
-			for(int color : TEAM_COLORS){
-				boolean validColor = true;
-				for(int illegal : illegalcolors){
-					if(color == illegal) validColor = false;
-				}
-				if(validColor) colors.add(color);
-			}
-			if(colors.size() != 0) colorsToPickFrom = colors.toArray(new Integer[1]);
-		}
-		int index = (int)Math.round(Math.random()*(colorsToPickFrom.length-1));
-		color = colorsToPickFrom[index];
-	}
-
-
-	public void sendToEngine(EngineProtocolNetwork epn, int hogCount, int health) throws IOException{
-		epn.sendToEngine(String.format("eaddteam %s %d %s", hash, color, name));
-		epn.sendToEngine(String.format("egrave %s", grave));
-		epn.sendToEngine(String.format("efort %s", fort));
-		epn.sendToEngine(String.format("evoicepack %s", voice));
-		epn.sendToEngine(String.format("eflag %s", flag));
-
-		for(int i = 0; i < hogCount; i++){
-			epn.sendToEngine(String.format("eaddhh %d %d %s", levels[i], health, hogNames[i]));
-			epn.sendToEngine(String.format("ehat %s", hats[i]));
-		}
-	}
-
-	public void setFileName(Context c){
-		if(file == null){
-		  	file = validFileName(c, name);
-		}
-	}
-	private String validFileName(Context c, String fileName){
-		String absolutePath = String.format("%s/%s", c.getFilesDir(), fileName);
-		File f = new File(absolutePath);
-		if(f.exists()){
-			String newFileName = fileName + (int)(Math.random()*10);
-			return validFileName(c, newFileName);
-		}else{
-			return fileName;
+	public static Team load(File f) {
+		TeamPtr teamPtr = Flib.INSTANCE.flib_team_from_ini(f.getAbsolutePath());
+		if(teamPtr != null) {
+			Team team = teamPtr.deref().team;
+			Flib.INSTANCE.flib_team_destroy(teamPtr);
+			return team;
+		} else {
+			return null;
 		}
 	}
 	
-	/*
-	 * XML METHODS
-	 */
-
-	/**
-	 * Read the xml file path and convert it to a Team object
-	 * @param path absolute path to the xml file
-	 * @return
-	 */
-	public static Team getTeamFromXml(String path){
-		try {
-			XmlPullParserFactory xmlPullFactory = XmlPullParserFactory.newInstance();
-			XmlPullParser xmlPuller = xmlPullFactory.newPullParser();
-
-			BufferedReader br = new BufferedReader(new FileReader(path), 1024);
-			xmlPuller.setInput(br);
-			Team team = new Team();
-			int hogCounter = 0;
-
-			int eventType = xmlPuller.getEventType();
-			int state = STATE_START;
-			while(eventType != XmlPullParser.END_DOCUMENT){
-				switch(state){
-				case STATE_START:
-					if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().equals("team")) state = STATE_ROOT;
-					else if(eventType != XmlPullParser.START_DOCUMENT) throwException(path, eventType);
-					break;
-				case STATE_ROOT:
-					if(eventType == XmlPullParser.START_TAG){
-						if(xmlPuller.getName().toLowerCase().equals("name")){
-							team.name = getXmlText(xmlPuller, "name");
-						}else if(xmlPuller.getName().toLowerCase().equals("flag")){
-							team.flag= getXmlText(xmlPuller, "flag");
-						}else if(xmlPuller.getName().toLowerCase().equals("voice")){
-							team.voice = getXmlText(xmlPuller, "voice");
-						}else if(xmlPuller.getName().toLowerCase().equals("grave")){
-							team.grave = getXmlText(xmlPuller, "grave");
-						}else if(xmlPuller.getName().toLowerCase().equals("fort")){
-							team.fort = getXmlText(xmlPuller, "fort");
-						}else if(xmlPuller.getName().toLowerCase().equals("hash")){
-							team.hash = getXmlText(xmlPuller, "hash");
-						}else if(xmlPuller.getName().toLowerCase().equals("hog")){
-							state = STATE_HOG_ROOT;
-						}else throwException(xmlPuller.getName(), eventType);
-					}else if(eventType == XmlPullParser.END_TAG) state = STATE_START;
-					else throwException(xmlPuller.getText(), eventType);
-					break;
-				case STATE_HOG_ROOT:
-					if(eventType == XmlPullParser.START_TAG){
-						if(xmlPuller.getName().toLowerCase().equals("name")){
-							team.hogNames[hogCounter] = getXmlText(xmlPuller, "name");
-						}else if(xmlPuller.getName().toLowerCase().equals("hat")){
-							team.hats[hogCounter] = getXmlText(xmlPuller, "hat");
-						}else if(xmlPuller.getName().toLowerCase().equals("level")){
-							team.levels[hogCounter] = Integer.parseInt(getXmlText(xmlPuller, "level"));
-						}else throwException(xmlPuller.getText(), eventType);
-					}else if(eventType == XmlPullParser.END_TAG){
-						hogCounter++;
-						state = STATE_ROOT;
-					}else throwException(xmlPuller.getText(), eventType);
-					break;
-				}
-				eventType = getEventType(xmlPuller);
-			}//end while(eventtype != END_DOCUMENT
-			return team;
-		} catch (NumberFormatException e){
-			e.printStackTrace();
-		} catch (XmlPullParserException e) {
-			e.printStackTrace();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return null;
-	}
-
-	private static String getXmlText(XmlPullParser xmlPuller, String parentTag)throws XmlPullParserException, IOException{
-		if(getEventType(xmlPuller) == XmlPullParser.TEXT){
-			String txt = xmlPuller.getText();
-			if(getEventType(xmlPuller) == XmlPullParser.END_TAG && xmlPuller.getName().toLowerCase().equals(parentTag)){
-				return txt;
-			}
-		}
-		throw new XmlPullParserException("malformed xml file on string read from tag: " + parentTag);
-	}
-
-	/**
-	 * Skips whitespaces..
-	 */
-	private static int getEventType(XmlPullParser xmlPuller)throws XmlPullParserException, IOException{
-		int eventType = xmlPuller.next();
-		while(eventType == XmlPullParser.TEXT && xmlPuller.isWhitespace()){
-			eventType = xmlPuller.next();
-		}
-		return eventType;
-	}
-
-	private static void throwException(String file, int eventType){
-		throw new IllegalArgumentException(String.format("Xml file: %s malformed with error: %d.", file, eventType));
+	public static File getTeamfileByName(Context c, String teamName) {
+		return new File(new File(c.getFilesDir(), DIRECTORY_TEAMS), FileUtils.replaceBadChars(teamName)+".hwt");
 	}
-
-	public void writeToXml(OutputStream os){
-		XmlSerializer serializer = Xml.newSerializer();
-		try{
-			serializer.setOutput(os, "UTF-8");	
-			serializer.startDocument("UTF-8", true);
-			serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
-			serializer.startTag(null, "team");
-			serializer.startTag(null, "name");
-			serializer.text(name);
-			serializer.endTag(null, "name");
-			serializer.startTag(null, "flag");
-			serializer.text(flag);
-			serializer.endTag(null, "flag");
-			serializer.startTag(null, "fort");
-			serializer.text(fort);
-			serializer.endTag(null, "fort");
-			serializer.startTag(null, "grave");
-			serializer.text(grave);
-			serializer.endTag(null, "grave");
-			serializer.startTag(null, "voice");
-			serializer.text(voice);
-			serializer.endTag(null, "voice");
-			serializer.startTag(null, "hash");
-			serializer.text(hash);
-			serializer.endTag(null, "hash");
-
-			for(int i = 0; i < maxNumberOfHogs; i++){
-				serializer.startTag(null, "hog");
-				serializer.startTag(null, "name");
-				serializer.text(hogNames[i]);
-				serializer.endTag(null, "name");
-				serializer.startTag(null, "hat");
-				serializer.text(hats[i]);
-				serializer.endTag(null, "hat");
-				serializer.startTag(null, "level");
-				serializer.text(String.valueOf(levels[i]));
-				serializer.endTag(null, "level");
-
-				serializer.endTag(null, "hog");
-			}
-			serializer.endTag(null, "team");
-			serializer.endDocument();
-			serializer.flush();
-
-		} catch (IOException e) {
-			e.printStackTrace();
-		}finally{
-			try {
-				os.close();
-			} catch (IOException e) {}
-		}
+	
+	@Override
+	public String toString() {
+		return "Team [name=" + name + ", grave=" + grave + ", flag=" + flag
+				+ ", voice=" + voice + ", fort=" + fort + ", hogs=" + hogs
+				+ "]";
 	}
-	/*
-	 * END XML METHODS
-	 */
-
-
-
-	/*
-	 * PARCABLE METHODS
-	 */
-
-	public int describeContents() {
-		return 0;
-	}
-
-	public void writeToParcel(Parcel dest, int flags) {
-		dest.writeString(name);
-		dest.writeString(grave);
-		dest.writeString(flag);
-		dest.writeString(voice);
-		dest.writeString(fort);
-		dest.writeString(hash);
-		dest.writeStringArray(hats);
-		dest.writeStringArray(hogNames);
-		dest.writeIntArray(levels);
-		dest.writeInt(color);
-		dest.writeInt(hogCount);
-		dest.writeString(file);
-	}
-
-
-	public void readFromParcel(Parcel src){
-		name = src.readString();
-		grave = src.readString();
-		flag = src.readString();
-		voice = src.readString();
-		fort = src.readString();
-		hash = src.readString();
-		src.readStringArray(hats);
-		src.readStringArray(hogNames);
-		src.readIntArray(levels);
-		color = src.readInt();
-		hogCount = src.readInt();
-		file = src.readString();
-	}
-
-	public static final Parcelable.Creator<Team> CREATOR = new Parcelable.Creator<Team>() {
-		public Team createFromParcel(Parcel source) {
-			return new Team(source);
+	
+	public static Comparator<Team> NAME_ORDER = new Comparator<Team>() {
+		public int compare(Team lhs, Team rhs) {
+			return lhs.name.compareToIgnoreCase(rhs.name);
 		}
-		public Team[] newArray(int size) {
-			return new Team[size];
-		}
-
 	};
-
-	/*
-	 * END PARCABLE METHODS
-	 */
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/TeamInGame.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,58 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+/**
+ * A team with per-game configuration. This is similar to the frontlib "team" structure,
+ * except that it does not include weaponset and initial health, which are handled on a
+ * per-game basis in the UI, but per-hog in the frontlib.
+ */
+public final class TeamInGame {
+	public final Team team;
+	public final TeamIngameAttributes ingameAttribs;
+	
+	public TeamInGame(Team team, TeamIngameAttributes ingameAttribs) {
+		this.team = team;
+		this.ingameAttribs = ingameAttribs;
+	}
+	
+	public TeamInGame withAttribs(TeamIngameAttributes attribs) {
+		return new TeamInGame(team, attribs);
+	}
+	
+	public static int getUnusedOrRandomColorIndex(Collection<TeamInGame> teams) {
+		int[] illegalColors = new int[teams.size()];
+		int i=0;
+		for(TeamInGame team : teams) {
+			illegalColors[i] = team.ingameAttribs.colorIndex;
+			i++;
+		}
+		return TeamIngameAttributes.randomColorIndex(illegalColors);
+	}
+	
+	public static Comparator<TeamInGame> NAME_ORDER = new Comparator<TeamInGame>() {
+		public int compare(TeamInGame lhs, TeamInGame rhs) {
+			return Team.NAME_ORDER.compare(lhs.team, rhs.team);
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/TeamIngameAttributes.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,80 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.hedgewars.hedgeroid.frontlib.Flib;
+
+public final class TeamIngameAttributes {
+	public static final int DEFAULT_HOG_COUNT = 4;
+	public static final int[] TEAM_COLORS;
+	
+	static {
+		int[] teamColors = new int[Flib.INSTANCE.flib_get_teamcolor_count()];
+		for(int i=0; i<teamColors.length; i++) {
+			teamColors[i] = Flib.INSTANCE.flib_get_teamcolor(i);
+		}
+		TEAM_COLORS = teamColors;
+	}
+	
+	public final String ownerName;
+	public final int colorIndex, hogCount;
+	public final boolean remoteDriven;
+	
+	public TeamIngameAttributes(String ownerName, int colorIndex, int hogCount, boolean remoteDriven) {
+		this.ownerName = ownerName;
+		this.colorIndex = colorIndex;
+		this.hogCount = hogCount;
+		this.remoteDriven = remoteDriven;
+	}
+	
+	public static int randomColorIndex(int[] illegalColors) {
+		Random rnd = new Random();
+		ArrayList<Integer> legalcolors = new ArrayList<Integer>();
+		for(int i=0; i<TEAM_COLORS.length; i++) {
+			legalcolors.add(i);
+		}
+		for(int illegalColor : illegalColors) {
+			legalcolors.remove(Integer.valueOf(illegalColor));
+		}
+		if(legalcolors.isEmpty()) {
+			return rnd.nextInt(TEAM_COLORS.length);
+		} else {
+			return legalcolors.get(rnd.nextInt(legalcolors.size()));
+		}
+	}
+	
+	public TeamIngameAttributes withColorIndex(int colorIndex) {
+		return new TeamIngameAttributes(ownerName, colorIndex, hogCount, remoteDriven);
+	}
+	
+	public TeamIngameAttributes withHogCount(int hogCount) {
+		return new TeamIngameAttributes(ownerName, colorIndex, hogCount, remoteDriven);
+	}
+
+	@Override
+	public String toString() {
+		return "TeamIngameAttributes [ownerName=" + ownerName + ", colorIndex="
+				+ colorIndex + ", hogCount=" + hogCount + ", remoteDriven="
+				+ remoteDriven + "]";
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weapon.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-package org.hedgewars.hedgeroid.Datastructures;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.ArrayList;
-
-import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
-import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import android.content.Context;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class Weapon implements Parcelable, Comparable<Weapon>{
-
-	public static final String DIRECTORY_WEAPON = "weapons";
-	
-	private String name;
-	private String QT;
-	private String prob;
-	private String delay;
-	private String crate;
-	private static int maxWeapons;
-	
-	static{
-		maxWeapons = PascalExports.HWgetNumberOfWeapons();
-	}
-	
-	public Weapon(String _name, String _QT, String _prob, String _delay, String _crate){
-		name = _name;
-		
-		//Incase there's a newer ammoStore which is bigger we append with zeros
-		StringBuffer sb = new StringBuffer();
-		while(_QT.length() + sb.length() < maxWeapons){
-			sb.append('0');
-		}
-		
-		QT = String.format("e%s %s%s", "ammloadt", _QT, sb);
-		prob = String.format("e%s %s%s", "ammprob", _prob, sb);
-		delay = String.format("e%s %s%s", "ammdelay", _delay, sb);
-		crate = String.format("e%s %s%s", "ammreinf", _crate, sb);
-	}
-	
-	public Weapon(Parcel in){
-		readFromParcel(in);
-	}
-	
-	public String toString(){
-		return name;
-	}
-	
-	public void sendToEngine(EngineProtocolNetwork epn, int teamsCount) throws IOException{
-		epn.sendToEngine(QT);//command prefix is already in string 
-		epn.sendToEngine(prob);
-		epn.sendToEngine(delay);
-		epn.sendToEngine(crate);
-		
-		for(int i = 0; i < teamsCount; i++){
-			epn.sendToEngine("eammstore");
-		}
-	}
-	
-	public static final int STATE_START = 0;
-	public static final int STATE_ROOT = 1;
-	public static final int STATE_NAME = 2;
-	public static final int STATE_QT = 3;
-	public static final int STATE_PROBABILITY = 4;
-	public static final int STATE_DELAY = 5;
-	public static final int STATE_CRATE = 6;
-	
-	public static ArrayList<Weapon> getWeapons(Context c) throws IllegalArgumentException{
-		String dir = c.getFilesDir().getAbsolutePath() + '/' + DIRECTORY_WEAPON + '/';
-		String[] files = new File(dir).list();
-		if(files == null) files = new String[]{};
-		
-		ArrayList<Weapon> weapons = new ArrayList<Weapon>();
-
-		try {
-			XmlPullParserFactory xmlPullFactory = XmlPullParserFactory.newInstance();
-			XmlPullParser xmlPuller = xmlPullFactory.newPullParser();
-			
-			for(String file : files){
-				BufferedReader br = new BufferedReader(new FileReader(dir + file), 1024);
-				xmlPuller.setInput(br);
-				String name = null;
-				String qt = null;
-				String prob = null;
-				String delay = null;
-				String crate = null;
-				
-				int eventType = xmlPuller.getEventType();
-				int state = STATE_START;
-				while(eventType != XmlPullParser.END_DOCUMENT){
-					switch(state){
-					case STATE_START:
-						if(eventType == XmlPullParser.START_TAG && xmlPuller.getName().equals("weapon")) state = STATE_ROOT;
-						else if(eventType != XmlPullParser.START_DOCUMENT) throwException(file, eventType);
-						break;
-					case STATE_ROOT:
-						if(eventType == XmlPullParser.START_TAG){
-							if(xmlPuller.getName().toLowerCase().equals("qt")) state = STATE_QT;
-							else if(xmlPuller.getName().toLowerCase().equals("name")) state = STATE_NAME;
-							else if(xmlPuller.getName().toLowerCase().equals("probability")) state = STATE_PROBABILITY;
-							else if(xmlPuller.getName().toLowerCase().equals("delay")) state = STATE_DELAY;
-							else if(xmlPuller.getName().toLowerCase().equals("crate")) state = STATE_CRATE;
-							else throwException(file, eventType);
-						}else if(eventType == XmlPullParser.END_TAG) state = STATE_START;
-						else throwException(xmlPuller.getText(), eventType);
-						break;
-					case STATE_NAME:
-						if(eventType == XmlPullParser.TEXT) name = xmlPuller.getText().trim();
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_QT:
-						if(eventType == XmlPullParser.TEXT) qt = xmlPuller.getText().trim();
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_PROBABILITY:
-						if(eventType == XmlPullParser.TEXT) prob = xmlPuller.getText().trim();
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_DELAY:
-						if(eventType == XmlPullParser.TEXT) delay = xmlPuller.getText().trim();
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					case STATE_CRATE:
-						if(eventType == XmlPullParser.TEXT) crate = xmlPuller.getText().trim();
-						else if(eventType == XmlPullParser.END_TAG) state = STATE_ROOT;
-						else throwException(file, eventType);
-						break;
-					}
-					eventType = xmlPuller.next();
-					while(eventType == XmlPullParser.TEXT && xmlPuller.isWhitespace()){//Skip whitespaces
-						eventType = xmlPuller.next();
-					}
-				}//end while(eventtype != END_DOCUMENT
-				weapons.add(new Weapon(name, qt, prob, delay, crate));
-			}//end for(string file : files
-			return weapons;
-			
-		} catch (XmlPullParserException e) {
-			e.printStackTrace();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		return new ArrayList<Weapon>();//TODO handle correctly
-	}
-	
-	private static void throwException(String file, int eventType){
-		throw new IllegalArgumentException(String.format("Xml file: %s malformed with eventType: %d.", file, eventType));
-	}
-
-	public int describeContents() {
-		return 0;
-	}
-
-	public void writeToParcel(Parcel dest, int flags) {
-		dest.writeString(name);
-		dest.writeString(QT);
-		dest.writeString(prob);
-		dest.writeString(delay);
-		dest.writeString(crate);
-	}
-	
-	private void readFromParcel(Parcel src){
-		name = src.readString();
-		QT = src.readString();
-		prob = src.readString();
-		delay = src.readString();
-		crate = src.readString();
-	}
-	
-	public static final Parcelable.Creator<Weapon> CREATOR = new Parcelable.Creator<Weapon>() {
-		public Weapon createFromParcel(Parcel source) {
-			return new Weapon(source);
-		}
-		public Weapon[] newArray(int size) {
-			return new Weapon[size];
-		}
-		
-	};
-
-	public int compareTo(Weapon another) {
-		return name.compareTo(another.name);
-	}
-	
-	
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weaponset.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,102 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.frontlib.Flib;
+
+public final class Weaponset {
+	public static final int WEAPONS_COUNT = Flib.INSTANCE.flib_get_weapons_count();
+	
+	public final String name, loadout, crateProb, crateAmmo, delay;
+	
+	public Weaponset(String name, String loadout, String crateProb, String crateAmmo, String delay) {
+		this.name = name;
+		this.loadout = loadout;
+		this.crateProb = crateProb;
+		this.crateAmmo = crateAmmo;
+		this.delay = delay;
+	}
+
+	@Override
+	public String toString() {
+		return "Weaponset [name=" + name + ", loadout=" + loadout
+				+ ", crateProb=" + crateProb + ", crateAmmo=" + crateAmmo
+				+ ", delay=" + delay + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((crateAmmo == null) ? 0 : crateAmmo.hashCode());
+		result = prime * result
+				+ ((crateProb == null) ? 0 : crateProb.hashCode());
+		result = prime * result + ((delay == null) ? 0 : delay.hashCode());
+		result = prime * result + ((loadout == null) ? 0 : loadout.hashCode());
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Weaponset other = (Weaponset) obj;
+		if (crateAmmo == null) {
+			if (other.crateAmmo != null)
+				return false;
+		} else if (!crateAmmo.equals(other.crateAmmo))
+			return false;
+		if (crateProb == null) {
+			if (other.crateProb != null)
+				return false;
+		} else if (!crateProb.equals(other.crateProb))
+			return false;
+		if (delay == null) {
+			if (other.delay != null)
+				return false;
+		} else if (!delay.equals(other.delay))
+			return false;
+		if (loadout == null) {
+			if (other.loadout != null)
+				return false;
+		} else if (!loadout.equals(other.loadout))
+			return false;
+		if (name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!name.equals(other.name))
+			return false;
+		return true;
+	}
+
+	public static Comparator<Weaponset> NAME_ORDER = new Comparator<Weaponset>() {
+		public int compare(Weaponset lhs, Weaponset rhs) {
+			return String.CASE_INSENSITIVE_ORDER.compare(lhs.name, rhs.name);
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weaponsets.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,103 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.WeaponsetListPtr;
+
+import android.content.Context;
+
+public final class Weaponsets {
+	private Weaponsets() {
+		throw new AssertionError("This class is not meant to be instantiated");
+	}
+	
+	public static File getUserWeaponsetsFile(Context c) {
+		return new File(c.getFilesDir(), "weapons_user.ini");
+	}
+	
+	public static File getBuiltinWeaponsetsFile(Context c) {
+		return new File(c.getFilesDir(), "weapons_builtin.ini");
+	}
+	
+	public static List<Weaponset> loadAllWeaponsets(Context c) throws IOException {
+		List<Weaponset> result = loadBuiltinWeaponsets(c);
+		result.addAll(loadUserWeaponsets(c));
+		return result;
+	}
+	
+	public static List<Weaponset> loadUserWeaponsets(Context c) throws IOException {
+		return loadWeaponsets(c, getUserWeaponsetsFile(c));
+	}
+	
+	public static List<Weaponset> loadBuiltinWeaponsets(Context c) throws IOException {
+		return loadWeaponsets(c, getBuiltinWeaponsetsFile(c));
+	}
+	
+	public static List<Weaponset> loadWeaponsets(Context c, File weaponsetFile) throws IOException {
+		if(!weaponsetFile.isFile()) {
+			// No file == no weaponsets, no error
+			return new ArrayList<Weaponset>();
+		}
+		WeaponsetListPtr weaponsetListPtr = null;
+		try {
+			weaponsetListPtr = Flib.INSTANCE.flib_weaponsetlist_from_ini(weaponsetFile.getAbsolutePath());
+			if(weaponsetListPtr == null) {
+				throw new IOException("Unable to read weaponsets from "+weaponsetFile);
+			}
+			return weaponsetListPtr.deref();
+		} finally {
+			if(weaponsetListPtr != null) {
+				Flib.INSTANCE.flib_weaponsetlist_destroy(weaponsetListPtr);
+			}
+		}
+	}
+	
+	public static void saveUserWeaponsets(Context c, List<Weaponset> weaponsets) throws IOException {
+		WeaponsetListPtr ptr = WeaponsetListPtr.createJavaOwned(weaponsets);
+		Flib.INSTANCE.flib_weaponsetlist_to_ini(getUserWeaponsetsFile(c).getAbsolutePath(), ptr);
+	}
+	
+	public static void deleteUserWeaponset(Context c, String setToDelete) throws IOException {
+		List<Weaponset> userWeaponsets = loadUserWeaponsets(c);
+		for(Iterator<Weaponset> iter = userWeaponsets.iterator(); iter.hasNext();) {
+			Weaponset set = iter.next();
+			if(set.name.equals(setToDelete)) {
+				iter.remove();
+				break;
+			}
+		}
+		saveUserWeaponsets(c, userWeaponsets);
+	}
+	
+	public static List<String> toNameList(List<Weaponset> weaponsets) {
+		List<String> result = new ArrayList<String>();
+		for(Weaponset weaponset : weaponsets) {
+			result.add(weaponset.name);
+		}
+		return result;
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadAssets.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadAssets.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,100 +1,83 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid.Downloader;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 
 import org.hedgewars.hedgeroid.MainActivity;
 import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Utils;
-import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Schemes;
 import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.Datastructures.Weapon;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+import org.hedgewars.hedgeroid.util.FileUtils;
 
-import android.content.Context;
 import android.content.res.AssetManager;
 import android.os.AsyncTask;
 import android.util.Log;
 
-public class DownloadAssets extends AsyncTask<Object, Long, Long>{
-	
-	private MainActivity act;
-	private static byte[] buffer = null;
-	
-	public DownloadAssets(MainActivity _act){
-		act = _act;
-	}
+public class DownloadAssets extends AsyncTask<Object, Long, Boolean> {
+	private static final String VERSION_FILENAME = "assetsversion.txt";
+	private final MainActivity act;
 	
-	public static Long copyFileOrDir(Context c, String path) {
-	    AssetManager assetManager = c.getAssets();
-	    String assets[] = null;
-	    try {
-	        assets = assetManager.list(path);
-	        if (assets.length == 0) {
-	            return DownloadAssets.copyFile(c, path);
-	        } else {
-	            String fullPath = Utils.getCachePath(c) + path;
-	            File dir = new File(fullPath);
-	            if (!dir.exists())
-	                dir.mkdir();
-	            for (int i = 0; i < assets.length; ++i) {
-	                Long result = DownloadAssets.copyFileOrDir(c, path + "/" + assets[i]);
-	                if(result > 0) return 1l;
-	            }
-	        }
-	    } catch (IOException ex) {
-	    	ex.printStackTrace();
-	        Log.e("tag", "I/O Exception", ex);
-	        return 1l;
-	    }
-	    return 0l;
+	public DownloadAssets(MainActivity act){
+		this.act = act;
 	}
 	
-	private static Long copyFile(Context c, String filename) {
-	    AssetManager assetManager = c.getAssets();
-
-	    InputStream in = null;
-	    OutputStream out = null;
-	    try {
-	        in = assetManager.open(filename);
-	        in = new BufferedInputStream(in, 8192);
-	        
-	        String newFileName = Utils.getCachePath(c) + filename;
-	        out = new FileOutputStream(newFileName);
-	        out = new BufferedOutputStream(out, 8192);
-
-	        int read;
-	        while ((read = in.read(buffer)) != -1) {
-	            out.write(buffer, 0, read);
-	        }
-	        in.close();
-	        in = null;
-	        out.flush();
-	        out.close();
-	        out = null;
-	    } catch (Exception e) {
-	    	e.printStackTrace();
-	        Log.e("tag", e.getMessage());
-	        return 1l;
-	    }
-	    return 0l;
-
-	}
-
-	protected Long doInBackground(Object... params) {
-		Utils.resRawToFilesDir(act,R.array.schemes, Scheme.DIRECTORY_SCHEME);
-		Utils.resRawToFilesDir(act, R.array.weapons, Weapon.DIRECTORY_WEAPON);
-		Utils.resRawToFilesDir(act, R.array.teams, Team.DIRECTORY_TEAMS);
-		buffer = new byte[8192];//allocate the buffer
-		return DownloadAssets.copyFileOrDir(act, "Data");
+	private void copyFileOrDir(AssetManager assetManager, File target, String assetPath) throws IOException {
+		try {
+			FileUtils.writeStreamToFile(assetManager.open(assetPath), target);
+		} catch(FileNotFoundException e) {
+			/*
+			 * I can't find a better way to figure out whether an asset entry is
+			 * a file or a directory. Checking if assetManager.list(assetPath)
+			 * is empty is a bit cleaner, but SLOW.
+			 */
+			if (!target.isDirectory() && !target.mkdir()) {
+				throw new IOException("Unable to create directory "+target);
+			}
+			for (String asset : assetManager.list(assetPath)) {
+				copyFileOrDir(assetManager, new File(target, asset), assetPath + "/" + asset);
+			}
+		}
 	}
 	
-	protected void onPostExecute(Long result){
-		act.onAssetsDownloaded(result == 0);
-		buffer = null;
+	@Override
+	protected Boolean doInBackground(Object... params) {
+		try {
+			FileUtils.writeStreamToFile(act.getResources().openRawResource(R.raw.schemes_builtin), Schemes.getBuiltinSchemesFile(act));
+			FileUtils.writeStreamToFile(act.getResources().openRawResource(R.raw.weapons_builtin), Weaponsets.getBuiltinWeaponsetsFile(act));
+			FileUtils.resRawToFilesDir(act, R.array.teams, R.array.teamFilenames, Team.DIRECTORY_TEAMS);
+			copyFileOrDir(act.getAssets(), FileUtils.getDataPathFile(act), "Data");
+			copyFileOrDir(act.getAssets(), new File(FileUtils.getCachePath(act), VERSION_FILENAME), VERSION_FILENAME);
+			return Boolean.TRUE;
+		} catch(IOException e) {
+			Log.e("DownloadAssets", e.getMessage(), e);
+			return Boolean.FALSE;
+		}
+	}
+	
+	@Override
+	protected void onPostExecute(Boolean result){
+		act.onAssetsDownloaded(result);
 	}
 }
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadAsyncTask.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadAsyncTask.java	Sun Nov 18 23:10:26 2012 +0400
@@ -2,9 +2,10 @@
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,7 +14,7 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 
@@ -107,7 +108,7 @@
 				entry = input.getNextEntry();	
 			}catch(IOException e){
 				e.printStackTrace();
-				if(conn != null) conn.disconnect();
+				conn.disconnect();
 				return EXIT_CONNERROR;
 			}
 
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadDialogFragment.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadDialogFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid.Downloader;
 
 import org.hedgewars.hedgeroid.R;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadFragment.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -2,9 +2,10 @@
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,10 +14,9 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 package org.hedgewars.hedgeroid.Downloader;
 
 import org.hedgewars.hedgeroid.R;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadListActivity.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadListActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid.Downloader;
 
 import org.hedgewars.hedgeroid.R;
@@ -6,7 +25,6 @@
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
 import android.view.View.OnClickListener;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadListFragment.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadListFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,3 +1,22 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid.Downloader;
 
 import java.io.BufferedReader;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadPackage.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadPackage.java	Sun Nov 18 23:10:26 2012 +0400
@@ -2,9 +2,10 @@
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,14 +14,14 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 package org.hedgewars.hedgeroid.Downloader;
 
 import java.io.IOException;
 
-import org.hedgewars.hedgeroid.Utils;
+import org.hedgewars.hedgeroid.util.FileUtils;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -29,7 +30,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.preference.PreferenceManager;
-import android.util.Log;
 
 public class DownloadPackage implements Parcelable{
 	private String url_without_suffix;
@@ -137,7 +137,7 @@
 							version = -1;
 						}
 					}else if(name.equals("path")){
-						path = Utils.getDataPath(c) + text;
+						path = FileUtils.getDataPathFile(c, text).getAbsolutePath();
 					}else if(name.equals("representation")){
 						representation = text;
 					}else if(name.equals("description")){
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadService.java	Sun Nov 18 23:10:26 2012 +0400
@@ -2,9 +2,10 @@
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,10 +14,9 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 package org.hedgewars.hedgeroid.Downloader;
 
 import java.util.LinkedList;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/EngineProtocolNetwork.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-
-package org.hedgewars.hedgeroid.EngineProtocol;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.UnknownHostException;
-
-public class EngineProtocolNetwork extends Thread{
-
-	public static final String GAMEMODE_LOCAL = "TL";
-	public static final String GAMEMODE_DEMO = "TD";
-	public static final String GAMEMODE_NET = "TN";
-	public static final String GAMEMODE_SAVE = "TS";
-	
-	public static final int BUFFER_SIZE = 255; //From iOS code which got it from the origional frontend
-	
-	public static final int MODE_GENLANDPREVIEW = 0;
-	public static final int MODE_GAME = 1;
-
-	private ServerSocket serverSocket;
-	private InputStream input;
-	private OutputStream output;
-	public int port;
-	private final GameConfig config;
-	private boolean clientQuit = false;
-
-	public EngineProtocolNetwork(GameConfig _config){
-		config = _config;
-		try {
-			serverSocket = new ServerSocket(0);
-			port = serverSocket.getLocalPort();
-			Thread ipcThread = new Thread(this, "IPC - Thread");			
-			ipcThread.start();
-		} catch (UnknownHostException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-	}
-	
-	public void run(){
-		//if(mode == MODE_GENLANDPREVIEW) genLandPreviewIPC();
-		/*else if (mode == MODE_GAME)*/ gameIPC();
-	}
-	
-	private void gameIPC(){
-		Socket sock = null;
-		try{
-			sock = serverSocket.accept();
-			input = sock.getInputStream();
-			output = sock.getOutputStream();
-			
-			int msgSize = 0;
-			byte[] buffer = new byte[BUFFER_SIZE];
-
-			while(!clientQuit){
-				msgSize = 0;
-
-				input.read(buffer, 0, 1);
-				msgSize = buffer[0];
-
-				input.read(buffer, 0, msgSize);
-				System.out.println("IPC" + (char)buffer[0] + " : " + new String(buffer, 1,msgSize-1, "US_ASCII"));
-				switch(buffer[0]){
-				case 'C'://game init
-					config.sendToEngine(this);
-					break;
-				case '?'://ping - pong
-					sendToEngine("!");
-					break;
-				case 'e'://Send protocol version
-					System.out.println(new String(buffer));
-					break;
-				case 'i'://game statistics
-					switch(buffer[1]){
-					case 'r'://winning team
-						break;
-					case 'D'://best shot
-						break;
-					case 'k'://best hedgehog
-						break;
-					case 'K'://# hogs killed
-						break;
-					case 'H'://team health graph
-						break;
-					case 'T':// local team stats
-						break;
-					case 'P'://teams ranking
-						break;
-					case 's'://self damage
-						break;
-					case 'S'://friendly fire
-						break;
-					case 'B'://turn skipped
-						break;
-					default:
-					}
-					break;
-				case 'E'://error - quits game
-					System.out.println(new String(buffer));
-					return;
-				case 'q'://game ended remove save file
-
-				    return;
-				case 'Q'://game ended but not finished
-
-					return;
-				}
-
-			}
-		}catch(IOException e){
-			e.printStackTrace();
-		}finally{
-			try {
-				if(sock != null) sock.close();
-			} catch (IOException e) {}
-			try{
-				if(serverSocket != null) serverSocket.close();
-			} catch (IOException e) {}
-		}
-	}
-
-	public void sendToEngine(String s){
-		int length = s.length();
-		
-		try {
-			output.write(length);
-			output.write(s.getBytes(), 0, length);
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-	}
-	
-	public void quitIPC(){
-		clientQuit = true;
-	}
-	
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/GameConfig.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-package org.hedgewars.hedgeroid.EngineProtocol;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.UUID;
-
-import org.hedgewars.hedgeroid.Datastructures.GameMode;
-import org.hedgewars.hedgeroid.Datastructures.Map;
-import org.hedgewars.hedgeroid.Datastructures.Scheme;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.Datastructures.Weapon;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-public class GameConfig implements Parcelable{
-	
-	public GameMode mode = GameMode.MODE_LOCAL;
-	public Map map = null;
-	public String theme = null;
-	public Scheme scheme = null;
-	public Weapon weapon = null;
-	
-	public String style = null;
-	public String training = null;
-	public String seed = null;
-	
-	public ArrayList<Team> teams = new ArrayList<Team>();
-	
-	public GameConfig(){
-		
-	}
-	
-	public GameConfig(Parcel in){
-		readFromParcel(in);	
-	}
-	
-
-	
-	public void sendToEngine(EngineProtocolNetwork epn) throws IOException{
-		Log.d("HW_Frontend", "Sending Gameconfig...");
-		int teamCount = 4;
-		epn.sendToEngine("TL"); //Write game mode
-		if(training != null) epn.sendToEngine(String.format("escript Scripts/Training/%s.lua", training));
-		else if(style != null) epn.sendToEngine(String.format("escript Scripts/Multiplayer/%s.lua", style));
-		
-		//seed info
-		epn.sendToEngine(String.format("eseed {%s}", UUID.randomUUID().toString()));
-		
-		map.sendToEngine(epn);
-		//dimensions of the map
-		//templatefilter_command
-		//mapgen_command
-		//mazesize_command
-		
-		epn.sendToEngine(String.format("etheme %s", theme));
-		
-		scheme.sendToEngine(epn);
-		
-		weapon.sendToEngine(epn, teamCount);
-		
-		for(Team t : teams){
-			if(t != null)t.sendToEngine(epn, teamCount, scheme.health);
-		}
-	}
-	
-	public int describeContents() {
-		return 0;
-	}
-
-	public void writeToParcel(Parcel dest, int flags) {
-		dest.writeString(mode.name());
-		dest.writeParcelable(map, flags);
-		dest.writeString(theme);
-		dest.writeParcelable(scheme, flags);
-		dest.writeParcelable(weapon, flags);
-		dest.writeString(style);
-		dest.writeString(training);
-		dest.writeString(seed);
-		dest.writeParcelableArray((Team[])teams.toArray(new Team[1]), 0);
-	}
-	
-	private void readFromParcel(Parcel src){
-		mode = GameMode.valueOf(src.readString());
-		map = src.readParcelable(Map.class.getClassLoader());
-		theme = src.readString();
-		scheme = src.readParcelable(Scheme.class.getClassLoader());
-		weapon = src.readParcelable(Weapon.class.getClassLoader());
-		style = src.readString();
-		training = src.readString();
-		seed = src.readString();
-		Parcelable[] parcelables = src.readParcelableArray(Team[].class.getClassLoader());
-		for(Parcelable team : parcelables){
-			teams.add((Team)team);
-		}
-		
-	}
-	
-	public static final Parcelable.Creator<GameConfig> CREATOR = new Parcelable.Creator<GameConfig>() {
-		public GameConfig createFromParcel(Parcel source) {
-			return new GameConfig(source);
-		}
-		public GameConfig[] newArray(int size) {
-			return new GameConfig[size];
-		}
-	};
-	
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,12 @@
 /*
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,12 +15,13 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 package org.hedgewars.hedgeroid.EngineProtocol;
 
 public class PascalExports {
+	public static Object engineMutex = new Object();
 
 	static{
 		System.loadLibrary("SDL");
@@ -31,10 +34,13 @@
 		System.loadLibrary("hwengine");
 	}
 	
-	public static native int HWversionInfoNetProto();
-	public static native String HWversionInfoVersion();
-	public static native int HWgetNumberOfWeapons();
 	public static native int HWgetMaxNumberOfTeams();
-	public static native int HWgetMaxNumberOfHogs();
-        public static native int HWterminate(boolean b);	
+    private static native void HWGenLandPreview(int port);
+
+    public static void synchronizedGenLandPreview(int port) {
+    	synchronized(engineMutex) {
+    		HWGenLandPreview(port);
+    	}
+    }
+    
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,222 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.net.ConnectException;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.ByteArrayPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BytesCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrBoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback;
+import org.hedgewars.hedgeroid.frontlib.NativeSizeT;
+import org.hedgewars.hedgeroid.netplay.GameMessageListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.util.TickHandler;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Log;
+
+import com.sun.jna.Pointer;
+
+/**
+ * This class handles both talking to the engine (IPC) for running a game, and
+ * coordinating with the netconn if it is a netgame, using the frontlib for the
+ * actual IPC networking communication.
+ * 
+ * After creating the GameConnection object, it will communicate with the engine
+ * on its own thread. It shuts itself down as soon as the connection to the engine
+ * is lost.
+ */
+public final class GameConnection {
+	private static final Handler mainHandler = new Handler(Looper.getMainLooper());
+	
+	public final int port;
+	private final HandlerThread thread;
+	private final Handler handler;
+	private TickHandler tickHandler;
+	private final Netplay netplay; // ==null if not a netgame
+	private GameconnPtr conn;
+	
+	private GameConnection(GameconnPtr conn, Netplay netplay) {
+		this.conn = conn;
+		this.port = Flib.INSTANCE.flib_gameconn_getport(conn);
+		this.netplay = netplay;
+		this.thread = new HandlerThread("IPCThread");
+		thread.start();
+		this.handler = new Handler(thread.getLooper());
+	}
+	
+	private void setupConnection() {
+		tickHandler = new TickHandler(thread.getLooper(), 50, tickCb);
+		tickHandler.start();
+		
+		if(netplay != null) {
+			mainHandler.post(new Runnable() {
+				public void run() { 
+					netplay.registerGameMessageListener(gameMessageListener);
+				}
+			});
+			Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null);
+			Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null);
+		}
+		Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null);
+		Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null);
+		Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null);
+	}
+	
+	/**
+	 * Start a new IPC server to communicate with the engine.
+	 * Performs networking operations, don't run on the UI thread.
+	 * @throws ConnectException if we can't set up the IPC server
+	 */
+	public static GameConnection forNetgame(final GameConfig config, Netplay netplay) throws ConnectException {
+		final String playerName = netplay.getPlayerName();
+		GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true);
+		if(conn == null) {
+			throw new ConnectException();
+		}
+		GameConnection result = new GameConnection(conn, netplay);
+		result.setupConnection();
+		return result;
+	}
+	
+	/**
+	 * Start a new IPC server to communicate with the engine.
+	 * Performs networking operations, don't run on the UI thread.
+	 * @throws ConnectException if we can't set up the IPC server
+	 */
+	public static GameConnection forLocalGame(final GameConfig config) throws ConnectException {
+		GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false);
+		if(conn == null) {
+			throw new ConnectException();
+		}
+		GameConnection result = new GameConnection(conn, null);
+		result.setupConnection();
+		return result;
+	}
+	
+	private final Runnable tickCb = new Runnable() {
+		public void run() {
+			Flib.INSTANCE.flib_gameconn_tick(conn);
+		}
+	};
+	
+	// runs on the IPCThread
+	private void shutdown() {
+		tickHandler.stop();
+		thread.quit();
+		Flib.INSTANCE.flib_gameconn_destroy(conn);
+		conn = null;
+		if(netplay != null) {
+			mainHandler.post(new Runnable() {
+				public void run() {
+					netplay.unregisterGameMessageListener(gameMessageListener);
+				}
+			});
+		}
+	}
+	
+	// runs on the IPCThread
+	private final StrBoolCallback chatCb = new StrBoolCallback() {
+		public void callback(Pointer context, String message, boolean teamChat) {
+			if(teamChat) {
+				netplay.sendTeamChat(message);
+			} else {
+				netplay.sendChat(message);
+			}
+		}
+	};
+	
+	// runs on the IPCThread
+	private final VoidCallback connectCb = new VoidCallback() {
+		public void callback(Pointer context) {
+			Log.i("GameConnection", "Connected");
+		}
+	};
+	
+	// runs on the IPCThread
+	private final IntCallback disconnectCb = new IntCallback() {
+		public void callback(Pointer context, int reason) {
+			if(netplay != null) {
+				netplay.sendRoundFinished(reason==Frontlib.GAME_END_FINISHED);
+			}
+			shutdown();
+		}
+	};
+	
+	// runs on the IPCThread
+	private final BytesCallback engineMessageCb = new BytesCallback() {
+		public void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size) {
+			netplay.sendEngineMessage(buffer.deref(size.intValue()));
+		}
+	};
+	
+	// runs on the IPCThread
+	private final StrCallback errorMessageCb = new StrCallback() {
+		public void callback(Pointer context, String message) {
+			Log.e("GameConnection", message);
+		}
+	};
+	
+	// runs on any thread
+	private final GameMessageListener gameMessageListener = new GameMessageListener() {
+		public void onNetDisconnected() {
+			handler.post(new Runnable() {
+				public void run() {
+					Flib.INSTANCE.flib_gameconn_send_quit(conn);
+				}
+			});
+		}
+		
+		public void onMessage(final int type, final String message) {
+			handler.post(new Runnable() {
+				public void run() {
+					Flib.INSTANCE.flib_gameconn_send_textmsg(conn, type, message);
+				}
+			});
+		}
+		
+		public void onEngineMessage(final byte[] em) {
+			handler.post(new Runnable() {
+				public void run() {
+					ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(em);
+					Flib.INSTANCE.flib_gameconn_send_enginemsg(conn, ptr, NativeSizeT.valueOf(em.length));
+				}
+			});
+		}
+		
+		public void onChatMessage(final String nick, final String message) {
+			handler.post(new Runnable() {
+				public void run() {
+					Flib.INSTANCE.flib_gameconn_send_chatmsg(conn, nick, message);
+				}
+			});
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,140 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+import org.hedgewars.hedgeroid.util.TextInputDialog;
+import org.hedgewars.hedgeroid.util.TextInputDialog.TextInputDialogListener;
+import org.hedgewars.hedgeroid.util.UiUtils;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+
+/**
+ * Activity for the server lobby of a hedgewars server. Allows you to chat, join
+ * and create rooms and interact with a list of players.
+ * 
+ * Most of the functionality is handled by various fragments.
+ */
+public class LobbyActivity extends FragmentActivity implements TextInputDialogListener, NetplayStateListener {
+	private static final int DIALOG_CREATE_ROOM = 0;
+	
+    private TabHost tabHost;
+    private Netplay netplay;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        setContentView(R.layout.activity_lobby);
+        ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
+        chatFragment.setInRoom(false);
+        
+        FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+        trans.add(new NetplayStateFragment(), "netplayFragment");
+        trans.commit();
+        
+        netplay = Netplay.getAppInstance(getApplicationContext());
+        
+        // Set up a tabbed UI for medium and small screens
+        tabHost = (TabHost)findViewById(android.R.id.tabhost);
+        if(tabHost != null) {
+	        tabHost.setup();
+	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+	        tabHost.addTab(tabHost.newTabSpec("rooms").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.lobby_tab_rooms, R.drawable.roomlist_ingame)).setContent(R.id.roomListFragment));
+	        tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.lobby_tab_chat, R.drawable.edit)).setContent(R.id.chatFragment));
+	        tabHost.addTab(tabHost.newTabSpec("players").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.lobby_tab_players, R.drawable.human)).setContent(R.id.playerListFragment));
+	
+	        if (icicle != null) {
+	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+	        }
+        }
+    }
+    
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		super.onCreateOptionsMenu(menu);
+		getMenuInflater().inflate(R.menu.lobby_options, menu);
+		return true;
+	}
+	
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch(item.getItemId()) {
+		case R.id.room_create:
+	        TextInputDialog dialog = new TextInputDialog(DIALOG_CREATE_ROOM, R.string.dialog_create_room_title, 0, R.string.dialog_create_room_hint);
+	        dialog.show(getSupportFragmentManager(), "create_room_dialog");
+			return true;
+		case R.id.disconnect:
+			netplay.disconnect();
+			return true;
+		default:
+			return super.onOptionsItemSelected(item);
+		}
+	}
+	
+	@Override
+	public void onBackPressed() {
+		netplay.disconnect();
+	}
+	
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if(tabHost != null) {
+        	icicle.putString("currentTab", tabHost.getCurrentTabTag());
+        }
+    }
+    
+    public void onTextInputDialogSubmitted(int dialogId, String text) {
+    	if(text != null && text.length()>0) {
+    		netplay.sendCreateRoom(text);
+    	}
+    }
+    
+    public void onTextInputDialogCancelled(int dialogId) {
+    }
+    
+    public void onNetplayStateChanged(State newState) {
+    	switch(newState) {
+    	case CONNECTING:
+    	case NOT_CONNECTED:
+    		finish();
+    		break;
+    	case ROOM:
+    		startActivity(new Intent(getApplicationContext(), NetRoomActivity.class));
+    		break;
+    	case LOBBY:
+    		// Do nothing
+    		break;
+		default:
+			throw new IllegalStateException("Unknown connection state: "+newState);
+    	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,68 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Simple adapter for displaying the list of players in the lobby.
+ */
+public class LobbyPlayerlistAdapter extends ObservableTreeMapAdapter<String, Player> {
+	@Override
+	protected Comparator<Player> getEntryOrder() {
+		return Player.ADMIN_NAME_ORDER;
+	}
+
+	public View getView(int position, View convertView, ViewGroup parent) {
+		View v = convertView;
+		if (v == null) {
+			LayoutInflater vi = LayoutInflater.from(parent.getContext());
+			v = vi.inflate(R.layout.listview_player, null);
+		}
+
+		Player player = getItem(position);
+		TextView username = (TextView) v.findViewById(android.R.id.text1);
+		Spannable spannable = new SpannableString(player.name);
+		if(player.registered) {
+			spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+		}
+		if(player.admin) {
+			spannable.setSpan(new ForegroundColorSpan(Color.YELLOW), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+		}
+		username.setText(spannable);
+		return v;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,98 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+/**
+ * Shows the list of players in the lobby and allows some interactions with them
+ * over the context menu.
+ */
+public class LobbyPlayerlistFragment extends ListFragment {
+	private Netplay netplay;
+	private LobbyPlayerlistAdapter adapter;
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+		adapter = new LobbyPlayerlistAdapter();
+		adapter.setSource(netplay.lobbyPlayerlist);
+		setListAdapter(adapter);
+	}
+
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		adapter.invalidate();
+	}
+	
+	@Override
+	public void onActivityCreated(Bundle savedInstanceState) {
+		super.onActivityCreated(savedInstanceState);
+		registerForContextMenu(getListView());
+	}
+
+	@Override
+	public void onCreateContextMenu(ContextMenu menu, View v,
+			ContextMenuInfo menuInfo) {
+		super.onCreateContextMenu(menu, v, menuInfo);
+		AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
+		MenuInflater inflater = getActivity().getMenuInflater();
+		inflater.inflate(R.menu.lobby_playerlist_context, menu);
+		menu.setHeaderIcon(R.drawable.human);
+		menu.setHeaderTitle(adapter.getItem(info.position).name);
+	}
+	
+	@Override
+	public boolean onContextItemSelected(MenuItem item) {
+		AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
+		Player player = adapter.getItem(info.position);
+		switch(item.getItemId()) {
+		case R.id.player_info:
+			netplay.sendPlayerInfoQuery(player.name);
+			return true;
+		case R.id.player_follow:
+			netplay.sendFollowPlayer(player.name);
+			return true;
+		default:
+			return super.onContextItemSelected(item);
+		}
+	}
+	
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		return inflater.inflate(R.layout.fragment_playerlist, container, false);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LocalRoomActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,121 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.util.UiUtils;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+import android.widget.Toast;
+
+/**
+ * This activity is used to set up and start a local game.
+ */
+public class LocalRoomActivity extends FragmentActivity implements RoomStateManager.Provider, TeamAddDialog.Listener {
+	private TabHost tabHost;
+	private RoomStateManager stateManager;
+	private Button startButton;
+	
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        // TODO find a better central location / way to set up the default scheme and weaponset
+        Netplay netplay = Netplay.getAppInstance(getApplicationContext());
+        stateManager = new LocalRoomStateManager(netplay.defaultScheme, netplay.defaultWeaponset);
+        
+        setContentView(R.layout.activity_localroom);
+        startButton = (Button)findViewById(R.id.startGame);
+        
+        startButton.setOnClickListener(startButtonClickListener);
+        
+        // Set up a tabbed UI for medium and small screens
+        tabHost = (TabHost)findViewById(android.R.id.tabhost);
+        if(tabHost != null) {
+	        tabHost.setup();
+	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+	        tabHost.addTab(tabHost.newTabSpec("map").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_map, 0)).setContent(R.id.mapFragment));
+	        tabHost.addTab(tabHost.newTabSpec("settings").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_settings, 0)).setContent(R.id.settingsFragment));
+	        tabHost.addTab(tabHost.newTabSpec("teams").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_teams, 0)).setContent(R.id.teamlistContainer));
+	        
+	        if (icicle != null) {
+	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+	        }
+        }
+    }
+    
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if(tabHost != null) {
+        	icicle.putString("currentTab", tabHost.getCurrentTabTag());
+        }
+    }
+    
+	public void onTeamAddDialogSubmitted(Team newTeam) {
+		stateManager.requestAddTeam(newTeam, TeamInGame.getUnusedOrRandomColorIndex(stateManager.getTeams().values()));
+	}
+	
+	public RoomStateManager getRoomStateManager() {
+		return stateManager;
+	}
+
+	private final OnClickListener startButtonClickListener = new OnClickListener() {
+		public void onClick(View v) {
+			Map<String, TeamInGame> teams = stateManager.getTeams();
+			Set<Integer> clanColors = new TreeSet<Integer>();
+			for(TeamInGame t : teams.values()) {
+				clanColors.add(t.ingameAttribs.colorIndex);
+			}
+			if(clanColors.size()<2) {
+				if(tabHost != null) {
+					tabHost.setCurrentTabByTag("teams");
+				}
+				int errortext = teams.size()<2 ? R.string.not_enough_teams : R.string.not_enough_clans;
+				Toast.makeText(getApplicationContext(), errortext, Toast.LENGTH_SHORT).show();
+				return;
+			}
+			
+			SDLActivity.startNetgame = false;
+			SDLActivity.startConfig = new GameConfig(
+					stateManager.getGameStyle(),
+					stateManager.getScheme(),
+					stateManager.getMapRecipe(),
+					new ArrayList<TeamInGame>(stateManager.getTeams().values()),
+					stateManager.getWeaponset());
+			startActivity(new Intent(LocalRoomActivity.this, SDLActivity.class));
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LocalRoomStateManager.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,114 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+import android.util.Log;
+
+/**
+ * This RoomStateManager is responsible for keeping/changing the roomstate in local play.
+ * That is very straightforward, just react to every request by immediately changing the
+ * state.
+ */
+public class LocalRoomStateManager extends BasicRoomState {
+	private static final String TAG = LocalRoomStateManager.class.getSimpleName(); 
+
+	public LocalRoomStateManager(Scheme defaultScheme, Weaponset defaultWeaponset) {
+		setChief(true);
+		setGameStyle(GameConfig.DEFAULT_STYLE);
+		setMapRecipe(MapRecipe.makeRandomMap(0, MapRecipe.makeRandomSeed(), GameConfig.DEFAULT_THEME));
+		setScheme(defaultScheme);
+		setWeaponset(defaultWeaponset);
+	}
+	
+	public void changeMapRecipe(MapRecipe map) {
+		setMapRecipe(map);
+	}
+
+	public void changeMapTheme(String theme) {
+		setMapRecipe(getMapRecipe().withTheme(theme));
+	}
+
+	public void changeMapNameAndGenerator(String mapName) {
+		int newGenerator = MapRecipe.generatorForMapname(mapName);
+		setMapRecipe(getMapRecipe().withName(mapName).withMapgen(newGenerator));
+	}
+
+	public void changeMapTemplate(int template) {
+		setMapRecipe(getMapRecipe().withTemplateFilter(template));
+	}
+
+	public void changeMazeSize(int mazeSize) {
+		setMapRecipe(getMapRecipe().withMazeSize(mazeSize));
+	}
+
+	public void changeMapSeed(String seed) {
+		setMapRecipe(getMapRecipe().withSeed(seed));
+	}
+
+	public void changeMapDrawdata(byte[] drawdata) {
+		setMapRecipe(getMapRecipe().withDrawData(drawdata));
+	}
+
+	public void changeScheme(Scheme scheme) {
+		setScheme(scheme);
+	}
+
+	public void changeGameStyle(String style) {
+		setGameStyle(style);
+	}
+
+	public void changeWeaponset(Weaponset weaponset) {
+		setWeaponset(weaponset);
+	}
+
+	public void requestAddTeam(Team team, int colorIndex) {
+		putTeam(new TeamInGame(team, new TeamIngameAttributes("Player", colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, false)));
+	}
+
+	public void requestRemoveTeam(String teamname) {
+		removeTeam(teamname);
+	}
+
+	public void changeTeamColorIndex(String teamname, int colorIndex) {
+		TeamInGame oldTeam = getTeams().get(teamname);
+		if(oldTeam != null) {
+			putTeam(oldTeam.withAttribs(oldTeam.ingameAttribs.withColorIndex(colorIndex)));
+		} else {
+			Log.e(TAG, "Requested color change for unknown team "+ teamname);
+		}
+	}
+
+	public void changeTeamHogCount(String teamname, int hogcount) {
+		TeamInGame oldTeam = getTeams().get(teamname);
+		if(oldTeam != null) {
+			putTeam(oldTeam.withAttribs(oldTeam.ingameAttribs.withHogCount(hogcount)));
+		} else {
+			Log.e(TAG, "Requested hog count change for unknown team "+ teamname);
+		}
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,12 @@
 /*
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,66 +15,137 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+package org.hedgewars.hedgeroid;
 
-package org.hedgewars.hedgeroid;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 
 import org.hedgewars.hedgeroid.Downloader.DownloadAssets;
 import org.hedgewars.hedgeroid.Downloader.DownloadListActivity;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+import org.hedgewars.hedgeroid.util.FileUtils;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.IntentFilter;
 import android.os.Bundle;
-import android.preference.PreferenceManager;
 import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.Toast;
 
 public class MainActivity extends FragmentActivity {
-
-	private Button downloader, startGame;
+	private static final int DIALOG_NO_SDCARD = 0;
+	
+	private LocalBroadcastManager broadcastManager;
 	private ProgressDialog assetsDialog;
 
 	public void onCreate(Bundle sis){
 		super.onCreate(sis);
-		setContentView(R.layout.main);
+		setContentView(R.layout.activity_main);
 
-		downloader = (Button)findViewById(R.id.downloader);
-		startGame = (Button)findViewById(R.id.startGame);
+		broadcastManager = LocalBroadcastManager.getInstance(getApplicationContext());
+		Button startLocalGame = (Button)findViewById(R.id.startGame);
+		Button startNetGame = (Button)findViewById(R.id.joinLobby);
 
-		downloader.setOnClickListener(downloadClicker);
-		startGame.setOnClickListener(startGameClicker);
-
+		startLocalGame.setOnClickListener(startGameListener);
+		startNetGame.setOnClickListener(startNetGameListener);
 
-		String cacheDir = Utils.getCachePath(this);
-		if(cacheDir == null){
-			showDialog(0);
-		}else{
-			int versionCode = 0;
+		if(!FileUtils.isDataPathAvailable()){
+			showDialog(DIALOG_NO_SDCARD);
+		} else {
+			String existingVersion = "";
 			try {
-				versionCode = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionCode;
-			} catch (NameNotFoundException e) {
-
+				File versionFile = new File(FileUtils.getCachePath(this), "assetsversion.txt");
+				existingVersion = FileUtils.readToString(new FileInputStream(versionFile));
+			} catch(IOException e) {
 			}
-			boolean assetsCopied = PreferenceManager.getDefaultSharedPreferences(this).getInt("latestAssets", 0) >= versionCode;
-
-			if(!assetsCopied){
+			
+			String newVersion = "";
+			try {
+				newVersion = FileUtils.readToString(getAssets().open("assetsversion.txt"));
+			} catch(IOException e) {
+			}
+			
+			if(!existingVersion.equals(newVersion)) {
 				DownloadAssets assetsAsyncTask = new DownloadAssets(this);
-				assetsDialog = ProgressDialog.show(this, "Please wait a moment", "Moving assets...");
-				assetsAsyncTask.execute((Object[])null);
+				assetsDialog = ProgressDialog.show(this, "Please wait a moment", "Moving assets to SD card...");
+				assetsAsyncTask.execute();
 			}
 		}
 	}
 
+	@Override
+	protected void onResume() {
+		super.onResume();
+		broadcastManager.registerReceiver(connectedReceiver, new IntentFilter(Netplay.ACTION_CONNECTED));
+		broadcastManager.registerReceiver(connectionFailedReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
+		broadcastManager.registerReceiver(passwordRequestedReceiver, new IntentFilter(Netplay.ACTION_PASSWORD_REQUESTED));
+	}
+	
+	@Override
+	protected void onPause() {
+		super.onPause();
+		broadcastManager.unregisterReceiver(connectedReceiver);
+		broadcastManager.unregisterReceiver(connectionFailedReceiver);
+		broadcastManager.unregisterReceiver(passwordRequestedReceiver);
+		Netplay netplay = Netplay.getAppInstance(getApplicationContext());
+		if(netplay.getState() == State.CONNECTING) {
+			netplay.disconnect();
+		}
+	}
+	
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		super.onCreateOptionsMenu(menu);
+		getMenuInflater().inflate(R.menu.main_options, menu);
+		return true;
+	}
+	
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch(item.getItemId()) {
+		case R.id.download:
+			startActivityForResult(new Intent(this, DownloadListActivity.class), 0);
+			return true;
+		case R.id.preferences:
+			Toast.makeText(this, R.string.not_implemented_yet, Toast.LENGTH_SHORT).show();
+			return true;
+		case R.id.edit_weaponsets:
+			startActivity(new Intent(this, WeaponsetListActivity.class));
+			return true;
+		case R.id.edit_teams:
+			startActivity(new Intent(this, TeamListActivity.class));
+			return true;
+		default:
+			return super.onOptionsItemSelected(item);
+		}
+	}
+	
 	public Dialog onCreateDialog(int id, Bundle args){
+		switch(id) {
+		case DIALOG_NO_SDCARD:
+			return createNoSdcardDialog();
+		default:
+			throw new IndexOutOfBoundsException();
+		}
+	}
+
+	private Dialog createNoSdcardDialog() {
 		AlertDialog.Builder builder = new AlertDialog.Builder(this);
 		builder.setTitle(R.string.sdcard_not_mounted_title);
 		builder.setMessage(R.string.sdcard_not_mounted);
@@ -84,30 +157,67 @@
 
 		return builder.create();
 	}
-
+	
 	public void onAssetsDownloaded(boolean result){
-		if(result){
-			try {
-				int versionCode = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionCode;
-				PreferenceManager.getDefaultSharedPreferences(this).edit().putInt("latestAssets", versionCode).commit();
-			} catch (NameNotFoundException e) {}
-			
-		}else{
-			Toast.makeText(this, R.string.download_failed, Toast.LENGTH_LONG);
+		if(!result){
+			Toast.makeText(this, R.string.download_failed, Toast.LENGTH_LONG).show();
 		}
 		assetsDialog.dismiss();
 	}
 
-	private OnClickListener downloadClicker = new OnClickListener(){
+	private final OnClickListener startGameListener = new OnClickListener(){
 		public void onClick(View v){
-			//startActivityForResult(new Intent(getApplicationContext(), DownloadActivity.class), 0);
-			startActivityForResult(new Intent(getApplicationContext(), DownloadListActivity.class), 0);
+			startActivity(new Intent(getApplicationContext(), LocalRoomActivity.class));
+		}
+	};
+	
+	private final OnClickListener startNetGameListener = new OnClickListener() {
+		public void onClick(View v) {
+			State state = Netplay.getAppInstance(getApplicationContext()).getState();
+			switch(state) {
+			case NOT_CONNECTED:
+		        FragmentManager fm = getSupportFragmentManager();
+		        StartNetgameDialog startNetgameDialog = new StartNetgameDialog();
+		        startNetgameDialog.show(fm, "start_netgame_dialog");
+				break;
+			case CONNECTING:
+				onNetConnectingStarted();
+				break;
+			default:
+				startActivity(new Intent(getApplicationContext(), LobbyActivity.class));
+				break;
+			}
+		}
+	};
+	
+	private BroadcastReceiver connectedReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			startActivity(new Intent(getApplicationContext(), LobbyActivity.class));
+		}
+	};
+	
+	private BroadcastReceiver connectionFailedReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			if(intent.getBooleanExtra(Netplay.EXTRA_HAS_ERROR, true)) {
+				Toast.makeText(getApplicationContext(), intent.getStringExtra(Netplay.EXTRA_MESSAGE), Toast.LENGTH_LONG).show();
+			}
+		}
+	};
+	
+	private BroadcastReceiver passwordRequestedReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+	        FragmentManager fm = getSupportFragmentManager();
+	        PasswordDialog passwordDialog = new PasswordDialog(intent.getStringExtra(Netplay.EXTRA_PLAYERNAME));
+	        passwordDialog.show(fm, "fragment_password_dialog");
 		}
 	};
 
-	private OnClickListener startGameClicker = new OnClickListener(){
-		public void onClick(View v){
-			startActivity(new Intent(getApplicationContext(), StartGameActivity.class));
-		}
-	};
+	public void onNetConnectingStarted() {
+        FragmentManager fm = getSupportFragmentManager();
+        ConnectingDialog connectingDialog = new ConnectingDialog();
+        connectingDialog.show(fm, "fragment_connecting_dialog");
+	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,274 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.MapFile;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.util.CalmDownHandler;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.TableRow;
+import android.widget.Toast;
+
+/**
+ * Display a map preview, and configuration options for the map.
+ * 
+ * Mostly for layout reasons, this does not include the theme setting, which
+ * (arguably) is more a map setting than a general game setting.
+ */
+public class MapFragment extends Fragment {
+	private Spinner mapTypeSpinner, mapNameSpinner, templateSpinner, mazeSizeSpinner;
+	private TableRow nameRow, templateRow, mazeSizeRow;
+	private ImageView mapPreview;
+	
+	private List<MapFile> mapFiles;
+	private RoomStateManager stateManager;
+	private Random random = new Random();
+	private CalmDownHandler mapPreviewHandler;
+	
+	/*
+	 * Rendering the preview can take a few seconds on Android, so we want to prevent preview
+	 * requests from queueing up if maps are changed quickly. So if there is already a preview
+	 * being generated, we store our latest request in the newPreviewRequest variable instead.
+	 * Once the current preview is finished generating it will start on that one.
+	 */
+	private boolean previewGenerationInProgress;
+	private MapRecipe newPreviewRequest;
+	private MapRecipe currentMap; // kept for reference on every change to find out what changed
+	
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		View v = inflater.inflate(R.layout.fragment_map, container, false);
+		final Context appContext = getActivity().getApplicationContext();
+
+		/*
+		 * This handler will start the map preview after none of the map settings
+		 * have been updated for a short time.
+		 */
+		mapPreviewHandler = new CalmDownHandler(getActivity().getMainLooper(), new Runnable() {
+			public void run() {
+				if(!previewGenerationInProgress) {
+					mapPreview.setImageResource(R.drawable.roomlist_preparing);
+					MapPreviewGenerator.startPreviewGeneration(appContext, stateManager.getMapRecipe(), mapPreviewListener);
+					previewGenerationInProgress = true;
+				} else {
+					newPreviewRequest = stateManager.getMapRecipe();
+				}
+			}
+		}, 250);
+		
+		nameRow = (TableRow) v.findViewById(R.id.rowMapName);
+		templateRow = (TableRow) v.findViewById(R.id.rowTemplateFilter);
+		mazeSizeRow = (TableRow) v.findViewById(R.id.rowMazeSize);
+		mapPreview = (ImageView) v.findViewById(R.id.mapPreview);
+		mapPreview.setImageDrawable(null);;
+		mapPreview.setOnClickListener(mapClickListener);
+		
+		try {
+			mapFiles = FrontendDataUtils.getMaps(getActivity());
+		} catch (IOException e) {
+			Toast.makeText(getActivity().getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+			getActivity().finish();
+			return null;
+		}
+		Collections.sort(mapFiles, MapFile.MISSIONS_FIRST_NAME_ORDER);
+		
+		List<String> mapNames = MapFile.toDisplayNameList(mapFiles, getResources());
+		mapTypeSpinner = prepareSpinner(v, R.id.spinMapType, Arrays.asList(getResources().getStringArray(R.array.map_types)), mapTypeSelectedListener);
+		mapNameSpinner = prepareSpinner(v, R.id.spinMapName, mapNames, mapNameSelectedListener);
+		templateSpinner = prepareSpinner(v, R.id.spinTemplateFilter, Arrays.asList(getResources().getStringArray(R.array.map_templates)), mapTemplateSelectedListener);
+		mazeSizeSpinner = prepareSpinner(v, R.id.spinMazeSize, Arrays.asList(getResources().getStringArray(R.array.map_maze_sizes)), mazeSizeSelectedListener);
+
+		stateManager.addListener(roomStateChangeListener);
+		currentMap = stateManager.getMapRecipe();
+		if(currentMap != null) {
+			updateDisplay(currentMap);
+		}
+		setChiefState(stateManager.getChiefStatus());
+		mapPreviewHandler.activity();
+		return v;
+	}
+	
+	private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) {
+		Spinner spinner = (Spinner)v.findViewById(id);
+		ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items);
+		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+		spinner.setAdapter(adapter);
+		spinner.setOnItemSelectedListener(itemSelectedListener);
+		return spinner;
+	}
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		try {
+			stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager();
+		} catch(ClassCastException e) {
+			throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
+		}
+	}
+	
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		mapPreviewHandler.stop();
+		newPreviewRequest = null;
+		
+		stateManager.removeListener(roomStateChangeListener);
+	}
+	
+	private void setChiefState(boolean chiefState) {
+		mapTypeSpinner.setEnabled(chiefState);
+		mapNameSpinner.setEnabled(chiefState);
+		templateSpinner.setEnabled(chiefState);
+		mazeSizeSpinner.setEnabled(chiefState);
+		mapPreview.setEnabled(chiefState);
+		
+		if(chiefState) {
+			sendMapnameAndGenerator();
+			stateManager.changeMapTemplate(templateSpinner.getSelectedItemPosition());
+			stateManager.changeMazeSize(mazeSizeSpinner.getSelectedItemPosition());
+		}
+	}
+	
+	private void updateDisplay(MapRecipe map) {
+		nameRow.setVisibility(map.mapgen == Frontlib.MAPGEN_NAMED ? View.VISIBLE : View.GONE);
+		templateRow.setVisibility(map.mapgen == Frontlib.MAPGEN_REGULAR ? View.VISIBLE : View.GONE);
+		mazeSizeRow.setVisibility(map.mapgen == Frontlib.MAPGEN_MAZE ? View.VISIBLE : View.GONE);
+		
+		mapTypeSpinner.setSelection(map.mapgen);
+		int mapPosition = findMapPosition(mapFiles, map.name);
+		if(mapPosition >= 0) {
+			mapNameSpinner.setSelection(mapPosition);
+		}
+		templateSpinner.setSelection(map.templateFilter);
+		mazeSizeSpinner.setSelection(map.mazeSize);
+	}
+	
+	private static int findMapPosition(List<MapFile> mapFiles, String mapName) {
+		for(int i=0; i<mapFiles.size(); i++) {
+			if(mapName.equals(mapFiles.get(i).name)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	private void sendMapnameAndGenerator() {
+		int mapType = mapTypeSpinner.getSelectedItemPosition();
+		String mapName = mapFiles.get(mapNameSpinner.getSelectedItemPosition()).name;
+		stateManager.changeMapNameAndGenerator(MapRecipe.mapnameForGenerator(mapType, mapName));
+	}
+	
+	private final OnItemSelectedListener mapTypeSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			sendMapnameAndGenerator();
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnItemSelectedListener mapNameSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			sendMapnameAndGenerator();
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnItemSelectedListener mapTemplateSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			stateManager.changeMapTemplate(position);
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnItemSelectedListener mazeSizeSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			stateManager.changeMazeSize(position);
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnClickListener mapClickListener = new OnClickListener() {
+		public void onClick(View v) {
+			stateManager.changeMapSeed(MapRecipe.makeRandomSeed());
+			if(mapTypeSpinner.getSelectedItemPosition() == Frontlib.MAPGEN_NAMED) {
+				mapNameSpinner.setSelection(random.nextInt(mapNameSpinner.getCount()));
+			}
+		}
+	};
+	
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() {
+		@Override
+		public void onChiefStatusChanged(boolean isChief) {
+			setChiefState(isChief);
+		};
+		
+		@Override
+		public void onMapChanged(MapRecipe recipe) {
+			// Only trigger a preview update if a relevant field changed (not theme)
+			if(currentMap==null
+					|| currentMap.mapgen != recipe.mapgen
+					|| currentMap.mazeSize != recipe.mazeSize
+					|| !currentMap.name.equals(recipe.name)
+					|| !currentMap.seed.equals(recipe.seed)
+					|| currentMap.templateFilter != recipe.templateFilter
+					|| !Arrays.equals(currentMap.getDrawData(), recipe.getDrawData())) {
+				mapPreviewHandler.activity();
+			}
+			updateDisplay(recipe);
+			currentMap = recipe;
+		};
+	};
+	
+	private MapPreviewGenerator.Listener mapPreviewListener = new MapPreviewGenerator.Listener() {
+		public void onMapPreviewResult(Drawable preview) {
+			if(newPreviewRequest != null) {
+				MapPreviewGenerator.startPreviewGeneration(getActivity().getApplicationContext(), newPreviewRequest, mapPreviewListener);
+				newPreviewRequest = null;
+			} else {
+				if(mapPreview != null) {
+					mapPreview.setImageDrawable(preview);
+				}
+				previewGenerationInProgress = false;
+			}
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapPreviewGenerator.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,223 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import org.hedgewars.hedgeroid.Datastructures.MapFile;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.ByteArrayPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapRecipePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapimageCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.util.FileUtils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import com.sun.jna.Pointer;
+
+/**
+ * A class that asynchronously generates a map preview from a MapRecipe.
+ * 
+ * For named maps, this will load the preview image from the filesystem. For others,
+ * it will call the Hedgewars engine to generate a preview image. The result is sent
+ * back to a listener on the UI thread.
+ */
+public final class MapPreviewGenerator implements Runnable {
+	private static final String TAG = MapPreviewGenerator.class.getSimpleName();
+	private static final Handler mainHandler = new Handler(Looper.getMainLooper());
+	private static final long TIMEOUT_NS = 20l * 1000 * 1000 * 1000;
+
+	private final Context appContext;
+	private final MapRecipe map;
+	private final Listener listener;
+	
+	private boolean resultAvailable;
+	private Drawable result;
+	
+	public static interface Listener {
+		/**
+		 * This is called on the UI thread once the preview is ready or failed.
+		 * In case of failure, null is passed.
+		 */
+		void onMapPreviewResult(Drawable preview);
+	}
+
+	private MapPreviewGenerator(Context appContext, MapRecipe map, Listener listener) {
+		this.appContext = appContext;
+		this.map = map;
+		this.listener = listener;
+	}
+	
+	public void run() {
+		if (map.mapgen == Frontlib.MAPGEN_NAMED) {
+			postToListener(loadPreviewFromFile(appContext, map.name));
+		} else {
+			resultAvailable = false;
+			result = null;
+			MapconnPtr conn = Flib.INSTANCE.flib_mapconn_create(MapRecipePtr.createJavaOwned(map));
+			if (conn == null) {
+				postToListener(null);
+				return;
+			}
+			try {
+				int port = Flib.INSTANCE.flib_mapconn_getport(conn);
+				Flib.INSTANCE.flib_mapconn_onSuccess(conn, successCb, null);
+				Flib.INSTANCE.flib_mapconn_onFailure(conn, failureCb, null);
+	
+				String configPath;
+				try {
+					configPath = FileUtils.getCachePath(appContext).getAbsolutePath();
+				} catch(FileNotFoundException e) {
+					return;
+				}
+				
+				startEngine(configPath, port);
+				long startTime = System.nanoTime();
+				do {
+					Flib.INSTANCE.flib_mapconn_tick(conn);
+					try {
+						Thread.sleep(50);
+					} catch (InterruptedException e) {
+						// ignore
+					}
+					if(System.nanoTime()-startTime > TIMEOUT_NS) {
+						Log.w(TAG, "Error generating map preview: timeout");
+						resultAvailable = true;
+					}
+				} while(!resultAvailable); 
+			} finally {
+				Flib.INSTANCE.flib_mapconn_destroy(conn);
+				postToListener(result);
+			}
+		}
+	}
+	
+	public static void startPreviewGeneration(Context appContext, MapRecipe map, Listener listener) {
+		new Thread(new MapPreviewGenerator(appContext, map, listener)).start();
+	}
+	
+	private static Drawable loadPreviewFromFile(Context appContext, String mapName) {
+		if(!mapName.startsWith("+")) {
+			try {
+				File previewFile = MapFile.getPreviewFile(appContext, mapName);
+				return Drawable.createFromPath(previewFile.getAbsolutePath());
+			} catch (FileNotFoundException e) {
+				Log.w("MapPreviewGenerator", "Preview for map "+mapName+" not found.");
+			}
+		}
+		return null;
+	}
+	
+	private static void startEngine(final String configPath, final int port) {
+		new Thread(new Runnable() {
+			public void run() {
+				Log.d(TAG, "Starting engine "+port);
+				PascalExports.synchronizedGenLandPreview(port);
+				Log.d(TAG, "Engine finished");
+			}
+		}).start();
+	}
+	
+	private void postToListener(final Drawable result) {
+		mainHandler.post(new Runnable() {
+			public void run() {
+				listener.onMapPreviewResult(result);
+			}
+		});
+	}
+	
+	/**
+	 * Let's be extra nice here and clip off the left and right sides, so the preview is centered...
+	 * Since the image is present in bytes, we can save some effort by checking entire byte-columns first.
+	 */
+	private final MapimageCallback successCb = new MapimageCallback() {
+		public void callback(Pointer context, ByteArrayPtr buffer, int hedgehogCount) {
+			byte[] mapdata = buffer.deref(Frontlib.MAPIMAGE_BYTES);
+			
+			int leftmostPixel = Frontlib.MAPIMAGE_WIDTH;
+			int rightmostPixel = -1;
+			int bytesPerLine = Frontlib.MAPIMAGE_WIDTH/8;
+			
+			// Find the leftmost pixel
+			for(int xbyte=0; xbyte<bytesPerLine; xbyte++) {
+				for(int y=0; y<Frontlib.MAPIMAGE_HEIGHT; y++) {
+					int b = 0xff&mapdata[xbyte+y*bytesPerLine];
+					if(b != 0) {
+						leftmostPixel = Math.min(leftmostPixel, Integer.numberOfLeadingZeros(b)-24+xbyte*8);
+					}
+				}
+				if(leftmostPixel!=Frontlib.MAPIMAGE_WIDTH) break;
+			}
+			
+			// Find the rightmost pixel
+			for(int xbyte=bytesPerLine-1; xbyte>=0; xbyte--) {
+				for(int y=0; y<Frontlib.MAPIMAGE_HEIGHT; y++) {
+					int b = mapdata[xbyte+y*bytesPerLine];
+					if(b != 0) {
+						rightmostPixel = Math.max(rightmostPixel, xbyte*8+7-Integer.numberOfTrailingZeros(b));
+					}
+				}
+				if(rightmostPixel!=-1) break;
+			}
+		
+			// No pixel was set at all -> use default width
+			if(rightmostPixel==-1) {
+				leftmostPixel = 0;
+				rightmostPixel = Frontlib.MAPIMAGE_WIDTH-1;
+			}
+			
+			Bitmap bitmap = Bitmap.createBitmap(rightmostPixel-leftmostPixel+1, Frontlib.MAPIMAGE_HEIGHT, Config.ARGB_8888);
+			for(int y=0; y<Frontlib.MAPIMAGE_HEIGHT; y++) {
+				for(int x=0; x<bitmap.getWidth(); x++) {
+					bitmap.setPixel(x, y, isPixelSet(mapdata, x+leftmostPixel, y) ? Color.YELLOW : Color.TRANSPARENT);
+				}
+			}
+			result = new BitmapDrawable(bitmap);
+			resultAvailable = true;
+		}
+	};
+	
+	private static boolean isPixelSet(byte[] imgdata, int x, int y) {
+		int pixelnum = x+Frontlib.MAPIMAGE_WIDTH*y;
+		return (imgdata[pixelnum>>3] & (128>>(pixelnum&7))) != 0;
+	}
+	
+	private final StrCallback failureCb = new StrCallback() {
+		public void callback(Pointer context, String reason) {
+			Log.w(TAG, "Error generating map preview: "+reason);
+			result = null;
+			resultAvailable = true;
+		}
+	};
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/NetRoomActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,151 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.RunGameListener;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+import org.hedgewars.hedgeroid.util.UiUtils;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+
+/**
+ * This activity is used to set up and start a game on the server.
+ */
+public class NetRoomActivity extends FragmentActivity implements NetplayStateListener, TeamAddDialog.Listener, RoomStateManager.Provider, RunGameListener {
+	private TabHost tabHost;
+	private Netplay netplay;
+	private RoomStateManager stateManager;
+	private Button startButton;
+	
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        netplay = Netplay.getAppInstance(getApplicationContext());
+        netplay.registerRunGameListener(this);
+        stateManager = netplay.getRoomStateManager();
+        stateManager.addListener(roomStateChangeListener);
+        
+        setContentView(R.layout.activity_netroom);
+        startButton = (Button)findViewById(R.id.startGame);
+        
+        ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
+        chatFragment.setInRoom(true);
+        
+        FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+        trans.add(new NetplayStateFragment(), "netplayFragment");
+        trans.commit();
+        
+        startButton.setVisibility(netplay.isChief() ? View.VISIBLE : View.GONE);
+        startButton.setOnClickListener(startButtonClickListener);
+        
+        // Set up a tabbed UI for medium and small screens
+        tabHost = (TabHost)findViewById(android.R.id.tabhost);
+        if(tabHost != null) {
+	        tabHost.setup();
+	        tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+	        tabHost.addTab(tabHost.newTabSpec("map").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_map, 0)).setContent(R.id.mapFragment));
+	        tabHost.addTab(tabHost.newTabSpec("settings").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_settings, 0)).setContent(R.id.settingsFragment));
+	        tabHost.addTab(tabHost.newTabSpec("teams").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_teams, 0)).setContent(R.id.teamlistFragment));
+	        tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_chat, 0)).setContent(R.id.chatFragment));
+	        tabHost.addTab(tabHost.newTabSpec("players").setIndicator(UiUtils.createVerticalTabIndicator(tabHost, R.string.room_tab_players, 0)).setContent(R.id.playerListContainer));
+	        
+	        if (icicle != null) {
+	            tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+	        }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+    	super.onDestroy();
+    	stateManager.removeListener(roomStateChangeListener);
+    	netplay.unregisterRunGameListener(this);
+    }
+    
+	@Override
+	public void onBackPressed() {
+		netplay.sendLeaveRoom(null);
+	}
+    
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if(tabHost != null) {
+        	icicle.putString("currentTab", tabHost.getCurrentTabTag());
+        }
+    }
+    
+    public void onNetplayStateChanged(State newState) {
+    	switch(newState) {
+    	case NOT_CONNECTED:
+    	case CONNECTING:
+    	case LOBBY:
+    		finish();
+    		break;
+    	case ROOM:
+    		// Do nothing
+    		break;
+		default:
+			throw new IllegalStateException("Unknown connection state: "+newState);
+    	}
+    }
+    
+	public void onTeamAddDialogSubmitted(Team newTeam) {
+		stateManager.requestAddTeam(newTeam, TeamInGame.getUnusedOrRandomColorIndex(stateManager.getTeams().values()));
+	}
+	
+	public RoomStateManager getRoomStateManager() {
+		return stateManager;
+	}
+
+	private final OnClickListener startButtonClickListener = new OnClickListener() {
+		public void onClick(View v) {
+			netplay.sendStartGame();
+		}
+	};
+	
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() {
+		@Override
+		public void onChiefStatusChanged(boolean isChief) {
+			startButton.setVisibility(isChief ? View.VISIBLE : View.GONE);
+		}
+	};
+	
+	public void runGame(GameConfig config) {
+		SDLActivity.startConfig = config;
+		SDLActivity.startNetgame = true;
+		startActivity(new Intent(this, SDLActivity.class));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/NetplayStateFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,137 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.content.LocalBroadcastManager;
+import android.widget.Toast;
+
+/**
+ * Fragment for use by an activity that depends on the state of the network
+ * connection. The activity must implement the NetplayStateListener interface.
+ * 
+ * This fragment manages reacting to changes in the networking state by calling
+ * a callback method on the activity.
+ */
+public class NetplayStateFragment extends Fragment {
+    private Netplay netplay;
+    private Context appContext;
+    private LocalBroadcastManager broadcastManager;
+    private NetplayStateListener listener;
+    private State knownState;
+    
+    interface NetplayStateListener {
+    	/**
+    	 * This is called while the activity is running, and every time during resume, if
+    	 * a change in the networking state is detected. It is also called once
+    	 * with the initial state (which could be called a change from the "unknown" state).
+    	 */
+    	void onNetplayStateChanged(State newState);
+    } 
+    
+    @Override
+	public void onAttach(Activity activity) {
+		super.onAttach(activity);
+		try {
+			listener = (NetplayStateListener) activity;
+		} catch(ClassCastException e) {
+			throw new ClassCastException("Activity " + activity + " must implement NetplayStateListener to use NetplayStateFragment.");
+		}
+	}
+	
+	@Override
+	public void onDetach() {
+		super.onDetach();
+		listener = null;
+	}
+	
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        appContext = getActivity().getApplicationContext();
+        broadcastManager = LocalBroadcastManager.getInstance(appContext);
+        netplay = Netplay.getAppInstance(appContext);
+    }    
+
+    @Override
+    public void onResume() {
+    	super.onResume();
+    	broadcastManager.registerReceiver(disconnectReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
+    	broadcastManager.registerReceiver(leaveRoomReceiver, new IntentFilter(Netplay.ACTION_LEFT_ROOM));
+    	broadcastManager.registerReceiver(stateChangeReceiver, new IntentFilter(Netplay.ACTION_STATE_CHANGED));
+    	
+    	State newState = netplay.getState();
+		if(knownState != newState) {
+    		listener.onNetplayStateChanged(newState);
+    		knownState = newState;
+    	}
+    }
+    
+    @Override
+    public void onPause() {
+    	super.onPause();
+    	broadcastManager.unregisterReceiver(disconnectReceiver);
+    	broadcastManager.unregisterReceiver(leaveRoomReceiver);
+    	broadcastManager.unregisterReceiver(stateChangeReceiver);
+    }
+
+	private final BroadcastReceiver disconnectReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			if(intent.getBooleanExtra(Netplay.EXTRA_HAS_ERROR, true)) {
+				String message = intent.getStringExtra(Netplay.EXTRA_MESSAGE);
+				String toastText = getString(R.string.toast_disconnected, message);
+				Toast.makeText(appContext, toastText, Toast.LENGTH_LONG).show();
+			}
+		}
+	};
+	
+	private final BroadcastReceiver leaveRoomReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			int reason = intent.getIntExtra(Netplay.EXTRA_REASON, -1);
+			if(reason == Frontlib.NETCONN_ROOMLEAVE_ABANDONED) {
+				Toast.makeText(appContext, R.string.toast_room_abandoned, Toast.LENGTH_LONG).show();
+			} else if(reason == Frontlib.NETCONN_ROOMLEAVE_KICKED) {
+				Toast.makeText(appContext, R.string.toast_kicked, Toast.LENGTH_LONG).show();
+			}
+		}
+	};
+	
+	private final BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() {
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			State newState = netplay.getState();
+			listener.onNetplayStateChanged(newState);
+			knownState = newState;
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/PasswordDialog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,82 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.InputType;
+import android.text.method.PasswordTransformationMethod;
+import android.widget.EditText;
+
+/**
+ * Shown when connecting to the server, and the server requests a password.
+ */
+public class PasswordDialog extends ConnectionDependendDialogFragment {
+	String username;
+	
+	public PasswordDialog() {
+	}
+	
+	public PasswordDialog(String username) {
+		this.username = username;
+	}
+	
+	@Override
+	public void onSaveInstanceState(Bundle icicle) {
+		super.onSaveInstanceState(icicle);
+		icicle.putString("username", username);
+	}
+	
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+		if(savedInstanceState != null) {
+			username = savedInstanceState.getString("username");
+		}
+		final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+		final EditText editText = new EditText(getActivity());
+		final Netplay netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+		
+		editText.setHint(R.string.dialog_password_hint);
+		editText.setId(android.R.id.text1);
+		editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+		editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
+		builder.setView(editText);
+		builder.setTitle(R.string.dialog_password_title);
+		builder.setMessage(getString(R.string.dialog_password_message, username));
+		builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int which) {
+				String password = editText.getText().toString();
+				editText.setText("");
+				netplay.sendPassword(password);
+			}
+		});
+		return builder.create();
+	}
+	
+	@Override
+	public void onCancel(DialogInterface dialog) {
+		super.onCancel(dialog);
+		Netplay.getAppInstance(getActivity().getApplicationContext()).disconnect();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,60 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RoomPlayerlistAdapter extends ObservableTreeMapAdapter<String, PlayerInRoom> {
+	@Override
+	protected Comparator<PlayerInRoom> getEntryOrder() {
+		return AlphabeticalOrderComparator.INSTANCE;
+	}
+
+	public View getView(int position, View convertView, ViewGroup parent) {
+		View v = convertView;
+		if (v == null) {
+			LayoutInflater vi = LayoutInflater.from(parent.getContext());
+			v = vi.inflate(R.layout.listview_player, null);
+		}
+
+		PlayerInRoom player = getItem(position);
+		TextView username = (TextView) v.findViewById(android.R.id.text1);
+		username.setText(player.player.name);
+		int readyDrawable = player.ready ? R.drawable.lightbulb_on : R.drawable.lightbulb_off;
+		username.setCompoundDrawablesWithIntrinsicBounds(readyDrawable, 0, 0, 0);
+		return v;
+	}
+	
+	private static final class AlphabeticalOrderComparator implements Comparator<PlayerInRoom> {
+		public static final AlphabeticalOrderComparator INSTANCE = new AlphabeticalOrderComparator();
+		public int compare(PlayerInRoom lhs, PlayerInRoom rhs) {
+			return lhs.player.name.compareToIgnoreCase(rhs.player.name);
+		};
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,110 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class RoomPlayerlistFragment extends ListFragment implements OnItemClickListener {
+	private Netplay netplay;
+	private RoomPlayerlistAdapter adapter;
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+		adapter = new RoomPlayerlistAdapter();
+		adapter.setSource(netplay.roomPlayerlist);
+		setListAdapter(adapter);
+	}
+
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		adapter.invalidate();
+	}
+	
+	@Override
+	public void onActivityCreated(Bundle savedInstanceState) {
+		super.onActivityCreated(savedInstanceState);
+		registerForContextMenu(getListView());
+		getListView().setOnItemClickListener(this);
+	}
+
+	@Override
+	public void onCreateContextMenu(ContextMenu menu, View v,
+			ContextMenuInfo menuInfo) {
+		super.onCreateContextMenu(menu, v, menuInfo);
+		AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
+		String playerName = adapter.getItem(info.position).player.name;
+		
+		MenuInflater inflater = getActivity().getMenuInflater();
+		inflater.inflate(R.menu.room_playerlist_context, menu);
+		if(netplay.isChief() && !playerName.equals(netplay.getPlayerName())) {
+			inflater.inflate(R.menu.room_playerlist_chief_context, menu);
+		}
+		menu.setHeaderIcon(R.drawable.human);
+		menu.setHeaderTitle(playerName);
+	}
+	
+	@Override
+	public boolean onContextItemSelected(MenuItem item) {
+		AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
+		PlayerInRoom player = adapter.getItem(info.position);
+		switch(item.getItemId()) {
+		case R.id.player_info:
+			netplay.sendPlayerInfoQuery(player.player.name);
+			return true;
+		case R.id.player_kick:
+			netplay.sendKick(player.player.name);
+			return true;
+		default:
+			return super.onContextItemSelected(item);
+		}
+	}
+	
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		return inflater.inflate(R.layout.fragment_playerlist, container, false);
+	}
+	
+	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+		Player player = adapter.getItem(position).player;
+		if(player.name.equals(netplay.getPlayerName())) {
+			netplay.sendToggleReady();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomStateManager.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,110 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+/**
+ * This interface is supposed to abstract the handling of room state for several
+ * fragments that can display and manipulate it. The purpose of this is to allow
+ * using these fragments both for setting up networked and local games, despite
+ * the fact that for local games the settings can be changed immediately in
+ * memory, while they have to be sent out to the server for networked games.
+ * 
+ * If/when the state changes as result of calling one of the "changeX" or
+ * "requestX" functions, that will also trigger the corresponding change
+ * listener method. There is no guarantee that calling a changeX method will
+ * actually change the setting (e.g. if you're not room chief).
+ * 
+ * For local games, getChiefStatus is always true.
+ * 
+ * Implementations of this interface are probably not thread safe and should
+ * only be used on the UI thread.
+ */
+public interface RoomStateManager {
+	// Query current state
+	MapRecipe getMapRecipe();
+	boolean getChiefStatus();
+	Scheme getScheme();
+	String getGameStyle();
+	Weaponset getWeaponset();
+	Map<String, TeamInGame> getTeams();
+	
+	// Manipulate state
+	void changeMapRecipe(MapRecipe map);
+	void changeMapTheme(String theme);
+
+	/**
+	 * This function sets both the map's name and generator. There is no function
+	 * to change them independendly since e.g. the QtFrontend relies on them being
+	 * consistent.
+	 * 
+	 * If the name parameter is equal to one of the MapRecipe.MAPNAME_REGULAR, MAPNAME_MAZE
+	 * or MAPNAME_DRAWN constants, the map generator is set accordingly. Otherwise, the
+	 * map generator is set to represent a mapfile. The map's name is always set to
+	 * the parameter.
+	 */
+	void changeMapNameAndGenerator(String mapName);
+	void changeMapTemplate(int template);
+	void changeMazeSize(int mazeSize);
+	void changeMapSeed(String seed);
+	void changeMapDrawdata(byte[] drawdata);
+	
+	void changeScheme(Scheme scheme);
+	void changeGameStyle(String style);
+	void changeWeaponset(Weaponset weaponset);
+	
+	void requestAddTeam(Team team, int colorIndex);
+	void requestRemoveTeam(String teamname);
+	void changeTeamColorIndex(String teamname, int colorIndex);
+	void changeTeamHogCount(String teamname, int hogcount);
+	
+	// Observe changes
+	void addListener(Listener observer);
+	void removeListener(Listener observer);
+	
+	public interface Listener {
+		void onMapChanged(MapRecipe recipe);
+		void onChiefStatusChanged(boolean isChief);
+		void onSchemeChanged(Scheme scheme);
+		void onGameStyleChanged(String gameStyle);
+		void onWeaponsetChanged(Weaponset weaponset);
+		void onTeamsChanged(Map<String, TeamInGame> teams);
+	}
+	
+	public static class ListenerAdapter implements Listener {
+		public void onMapChanged(MapRecipe recipe) {}
+		public void onChiefStatusChanged(boolean isChief) {}
+		public void onSchemeChanged(Scheme scheme) {}
+		public void onGameStyleChanged(String gameStyle) {}
+		public void onWeaponsetChanged(Weaponset weaponset) {}
+		public void onTeamsChanged(Map<String, TeamInGame> teams) {}
+	}
+	
+	public interface Provider {
+		RoomStateManager getRoomStateManager();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,113 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.RoomWithId;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Displays the list of all rooms in the lobby
+ */
+public class RoomlistAdapter extends ObservableTreeMapAdapter<String, RoomWithId> {
+	private Context context;
+	
+	public RoomlistAdapter(Context context) {
+		this.context = context;
+	}
+	
+	@Override
+	protected Comparator<RoomWithId> getEntryOrder() {
+		return RoomWithId.NEWEST_FIRST_ORDER;
+	}
+	
+	@Override
+	public long getItemId(int position) {
+		return getItem(position).id;
+	}
+	
+	@Override
+	public boolean hasStableIds() {
+		return true;
+	}
+	
+	private static CharSequence formatExtra(Resources res, Room room) {
+		String ownermsg = res.getString(R.string.roomlist_owner, room.owner);
+		String mapmsg = res.getString(R.string.roomlist_map, room.formatMapName(res));
+		String scheme = room.scheme.equals(room.weapons) ? room.scheme : room.scheme + " / " + room.weapons;
+		String schememsg = res.getString(R.string.roomlist_scheme, scheme);
+		return ownermsg + ". " + mapmsg + ", " + schememsg;
+	}
+	
+	public View getView(int position, View convertView, ViewGroup parent) {
+		View v = convertView;
+		if (v == null) {
+			LayoutInflater vi = LayoutInflater.from(context);
+			v = vi.inflate(R.layout.listview_room, null);
+		}
+		
+		Room room = getItem(position).room;
+		int iconRes = room.inProgress ? R.drawable.roomlist_ingame : R.drawable.roomlist_preparing;
+		
+		if(v.findViewById(android.R.id.text1) == null) {
+			// Tabular room list
+			TextView roomnameView = (TextView)v.findViewById(R.id.roomname);
+			TextView playerCountView = (TextView)v.findViewById(R.id.playercount);
+			TextView teamCountView = (TextView)v.findViewById(R.id.teamcount);
+			TextView ownerView = (TextView)v.findViewById(R.id.owner);
+			TextView mapView = (TextView)v.findViewById(R.id.map);
+			TextView schemeView = (TextView)v.findViewById(R.id.scheme);
+			TextView weaponView = (TextView)v.findViewById(R.id.weapons);
+			
+			roomnameView.setCompoundDrawablesWithIntrinsicBounds(iconRes, 0, 0, 0);
+			roomnameView.setText(room.name);
+			if(playerCountView != null) {
+				playerCountView.setText(String.valueOf(room.playerCount));
+			}
+			if(teamCountView != null) {
+				teamCountView.setText(String.valueOf(room.teamCount));
+			}
+			ownerView.setText(room.owner);
+			mapView.setText(room.formatMapName(context.getResources()));
+			schemeView.setText(room.scheme);
+			weaponView.setText(room.weapons);
+		} else {
+			// Small room list
+			TextView v1 = (TextView)v.findViewById(android.R.id.text1);
+			TextView v2 = (TextView)v.findViewById(android.R.id.text2);
+			
+			v1.setCompoundDrawablesWithIntrinsicBounds(iconRes, 0, 0, 0);
+			v1.setText(room.name);
+			v2.setText(formatExtra(context.getResources(), room));
+		}
+		
+		return v;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,94 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.support.v4.app.ListFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+
+/**
+ * Displays the list of all rooms in the lobby
+ */
+public class RoomlistFragment extends ListFragment implements OnItemClickListener {
+	private static final int AUTO_REFRESH_INTERVAL_MS = 15000;
+	
+	private Netplay netplay;
+	private RoomlistAdapter adapter;
+	private CountDownTimer autoRefreshTimer = new CountDownTimer(Long.MAX_VALUE, AUTO_REFRESH_INTERVAL_MS) {
+		@Override
+		public void onTick(long millisUntilFinished) {
+			netplay.sendRoomlistRequest();
+		}
+		
+		@Override
+		public void onFinish() { }
+	};
+
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+		adapter = new RoomlistAdapter(getActivity());
+		adapter.setSource(netplay.roomList);
+		setListAdapter(adapter);
+	}
+
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		return inflater.inflate(R.layout.fragment_roomlist, container, false);
+	}
+	
+	@Override
+	public void onActivityCreated(Bundle savedInstanceState) {
+		super.onActivityCreated(savedInstanceState);
+		getListView().setOnItemClickListener(this);
+	}
+	
+	@Override
+	public void onResume() {
+		super.onResume();
+		autoRefreshTimer.start();
+	}
+	
+	@Override
+	public void onPause() {
+		super.onPause();
+		autoRefreshTimer.cancel();
+	}
+	
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		adapter.invalidate();
+	}
+	
+	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+		netplay.sendJoinRoom(adapter.getItem(position).room.name);
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,14 +1,40 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.com>
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
 package org.hedgewars.hedgeroid;
 
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.ConnectException;
+
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.egl.EGLContext;
 import javax.microedition.khronos.egl.EGLDisplay;
 import javax.microedition.khronos.egl.EGLSurface;
 
-import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
-import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.util.FileUtils;
 
 import android.app.Activity;
 import android.content.Context;
@@ -22,8 +48,7 @@
 import android.media.AudioManager;
 import android.media.AudioTrack;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
+import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -37,12 +62,17 @@
     SDL Activity
  */
 public class SDLActivity extends Activity {
-
+	/**
+	 * Set startConfig to the desired config when starting this activity. This avoids having to parcel all
+	 * the config objects into the Intent. Not particularly elegant, but it's actually a recommended
+	 * way to do this (http://developer.android.com/guide/faq/framework.html#3)
+	 */
+	public static volatile GameConfig startConfig;
+	public static volatile boolean startNetgame;
+	
 	// Main components
 	public static SDLActivity mSingleton;
 	private static SDLSurface mSurface;
-
-	// This is what SDL runs in. It invokes SDL_main(), eventually
 	private static Thread mSDLThread;
 
 	// Audio
@@ -59,26 +89,20 @@
 	// Load the .so
 	static {
 		System.loadLibrary("SDL");
-		//System.loadLibrary("SDL_image");
-		//System.loadLibrary("SDL_mixer");
-		//System.loadLibrary("SDL_ttf");
 		System.loadLibrary("main");
 	}
 
 	// Setup
 	protected void onCreate(Bundle savedInstanceState) {
-		//Log.v("SDL", "onCreate()");
 		super.onCreate(savedInstanceState);
 
 		// So we can call stuff from static callbacks
 		mSingleton = this;
 
 		// Set up the surface
-		GameConfig config = getIntent().getParcelableExtra("config");
-
-		mSurface = new SDLSurface(getApplication(), config);
+		mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
+		startConfig = null;
 		setContentView(mSurface);
-		SurfaceHolder holder = mSurface.getHolder();
 	}
 
 	// Events
@@ -106,42 +130,26 @@
 		Log.v("SDL", "onDestroy()");
 		// Send a quit message to the application
 		SDLActivity.nativeQuit();
-
 		// Now wait for the SDL thread to quit
 		if (mSDLThread != null) {
 			try {
 				mSDLThread.join();
 			} catch(Exception e) {
-				Log.v("SDL", "Problem stopping thread: " + e);
+				Log.w("SDL", "Problem stopping thread: " + e);
 			}
 			mSDLThread = null;
-
-			//Log.v("SDL", "Finished waiting for SDL thread");
+		}
+		mSingleton = null;
+	}
+	
+	public static void synchronizedNativeInit(String...args) {
+		synchronized(PascalExports.engineMutex) {
+			nativeInit(args);
 		}
 	}
-
-	// Messages from the SDLMain thread
-	static int COMMAND_CHANGE_TITLE = 1;
-
-	// Handler for the messages
-	Handler commandHandler = new Handler() {
-		public void handleMessage(Message msg) {
-			if (msg.arg1 == COMMAND_CHANGE_TITLE) {
-				setTitle((String)msg.obj);
-			}
-		}
-	};
-
-	// Send a message from the SDLMain thread
-	void sendCommand(int command, Object data) {
-		Message msg = commandHandler.obtainMessage();
-		msg.arg1 = command;
-		msg.obj = data;
-		commandHandler.sendMessage(msg);
-	}
-
+	
 	// C functions we call
-	public static native void nativeInit(String...args);
+	private static native void nativeInit(String...args);
 	public static native void nativeQuit();
 	public static native void nativePause();
 	public static native void nativeResume();
@@ -165,22 +173,25 @@
 		flipEGL();
 	}
 
-	public static void setActivityTitle(String title) {
+	public static void setActivityTitle(final String title) {
 		// Called from SDLMain() thread and can't directly affect the view
-		mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+		mSingleton.runOnUiThread(new Runnable() {
+			public void run() {
+				mSingleton.setTitle(title);
+			}
+		});
 	}
 
 	public static Context getContext() {
 		return mSingleton;
 	}
 
-	public static void startApp(int width, int height, GameConfig config) {
+	public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
 		// Start up the C app thread
 		if (mSDLThread == null) {
-			mSDLThread = new Thread(new SDLMain(width, height, config), "SDLThread");
+			mSDLThread = new Thread(new SDLMain(width, height, config, netgame));
 			mSDLThread.start();
-		}
-		else {
+		} else {
 			SDLActivity.nativeResume();
 		}
 	}
@@ -188,8 +199,6 @@
 	// EGL functions
 	public static boolean initEGL(int majorVersion, int minorVersion) {
 		if (SDLActivity.mEGLDisplay == null) {
-			//Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
-
 			try {
 				EGL10 egl = (EGL10)EGLContext.getEGL();
 
@@ -207,7 +216,6 @@
 					renderableType = EGL_OPENGL_ES_BIT;
 				}
 				int[] configSpec = {
-						//EGL10.EGL_DEPTH_SIZE,   16,
 						EGL10.EGL_RENDERABLE_TYPE, renderableType,
 						EGL10.EGL_NONE
 				};
@@ -219,15 +227,6 @@
 				}
 				EGLConfig config = configs[0];
 
-				/*int EGL_CONTEXT_CLIENT_VERSION=0x3098;
-                int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL10.EGL_NONE };
-                EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
-
-                if (ctx == EGL10.EGL_NO_CONTEXT) {
-                    Log.e("SDL", "Couldn't create context");
-                    return false;
-                }
-                SDLActivity.mEGLContext = ctx;*/
 				SDLActivity.mEGLDisplay = dpy;
 				SDLActivity.mEGLConfig = config;
 				SDLActivity.mGLMajor = majorVersion;
@@ -413,37 +412,74 @@
     Simple nativeInit() runnable
  */
 class SDLMain implements Runnable {
-
-	private int surfaceWidth, surfaceHeight;
-	private GameConfig config;
-
-	public SDLMain(int width, int height, GameConfig _config) {
-		config = _config;
+	public static final String TAG = "SDLMain";
+	
+    public static final int RQ_LOWRES            = 0x00000001; // use half land array
+    public static final int RQ_BLURRY_LAND       = 0x00000002; // downscaled terrain
+    public static final int RQ_NO_BACKGROUND     = 0x00000004; // don't draw background
+    public static final int RQ_SIMPLE_ROPE       = 0x00000008; // avoid drawing rope
+    public static final int RQ_2D_WATER          = 0x00000010; // disabe 3D water effect
+    public static final int RQ_SIMPLE_EXPLOSIONS = 0x00000020; // no fancy explosion effects
+    public static final int RQ_NO_FLAKES         = 0x00000040; // no flakes
+    public static final int RQ_NO_MENU_ANIM      = 0x00000080; // ammomenu appears with no animation
+    public static final int RQ_NO_DROPLETS       = 0x00000100; // no droplets
+    public static final int RQ_NO_CLAMPING       = 0x00000200; // don't clamp textures
+    public static final int RQ_NO_TOOLTIPS       = 0x00000400; // tooltips are not drawn
+    public static final int RQ_NO_VSYNC          = 0x00000800; // don't sync on vblank
+	
+	private final int surfaceWidth, surfaceHeight;
+	private final String playerName;
+	private final GameConfig config;
+	private final boolean netgame;
+	
+	public SDLMain(int width, int height, GameConfig config, boolean netgame) {
 		surfaceWidth = width;
 		surfaceHeight = height;
+		if(netgame) {
+			playerName = Netplay.getAppInstance(SDLActivity.getContext().getApplicationContext()).getPlayerName();
+		} else {
+			playerName = "Player";
+		}
+		this.config = config;
+		this.netgame = netgame;
 	}
 
 	public void run() {
 		//Set up the IPC socket server to communicate with the engine
-		EngineProtocolNetwork ipc = new EngineProtocolNetwork(config);
-
-		String path = Utils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
-		path = path.substring(0, path.length()-1);//remove the trailing '/'
-
-
-		// Runs SDL_main() with added parameters
-		SDLActivity.nativeInit(new String[] { String.valueOf(ipc.port),
-				String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
-				"0", "en.txt", "xeli", "1", "1", "1", path, ""  });
-
+		GameConnection gameConn;
+		String path;
 		try {
-			ipc.quitIPC();
-			ipc.join();
-		} catch (InterruptedException e) {
-			e.printStackTrace();
+			if(netgame) {
+				Netplay netplay = Netplay.getAppInstance(SDLActivity.mSingleton.getApplicationContext());
+				gameConn = GameConnection.forNetgame(config, netplay);
+			} else {
+				gameConn = GameConnection.forLocalGame(config);
+			}
+			
+			path = FileUtils.getDataPathFile(SDLActivity.mSingleton).getAbsolutePath();
+			Log.d(TAG, "Starting engine");
+			// Runs SDL_main() with added parameters
+			try {
+				String pPort = String.valueOf(gameConn.port);
+				String pWidth = String.valueOf(surfaceWidth);
+				String pHeight = String.valueOf(surfaceHeight);
+				String pQuality = Integer.toString(RQ_NO_FLAKES|RQ_NO_DROPLETS|RQ_SIMPLE_EXPLOSIONS);
+				String pPlayerName = Base64.encodeToString(playerName.getBytes("UTF-8"), 0);
+				SDLActivity.synchronizedNativeInit(new String[] { pPort, pWidth, pHeight, pQuality, "en.txt", pPlayerName, "1", "1", "1", path, ""  });
+			} catch (UnsupportedEncodingException e) {
+				throw new AssertionError(e); // never happens
+			}
+			Log.d(TAG, "Engine stopped");
+		} catch(ConnectException e) {
+			Log.e(TAG, "Error starting IPC connection");
+		} catch (IOException e) {
+			Log.e(TAG, "Missing SDCard");
 		}
-		Log.v("SDL", "SDL thread terminated");
-		//Log.v("SDL", "SDL thread terminated");
+		SDLActivity.mSingleton.runOnUiThread(new Runnable() { public void run() {
+			if(SDLActivity.mSingleton != null) {
+				SDLActivity.mSingleton.finish();
+			}
+		}});
 	}
 }
 
@@ -458,12 +494,13 @@
 View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
 
 	private GameConfig config;
-
+	private boolean netgame;
+	
 	// Sensors
 	private static SensorManager mSensorManager;
 
 	// Startup    
-	public SDLSurface(Context context, GameConfig _config) {
+	public SDLSurface(Context context, GameConfig _config, boolean netgame) {
 		super(context);
 		getHolder().addCallback(this); 
 
@@ -475,6 +512,7 @@
 
 		mSensorManager = (SensorManager)context.getSystemService("sensor");
 		config = _config;
+		this.netgame = netgame;
 	}
 
 	// Called when we have a valid drawing surface
@@ -544,7 +582,7 @@
 		SDLActivity.onNativeResize(width, height, sdlFormat);
 		Log.v("SDL", "Window size:" + width + "x"+height);
 
-		SDLActivity.startApp(width, height, config);
+		SDLActivity.startApp(width, height, config, netgame);
 	}
 
 	// unused
@@ -557,8 +595,9 @@
 	public boolean onKey(View  v, int keyCode, KeyEvent event) {
 		switch(keyCode){
 		case KeyEvent.KEYCODE_BACK:
-		        PascalExports.HWterminate(true);
-                        return true;
+			Log.d("SDL", "KEYCODE_BACK");
+			SDLActivity.nativeQuit();
+            return true;
 		case KeyEvent.KEYCODE_VOLUME_DOWN:
 		case KeyEvent.KEYCODE_VOLUME_UP:
 		case KeyEvent.KEYCODE_VOLUME_MUTE:
@@ -580,34 +619,29 @@
 
 	// Touch events
 	public boolean onTouch(View v, MotionEvent event) {
-		{
-			final int touchDevId = event.getDeviceId();
-			final int pointerCount = event.getPointerCount();
-			// touchId, pointerId, action, x, y, pressure
-			int actionPointerIndex = event.getActionIndex();
-			int pointerFingerId = event.getPointerId(actionPointerIndex);
-			int action = event.getActionMasked();
-
-			float x = event.getX(actionPointerIndex);
-			float y = event.getY(actionPointerIndex);
-			float p = event.getPressure(actionPointerIndex);
+		final int action = event.getAction() & MotionEvent.ACTION_MASK;
+		final int actionPointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;		
 
-			if (action == MotionEvent.ACTION_MOVE && pointerCount > 1) {
-				// TODO send motion to every pointer if its position has
-				// changed since prev event.
-				for (int i = 0; i < pointerCount; i++) {
-					pointerFingerId = event.getPointerId(i);
-					x = event.getX(i);
-					y = event.getY(i);
-					p = event.getPressure(i);
-					SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
-				}
-			} else {
-				SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+		if (action == MotionEvent.ACTION_MOVE) {
+			// TODO send motion to every pointer if its position has
+			// changed since prev event.
+			for (int i = 0; i < event.getPointerCount(); i++) {
+				sendNativeTouch(event, action, i);
 			}
+		} else {
+			sendNativeTouch(event, action, actionPointerIndex);
 		}
 		return true;
 	} 
+	
+	private static void sendNativeTouch(MotionEvent event, int action, int pointerIndex) {
+		int touchDevId = event.getDeviceId();
+		int pointerFingerId = event.getPointerId(pointerIndex);
+		float x = event.getX(pointerIndex);
+		float y = event.getY(pointerIndex);
+		float pressure = event.getPressure(pointerIndex);
+		SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, pressure);
+	}
 
 	// Sensor events
 	public void enableSensor(int sensortype, boolean enabled) {
@@ -633,6 +667,5 @@
 					event.values[2] / SensorManager.GRAVITY_EARTH);
 		}
 	}
-
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SchemeCreatorActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,8 @@
+package org.hedgewars.hedgeroid;
+
+import android.app.Activity;
+
+// TODO stub for the actual scheme editor
+public class SchemeCreatorActivity extends Activity {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SchemeListActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,8 @@
+package org.hedgewars.hedgeroid;
+
+import android.app.Activity;
+
+// TODO
+public class SchemeListActivity extends Activity {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SettingsFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,227 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Schemes;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+import org.hedgewars.hedgeroid.util.FileUtils;
+
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+public class SettingsFragment extends Fragment {
+	private Spinner styleSpinner, schemeSpinner, weaponsetSpinner, themeSpinner;
+	private ImageView themeIcon;
+	
+	private List<String> styles;
+	private List<Scheme> schemes;
+	private List<Weaponset> weaponsets;
+	private List<String> themes;
+	
+	private RoomStateManager stateManager;
+
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		View v = inflater.inflate(R.layout.fragment_settings, container, false);
+		themeIcon = (ImageView)v.findViewById(R.id.imgTheme);
+		
+		try {
+			styles = FrontendDataUtils.getGameStyles(getActivity());
+			schemes = Schemes.loadAllSchemes(getActivity());
+			weaponsets = Weaponsets.loadAllWeaponsets(getActivity());
+			themes = FrontendDataUtils.getThemes(getActivity());
+		} catch (IOException e) {
+			Toast.makeText(getActivity().getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+			getActivity().finish();
+			return null;
+		}
+		
+		Collections.sort(styles, String.CASE_INSENSITIVE_ORDER);
+		Collections.sort(schemes, Scheme.NAME_ORDER);
+		Collections.sort(weaponsets, Weaponset.NAME_ORDER);
+		Collections.sort(themes, String.CASE_INSENSITIVE_ORDER);
+		
+		styleSpinner = prepareSpinner(v, R.id.spinGameplay, styles, styleSelectedListener);
+		schemeSpinner = prepareSpinner(v, R.id.spinGamescheme, Schemes.toNameList(schemes), schemeSelectedListener);
+		weaponsetSpinner = prepareSpinner(v, R.id.spinweapons, Weaponsets.toNameList(weaponsets), weaponsetSelectedListener);
+		themeSpinner = prepareSpinner(v, R.id.spinTheme, themes, themeSelectedListener);
+		
+		stateManager.addListener(roomStateChangeListener);
+
+		if(stateManager.getGameStyle() != null) {
+			styleSpinner.setSelection(styles.indexOf(stateManager.getGameStyle()), false);
+		}
+		if(stateManager.getScheme() != null) {
+			schemeSpinner.setSelection(getSchemePosition(schemes, stateManager.getScheme().name), false);
+		}
+		if(stateManager.getWeaponset() != null) {
+			weaponsetSpinner.setSelection(getWeaponsetPosition(weaponsets, stateManager.getWeaponset().name), false);
+		}
+		if(stateManager.getMapRecipe() != null) {
+			themeSpinner.setSelection(themes.indexOf(stateManager.getMapRecipe().theme), false);
+		}
+		
+		setChiefState(stateManager.getChiefStatus());
+		
+		return v;
+	}
+	
+	private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) {
+		Spinner spinner = (Spinner)v.findViewById(id);
+		ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items);
+		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+		spinner.setAdapter(adapter);
+		spinner.setOnItemSelectedListener(itemSelectedListener);
+		return spinner;
+	}
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		try {
+			stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager();
+		} catch(ClassCastException e) {
+			throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
+		}
+	}
+	
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		stateManager.removeListener(roomStateChangeListener);
+	}
+	
+	private static int getSchemePosition(List<Scheme> schemes, String scheme) {
+		for(int i=0; i<schemes.size(); i++) {
+			if(schemes.get(i).name.equals(scheme)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	private static int getWeaponsetPosition(List<Weaponset> weaponsets, String weaponset) {
+		for(int i=0; i<weaponsets.size(); i++) {
+			if(weaponsets.get(i).name.equals(weaponset)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+	
+	private void setChiefState(boolean chiefState) {
+		styleSpinner.setEnabled(chiefState);
+		schemeSpinner.setEnabled(chiefState);
+		weaponsetSpinner.setEnabled(chiefState);
+		themeSpinner.setEnabled(chiefState);
+		
+		if(chiefState) {
+			stateManager.changeGameStyle(styles.get(styleSpinner.getSelectedItemPosition()));
+			stateManager.changeScheme(schemes.get(schemeSpinner.getSelectedItemPosition()));
+			stateManager.changeWeaponset(weaponsets.get(weaponsetSpinner.getSelectedItemPosition()));
+			stateManager.changeMapTheme(themes.get(themeSpinner.getSelectedItemPosition()));
+		}
+	}
+	
+	private final OnItemSelectedListener styleSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			stateManager.changeGameStyle(styles.get(position));
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnItemSelectedListener schemeSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			stateManager.changeScheme(schemes.get(position));
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnItemSelectedListener weaponsetSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			stateManager.changeWeaponset(weaponsets.get(position));
+		}
+		public void onNothingSelected(AdapterView<?> arg0) {}
+	};
+	
+	private final OnItemSelectedListener themeSelectedListener = new OnItemSelectedListener() {
+		public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+			stateManager.changeMapTheme(themes.get(position));
+			String theme = themes.get(position);
+			try {
+				File iconFile = FileUtils.getDataPathFile(getActivity(), "Themes", theme, "icon@2X.png");
+				Drawable themeIconDrawable = Drawable.createFromPath(iconFile.getAbsolutePath());
+				themeIcon.setImageDrawable(themeIconDrawable);
+			} catch (FileNotFoundException e) {
+				Log.e("SettingsFragment", "Unable to find preview for theme "+theme, e);
+			}
+		};
+		public void onNothingSelected(AdapterView<?> arg0) {};
+	};
+	
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.Listener() {
+		public void onWeaponsetChanged(Weaponset weaponset) {
+			weaponsetSpinner.setSelection(getWeaponsetPosition(weaponsets, weaponset.name));
+		}
+		
+		public void onTeamsChanged(Map<String, TeamInGame> teams) {}
+		
+		public void onSchemeChanged(Scheme scheme) {
+			schemeSpinner.setSelection(getSchemePosition(schemes, scheme.name));
+		}
+		
+		public void onMapChanged(MapRecipe recipe) {
+			themeSpinner.setSelection(themes.indexOf(recipe.theme));
+		}
+		
+		public void onGameStyleChanged(String gameStyle) {
+			styleSpinner.setSelection(styles.indexOf(gameStyle));
+		}
+		
+		public void onChiefStatusChanged(boolean isChief) {
+			setChiefState(isChief);
+		}
+	};
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/StartGameActivity.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,234 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-
-package org.hedgewars.hedgeroid;
-
-import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
-import org.hedgewars.hedgeroid.Datastructures.Map;
-import org.hedgewars.hedgeroid.Datastructures.Map.MapType;
-import org.hedgewars.hedgeroid.Datastructures.Scheme;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.Datastructures.Weapon;
-import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.preference.PreferenceManager;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.Spinner;
-import android.widget.Toast;
-
-public class StartGameActivity extends Activity {
-
-	public static final int ACTIVITY_TEAM_SELECTOR = 0;
-
-	private GameConfig config = null;
-	private ImageButton start, back, team;
-	private Spinner maps, gameplay, gamescheme, weapons, themes;
-	private ImageView themeIcon, mapPreview, teamCount;
-
-	public void onCreate(Bundle savedInstanceState){
-		super.onCreate(savedInstanceState);
-
-		Scheme.parseBasicFlags(this);
-		config = new GameConfig();
-
-		setContentView(R.layout.starting_game);
-
-		back = (ImageButton) findViewById(R.id.btnBack);
-		team = (ImageButton) findViewById(R.id.btnTeams);
-		start = (ImageButton) findViewById(R.id.btnStart);
-
-		maps = (Spinner) findViewById(R.id.spinMaps);
-		gameplay = (Spinner) findViewById(R.id.spinGameplay);
-		gamescheme = (Spinner) findViewById(R.id.spinGamescheme);
-		weapons = (Spinner) findViewById(R.id.spinweapons);
-		themes = (Spinner) findViewById(R.id.spinTheme);
-
-		themeIcon = (ImageView) findViewById(R.id.imgTheme);
-		mapPreview = (ImageView) findViewById(R.id.mapPreview);
-		teamCount = (ImageView) findViewById(R.id.imgTeamsCount);
-
-		start.setOnClickListener(startClicker);
-		back.setOnClickListener(backClicker);
-		team.setOnClickListener(teamClicker);
-
-		ArrayAdapter<?> adapter = new ArrayAdapter<Map>(this, R.layout.listview_item, FrontendDataUtils.getMaps(this));
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		maps.setAdapter(adapter);
-		maps.setOnItemSelectedListener(mapsClicker);
-		//set to first nonmap
-		for(int i = 0; i < adapter.getCount(); i++){
-			if(((Map)adapter.getItem(i)).getType() == MapType.TYPE_DEFAULT){
-				maps.setSelection(i, false);
-				break;
-			}
-		}
-
-		adapter = new ArrayAdapter<String>(this, R.layout.listview_item, FrontendDataUtils.getGameplay(this));
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		gameplay.setAdapter(adapter);
-		gameplay.setOnItemSelectedListener(gameplayClicker);
-		//set to first nonmap
-		for(int i = 0; i < adapter.getCount(); i++){
-			if(((String)adapter.getItem(i)).equals("None")){
-				gameplay.setSelection(i, false);
-				break;
-			}
-		}
-
-		adapter = new ArrayAdapter<Scheme>(this, R.layout.listview_item, FrontendDataUtils.getSchemes(this));
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		gamescheme.setAdapter(adapter);
-		gamescheme.setOnItemSelectedListener(schemeClicker);
-		//set to first nonmap
-		for(int i = 0; i < adapter.getCount(); i++){
-			if(((Scheme)adapter.getItem(i)).toString().equals("Default")){
-				gamescheme.setSelection(i, false);
-				break;
-			}
-		}
-		
-		
-		adapter = new ArrayAdapter<Weapon>(this, R.layout.listview_item, FrontendDataUtils.getWeapons(this));
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		weapons.setAdapter(adapter);
-		weapons.setOnItemSelectedListener(weaponClicker);
-		for(int i = 0; i < adapter.getCount(); i++){
-			if(((Weapon)adapter.getItem(i)).toString().equals("Crazy")){
-				weapons.setSelection(i, false);
-				break;
-			}
-		}
-		adapter = new ArrayAdapter<String>(this, R.layout.listview_item, FrontendDataUtils.getThemes(this));
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		themes.setAdapter(adapter);
-		themes.setOnItemSelectedListener(themesClicker);
-	}
-
-	private void startTeamsActivity(){
-		Intent i = new Intent(StartGameActivity.this, TeamSelectionActivity.class);
-		i.putParcelableArrayListExtra("teams", config.teams);
-		startActivityForResult(i, ACTIVITY_TEAM_SELECTOR);
-	}
-
-	public void onActivityResult(int requestCode, int resultCode, Intent data){
-		switch(requestCode){
-		case ACTIVITY_TEAM_SELECTOR:
-			if(resultCode == Activity.RESULT_OK){
-				Parcelable[] parcelables = (Parcelable[])data.getParcelableArrayExtra("teams");
-				config.teams.clear();
-				for(Parcelable t : parcelables){
-					config.teams.add((Team)t);
-				}
-				teamCount.getDrawable().setLevel(config.teams.size());
-			}
-			break;
-		}
-	}
-
-
-	private OnItemSelectedListener themesClicker = new OnItemSelectedListener(){
-
-		public void onItemSelected(AdapterView<?> arg0, View view, int position, long rowId) {
-			String themeName = (String) arg0.getAdapter().getItem(position);
-			Drawable themeIconDrawable = Drawable.createFromPath(Utils.getDataPath(StartGameActivity.this) + "Themes/" + themeName + "/icon@2X.png");
-			themeIcon.setImageDrawable(themeIconDrawable);
-			config.theme = themeName;
-		}
-
-		public void onNothingSelected(AdapterView<?> arg0) {
-		}
-
-	};
-
-	private OnItemSelectedListener mapsClicker = new OnItemSelectedListener(){
-
-		public void onItemSelected(AdapterView<?> arg0, View view, int position,long rowId) {
-			Map map = (Map)arg0.getAdapter().getItem(position);
-			mapPreview.setImageDrawable(map.getDrawable());
-			config.map = map;
-		}
-
-		public void onNothingSelected(AdapterView<?> arg0) {
-		}
-
-	};
-
-	private OnItemSelectedListener weaponClicker = new OnItemSelectedListener(){
-		public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
-			config.weapon = (Weapon)arg0.getAdapter().getItem(arg2);
-		}
-		public void onNothingSelected(AdapterView<?> arg0) {
-
-		}
-	};
-	private OnItemSelectedListener schemeClicker = new OnItemSelectedListener(){
-		public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
-			config.scheme = (Scheme)arg0.getAdapter().getItem(arg2);
-		}
-		public void onNothingSelected(AdapterView<?> arg0) {
-
-		}
-	};
-	private OnItemSelectedListener gameplayClicker = new OnItemSelectedListener(){
-		public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
-			//config = ()arg0.getAdapter().getItem(arg2);
-		}
-		public void onNothingSelected(AdapterView<?> arg0) {
-
-		}
-	};
-
-	private OnClickListener startClicker = new OnClickListener(){
-		public void onClick(View v) {
-			if(config.teams.size() < 2){
-				Toast.makeText(StartGameActivity.this, R.string.not_enough_teams, Toast.LENGTH_LONG).show();
-				startTeamsActivity();
-			}
-			else{
-				Intent i = new Intent(StartGameActivity.this, SDLActivity.class);
-				i.putExtra("config", config);
-				startActivity(i);}
-		}
-	};
-
-	private OnClickListener backClicker = new OnClickListener(){
-		public void onClick(View v) {
-			finish();
-		}
-	};
-
-	private OnClickListener teamClicker = new OnClickListener(){
-		public void onClick(View v) {
-			startTeamsActivity();
-		}
-	};
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/StartNetgameDialog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,95 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+public class StartNetgameDialog extends DialogFragment {
+	private static final String PREF_PLAYERNAME = "playerName";
+	
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+		SharedPreferences prefs = getActivity().getSharedPreferences("settings", Context.MODE_PRIVATE);
+		final String playerName = prefs.getString(PREF_PLAYERNAME, "Player");
+		final EditText editText = new EditText(getActivity());
+		final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+		
+		editText.setText(playerName);
+		editText.setHint(R.string.start_netgame_dialog_playername_hint);
+		editText.setId(android.R.id.text1);
+		editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
+		editText.setSingleLine();
+
+		builder.setTitle(R.string.start_netgame_dialog_title);
+		builder.setMessage(R.string.start_netgame_dialog_message);
+		builder.setView(editText);
+		builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int which) {
+				editText.setText(playerName);
+			}
+		});
+		
+		editText.setOnEditorActionListener(new OnEditorActionListener() {
+			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+				boolean handled = false;
+				if(actionId == EditorInfo.IME_ACTION_DONE) {
+					startConnection(v.getText().toString());
+					handled = true;
+				}
+				return handled;
+			}
+		});
+		
+		builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int which) {
+				startConnection(editText.getText().toString());
+			}
+		});
+
+		return builder.create();
+	}
+	
+	private void startConnection(String username) {
+		if(username.length() > 0) {
+			SharedPreferences prefs = getActivity().getSharedPreferences("settings", Context.MODE_PRIVATE);
+			Editor edit = prefs.edit();
+			edit.putString(PREF_PLAYERNAME, username);
+			edit.commit();
+			
+			Netplay.getAppInstance(getActivity().getApplicationContext()).connectToDefaultServer(username);
+			getDialog().dismiss();
+			((MainActivity)getActivity()).onNetConnectingStarted();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamAddDialog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,112 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+public class TeamAddDialog extends DialogFragment {
+	private static final String STATE_TEAMS_ALREADY_IN_GAME = "teamAlreadyInGame";
+	private ArrayList<String> teamsAlreadyInGame;
+	private List<Team> availableTeams;
+	private Listener listener;
+	
+	public static interface Listener {
+		void onTeamAddDialogSubmitted(Team newTeam);
+	}
+	
+	public TeamAddDialog() {
+		// Only for reflection-based instantiation by the framework
+	}
+	
+	TeamAddDialog(Collection<String> teamsAlreadyInGame) {
+		this.teamsAlreadyInGame = new ArrayList<String>(teamsAlreadyInGame);
+	}
+	
+	@Override
+	public void onAttach(Activity activity) {
+		super.onAttach(activity);
+		try {
+			listener = (Listener) activity;
+		} catch(ClassCastException e) {
+			throw new ClassCastException("Activity " + activity + " must implement TeamAddDialog.Listener to use TeamAddDialog.");
+		}
+	}
+	
+	@Override
+	public void onDetach() {
+		super.onDetach();
+		listener = null;
+	}
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		if(savedInstanceState != null) {
+			teamsAlreadyInGame = savedInstanceState.getStringArrayList(STATE_TEAMS_ALREADY_IN_GAME);
+		}
+		availableTeams = new ArrayList<Team>();
+		List<Team> teams = FrontendDataUtils.getTeams(getActivity());
+		for(Team team : teams) {
+			if(!teamsAlreadyInGame.contains(team.name)) {
+				availableTeams.add(team);
+			}
+		}
+		Collections.sort(availableTeams, Team.NAME_ORDER);
+	}
+	
+	// TODO use icons for the teams (corresponding to botlevel) 
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+		builder.setTitle(R.string.dialog_addteam_title);
+		builder.setIcon(R.drawable.human);
+		String[] teamNames = new String[availableTeams.size()];
+		for(int i=0; i<availableTeams.size(); i++) {
+			teamNames[i] = availableTeams.get(i).name;
+		}
+		builder.setItems(teamNames, new OnClickListener() {
+			public void onClick(DialogInterface dialog, int which) {
+				listener.onTeamAddDialogSubmitted(availableTeams.get(which));
+			}
+		});
+		return builder.create();
+	}
+	
+	@Override
+	public void onSaveInstanceState(Bundle outState) {
+		super.onSaveInstanceState(outState);
+		outState.putStringArrayList(STATE_TEAMS_ALREADY_IN_GAME, teamsAlreadyInGame);
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamCreatorActivity.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamCreatorActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,12 @@
 /*
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,31 +15,32 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 package org.hedgewars.hedgeroid;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
 
 import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.Hog;
 import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.util.FileUtils;
 
 import android.app.Activity;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.media.MediaPlayer;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.ArrayAdapter;
@@ -49,33 +52,50 @@
 import android.widget.ScrollView;
 import android.widget.SimpleAdapter;
 import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
 import android.widget.TextView;
 import android.widget.Toast;
 
-public class TeamCreatorActivity extends Activity implements Runnable{
-
+/**
+ * Edit or create a team. If a team should be edited, it is supplied in the extras
+ * as parameter oldTeamName.
+ */
+public class TeamCreatorActivity extends Activity implements Runnable {
+	public static final String PARAMETER_EXISTING_TEAMNAME = "existingTeamName";
+	private static final String TAG = TeamCreatorActivity.class.getSimpleName();
+	
 	private TextView name;
 	private Spinner difficulty, grave, flag, voice, fort;
 	private ImageView imgFort;
 	private ArrayList<ImageButton> hogDice = new ArrayList<ImageButton>();
 	private ArrayList<Spinner> hogHat = new ArrayList<Spinner>();
 	private ArrayList<EditText> hogName = new ArrayList<EditText>();
-	private ImageButton back, save, voiceButton;
+	private ImageButton voiceButton;
 	private ScrollView scroller;
 	private MediaPlayer mp = null;
-	private boolean settingsChanged = false;
-	private boolean saved = false;
-	private String fileName = null;
+	private boolean initComplete = false;
+	
+	private String existingTeamName = null;
 
-	private final List<HashMap<String, ?>> flagsData = new ArrayList<HashMap<String, ?>>();
-	private final List<HashMap<String, ?>> typesData = new ArrayList<HashMap<String, ?>>();
-	private final List<HashMap<String, ?>> gravesData = new ArrayList<HashMap<String, ?>>();
-	private final List<HashMap<String, ?>> hatsData = new ArrayList<HashMap<String, ?>>();
+	private final List<Map<String, ?>> flagsData = new ArrayList<Map<String, ?>>();
+	private final List<Map<String, ?>> typesData = new ArrayList<Map<String, ?>>();
+	private final List<Map<String, ?>> gravesData = new ArrayList<Map<String, ?>>();
+	private final List<Map<String, ?>> hatsData = new ArrayList<Map<String, ?>>();
 	private final List<String> voicesData = new ArrayList<String>();
 	private final List<String> fortsData = new ArrayList<String>();
 
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
+		initComplete = false;
+		
+		// Restore state and read parameters 
+		if(savedInstanceState != null) {
+			existingTeamName = savedInstanceState.getString(PARAMETER_EXISTING_TEAMNAME);
+		} else {
+			existingTeamName = getIntent().getStringExtra(PARAMETER_EXISTING_TEAMNAME);
+		}
+		
+		// Set up view
 		setContentView(R.layout.team_creation);
 
 		name = (TextView) findViewById(R.id.txtName);
@@ -87,15 +107,11 @@
 
 		imgFort = (ImageView) findViewById(R.id.imgFort);
 
-		back = (ImageButton) findViewById(R.id.btnBack);
-		save = (ImageButton) findViewById(R.id.btnSave);
 		voiceButton = (ImageButton) findViewById(R.id.btnPlay);
 
 		scroller = (ScrollView) findViewById(R.id.scroller);
 
-		save.setOnClickListener(saveClicker);
-		back.setOnClickListener(backClicker);
-
+		// Wire view elements
 		LinearLayout ll = (LinearLayout) findViewById(R.id.HogsContainer);
 		for (int i = 0; i < ll.getChildCount(); i++) {
 			RelativeLayout team_creation_entry = (RelativeLayout) ll.getChildAt(i);
@@ -108,107 +124,116 @@
 					.findViewById(R.id.txtTeam1));
 		}
 
-		SimpleAdapter sa = new SimpleAdapter(this, gravesData,
-				R.layout.spinner_textimg_entry, new String[] { "txt", "img" },
-				new int[] { R.id.spinner_txt, R.id.spinner_img });
-		sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry);
-		sa.setViewBinder(viewBinder);
-		grave.setAdapter(sa);
-		grave.setOnFocusChangeListener(focusser);
-
-		sa = new SimpleAdapter(this, flagsData, R.layout.spinner_textimg_entry,
-				new String[] { "txt", "img" }, new int[] { R.id.spinner_txt,
-				R.id.spinner_img });
-		sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry);
-		sa.setViewBinder(viewBinder);
-		flag.setAdapter(sa);
-		flag.setOnFocusChangeListener(focusser);
-
-		sa = new SimpleAdapter(this, typesData, R.layout.spinner_textimg_entry,
-				new String[] { "txt", "img" }, new int[] { R.id.spinner_txt,
-				R.id.spinner_img });
-		sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry);
-		difficulty.setAdapter(sa);
-		difficulty.setOnFocusChangeListener(focusser);
-
-		sa = new SimpleAdapter(this, hatsData, R.layout.spinner_textimg_entry,
-				new String[] { "txt", "img" }, new int[] { R.id.spinner_txt,
-				R.id.spinner_img });
-		sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry);
-		sa.setViewBinder(viewBinder);
+		grave.setAdapter(createMapSpinnerAdapter(gravesData));
+		flag.setAdapter(createMapSpinnerAdapter(flagsData));
+		difficulty.setAdapter(createMapSpinnerAdapter(typesData));
+		SpinnerAdapter hatAdapter = createMapSpinnerAdapter(hatsData);
 		for (Spinner spin : hogHat) {
-			spin.setAdapter(sa);
+			spin.setAdapter(hatAdapter);
 		}
 
-		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, voicesData);
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		voice.setAdapter(adapter);
-		voice.setOnFocusChangeListener(focusser);
+
+		voice.setAdapter(createListSpinnerAdapter(voicesData));
 		voiceButton.setOnClickListener(voiceClicker);
 
-		adapter = new ArrayAdapter<String>(this, R.layout.listview_item, fortsData);
-		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		fort.setAdapter(adapter);
+		fort.setAdapter(createListSpinnerAdapter(fortsData));
 		fort.setOnItemSelectedListener(fortSelector);
-		fort.setOnFocusChangeListener(focusser);
 
 		new Thread(this).start();
 	}
 
-	public void run(){
-		final ArrayList<HashMap<String, ?>> gravesDataNew = FrontendDataUtils.getGraves(this);
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				copy(gravesData, gravesDataNew);
-				((SimpleAdapter)grave.getAdapter()).notifyDataSetChanged();
-			}
-		});
-		
-		final ArrayList<HashMap<String, ?>> flagsDataNew = FrontendDataUtils.getFlags(this);
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				copy(flagsData, flagsDataNew);
-				((SimpleAdapter)flag.getAdapter()).notifyDataSetChanged();
-			}
-		});
-		
-		final ArrayList<HashMap<String, ?>> typesDataNew = FrontendDataUtils.getTypes(this);
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				copy(typesData, typesDataNew);
-				((SimpleAdapter)difficulty.getAdapter()).notifyDataSetChanged();
-			}
-		});
-		
-		final ArrayList<HashMap<String, ?>> hatsDataNew = FrontendDataUtils.getHats(this);
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				copy(hatsData, hatsDataNew);
-				((SimpleAdapter)hogHat.get(0).getAdapter()).notifyDataSetChanged();
-			}
-		});
-		
-		final ArrayList<String> voicesDataNew = FrontendDataUtils.getVoices(this);
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				copy(voicesData, voicesDataNew);
-				((ArrayAdapter<String>)voice.getAdapter()).notifyDataSetChanged();
-			}
-		});
-		
-		final ArrayList<String> fortsDataNew = FrontendDataUtils.getForts(this);
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				copy(fortsData, fortsDataNew);
-				((ArrayAdapter<String>)fort.getAdapter()).notifyDataSetChanged();
-			}
-		});
+	private SpinnerAdapter createMapSpinnerAdapter(List<? extends Map<String, ?>> data) {
+		SimpleAdapter sa = new SimpleAdapter(this, data,
+				R.layout.spinner_textimg_entry, new String[] { "txt", "img" },
+				new int[] { R.id.spinner_txt, R.id.spinner_img });
+		sa.setDropDownViewResource(R.layout.spinner_textimg_dropdown_entry);
+		sa.setViewBinder(viewBinder);
+		return sa;
+	}
+	
+	private SpinnerAdapter createListSpinnerAdapter(List<String> data) {
+		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listview_item, data);
+		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+		return adapter;
 	}
 	
-	private static <T> void copy(List<T> dest, List<T> src){
-		for(T t: src) dest.add(t);
+	public void run(){
+		try {
+			final List<Map<String, ?>> gravesDataNew = FrontendDataUtils.getGraves(this);
+			runOnUiThread(new Runnable(){
+				public void run() {
+					gravesData.addAll(gravesDataNew);
+					((SimpleAdapter)grave.getAdapter()).notifyDataSetChanged();
+				}
+			});
+			
+			final List<Map<String, ?>> flagsDataNew = FrontendDataUtils.getFlags(this);
+			runOnUiThread(new Runnable(){
+				public void run() {
+					flagsData.addAll(flagsDataNew);
+					((SimpleAdapter)flag.getAdapter()).notifyDataSetChanged();
+				}
+			});
+			
+			final List<Map<String, ?>> typesDataNew = FrontendDataUtils.getTypes(this);
+			runOnUiThread(new Runnable(){
+				public void run() {
+					typesData.addAll(typesDataNew);
+					((SimpleAdapter)difficulty.getAdapter()).notifyDataSetChanged();
+				}
+			});
+			
+			final List<Map<String, ?>> hatsDataNew = FrontendDataUtils.getHats(this);
+			runOnUiThread(new Runnable(){
+				public void run() {
+					hatsData.addAll(hatsDataNew);
+					((SimpleAdapter)hogHat.get(0).getAdapter()).notifyDataSetChanged();
+				}
+			});
+			
+			final List<String> voicesDataNew = FrontendDataUtils.getVoices(this);
+			runOnUiThread(new Runnable(){
+				public void run() {
+					voicesData.addAll(voicesDataNew);
+					((ArrayAdapter<?>)voice.getAdapter()).notifyDataSetChanged();
+				}
+			});
+			
+			final List<String> fortsDataNew = FrontendDataUtils.getForts(this);
+			runOnUiThread(new Runnable(){
+				public void run() {
+					fortsData.addAll(fortsDataNew);
+					((ArrayAdapter<?>)fort.getAdapter()).notifyDataSetChanged();
+				}
+			});
+			
+			if(existingTeamName!=null) {
+				final Team loadedTeam = Team.load(Team.getTeamfileByName(getApplicationContext(), existingTeamName));
+				if(loadedTeam==null) {
+					existingTeamName = null;
+				} else {
+					runOnUiThread(new Runnable(){
+						public void run() {
+							setTeamValues(loadedTeam);
+						}
+					});
+				}
+			}
+			runOnUiThread(new Runnable(){
+				public void run() {
+					initComplete = true;
+				}
+			});
+		} catch(FileNotFoundException e) {
+			this.runOnUiThread(new Runnable(){
+				public void run() {
+					Toast.makeText(getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+					finish();
+				}
+			});
+		}
 	}
-
+	
 	public void onDestroy() {
 		super.onDestroy();
 		if (mp != null) {
@@ -217,101 +242,70 @@
 		}
 	}
 
-	private OnFocusChangeListener focusser = new OnFocusChangeListener() {
-		public void onFocusChange(View v, boolean hasFocus) {
-			settingsChanged = true;
-		}
-
-	};
-
-	public void onBackPressed() {
-		onFinishing();
-		super.onBackPressed();
-
+	@Override
+	protected void onSaveInstanceState(Bundle outState) {
+		super.onSaveInstanceState(outState);
+		outState.putString(PARAMETER_EXISTING_TEAMNAME, existingTeamName);
 	}
 
-	private OnClickListener backClicker = new OnClickListener() {
-		public void onClick(View v) {
-			onFinishing();
-			finish();
+	public void onBackPressed() {
+		if(initComplete) {
+			saveTeam();
 		}
-	};
-
-	private void onFinishing() {
-		if (settingsChanged) {
-			setResult(RESULT_OK);
-		} else {
-			setResult(RESULT_CANCELED);
-		}
+		setResult(RESULT_OK);
+		super.onBackPressed();
 	}
 
-	private OnClickListener saveClicker = new OnClickListener() {
-		public void onClick(View v) {
-			Toast.makeText(TeamCreatorActivity.this, R.string.saved, Toast.LENGTH_SHORT).show();
-			saved = true;
-			Team team = new Team();
-			team.name = name.getText().toString();
-			HashMap<String, Object> hashmap = (HashMap<String, Object>) flag.getSelectedItem();
-
-			team.flag = (String) hashmap.get("txt");
-			team.fort = fort.getSelectedItem().toString();
-			hashmap = (HashMap<String, Object>) grave.getSelectedItem();
-			team.grave = hashmap.get("txt").toString();
-			team.hash = "0";
-			team.voice = voice.getSelectedItem().toString();
-			team.file = fileName;
-
-			hashmap = ((HashMap<String, Object>) difficulty.getSelectedItem());
-			String levelString = hashmap.get("txt").toString();
-			int levelInt;
-			if (levelString.equals(getString(R.string.human))) {
-				levelInt = 0;
-			} else if (levelString.equals(getString(R.string.bot5))) {
-				levelInt = 1;
-			} else if (levelString.equals(getString(R.string.bot4))) {
-				levelInt = 2;
-			} else if (levelString.equals(getString(R.string.bot3))) {
-				levelInt = 3;
-			} else if (levelString.equals(getString(R.string.bot2))) {
-				levelInt = 4;
-			} else {
-				levelInt = 5;
+	private void saveTeam() {
+		String teamName = name.getText().toString();
+		String teamFlag = (String)((Map<String, Object>) flag.getSelectedItem()).get("txt");
+		String teamFort = fort.getSelectedItem().toString();
+		String teamGrave = (String)((Map<String, Object>) grave.getSelectedItem()).get("txt");
+		String teamVoice = voice.getSelectedItem().toString();
+		int levelInt = (Integer)((Map<String, Object>) difficulty.getSelectedItem()).get("level");
+		
+		List<Hog> hogs = new ArrayList<Hog>();
+		for (int i = 0; i < hogName.size(); i++) {
+			String name = hogName.get(i).getText().toString();
+			String hat = ((Map<String, Object>) hogHat.get(i).getSelectedItem()).get("txt").toString();
+			hogs.add(new Hog(name, hat, levelInt));
+		}
+		
+		Team team = new Team(teamName, teamGrave, teamFlag, teamVoice, teamFort, hogs);
+		File teamsDir = new File(getFilesDir(), Team.DIRECTORY_TEAMS);
+		if (!teamsDir.exists()) teamsDir.mkdir();
+		
+		File newFile = Team.getTeamfileByName(this, teamName);
+		File oldFile = null;
+		if(existingTeamName != null) {
+			oldFile = Team.getTeamfileByName(this, existingTeamName);
+		}
+		try {
+			team.save(newFile);
+			// If the team was renamed, delete the old file.
+			if(oldFile != null && oldFile.isFile() && !oldFile.equals(newFile)) {
+				oldFile.delete();
 			}
-
-			for (int i = 0; i < hogName.size(); i++) {
-				team.hogNames[i] = hogName.get(i).getText().toString();
-				hashmap = (HashMap<String, Object>) hogHat.get(i).getSelectedItem();
-				team.hats[i] = hashmap.get("txt").toString();
-				team.levels[i] = levelInt;
-			}
-			try {
-				File teamsDir = new File(getFilesDir().getAbsolutePath() + '/' + Team.DIRECTORY_TEAMS);
-				if (!teamsDir.exists()) teamsDir.mkdir();
-				if(team.file == null){
-					team.setFileName(TeamCreatorActivity.this);
-				}
-				FileOutputStream fos = new FileOutputStream(String.format("%s/%s", teamsDir.getAbsolutePath(), team.file));
-				team.writeToXml(fos);
-			} catch (FileNotFoundException e) {
-				e.printStackTrace();
-			}
+			existingTeamName = teamName;
+		} catch(IOException e) {
+			Toast.makeText(getApplicationContext(), R.string.error_save_failed, Toast.LENGTH_SHORT).show();
 		}
-
 	};
 
 	private OnItemSelectedListener fortSelector = new OnItemSelectedListener() {
 		public void onItemSelected(AdapterView<?> arg0, View arg1,
 				int position, long arg3) {
-			settingsChanged = true;
 			String fortName = (String) arg0.getAdapter().getItem(position);
-			Drawable fortIconDrawable = Drawable.createFromPath(Utils
-					.getDataPath(TeamCreatorActivity.this)
-					+ "Forts/"
-					+ fortName + "L.png");
-			imgFort.setImageDrawable(fortIconDrawable);
+			try {
+				File fortImage = FileUtils.getDataPathFile(TeamCreatorActivity.this, "Forts", fortName, "L.png");
+				Drawable fortIconDrawable = Drawable.createFromPath(fortImage.getAbsolutePath());
+				imgFort.setImageDrawable(fortIconDrawable);
+			} catch(IOException e) {
+				Log.e(TAG, "Unable to show fort image", e);
+			}
 			scroller.fullScroll(ScrollView.FOCUS_DOWN);// Scroll the scrollview
 			// to the bottom, work
-			// around for scollview
+			// around for scrollview
 			// invalidation (scrolls
 			// back to top)
 		}
@@ -324,9 +318,7 @@
 	private OnClickListener voiceClicker = new OnClickListener() {
 		public void onClick(View v) {
 			try {
-				File dir = new File(String.format("%sSounds/voices/%s",
-						Utils.getDataPath(TeamCreatorActivity.this),
-						voice.getSelectedItem()));
+				File dir = FileUtils.getDataPathFile(TeamCreatorActivity.this, "Sounds", "voices", (String)voice.getSelectedItem());
 				String file = "";
 				File[] dirs = dir.listFiles();
 				File f = dirs[(int) Math.round(Math.random() * dirs.length)];
@@ -341,63 +333,57 @@
 				mp.prepare();
 				mp.start();
 			} catch (IllegalArgumentException e) {
-				e.printStackTrace();
+				Log.e(TAG, "Unable to play voice sample", e);
 			} catch (IllegalStateException e) {
-				e.printStackTrace();
+				Log.e(TAG, "Unable to play voice sample", e);
 			} catch (IOException e) {
-				e.printStackTrace();
+				Log.e(TAG, "Unable to play voice sample", e);
 			}
 		}
 	};
 
+	@SuppressWarnings("unchecked")
 	private void setTeamValues(Team t){
-
-		if (t != null) {
+		if (t == null) {
+			return;
+		}
+		
+		try {
 			name.setText(t.name);
-			int position = ((ArrayAdapter<String>) voice.getAdapter()).getPosition(t.voice);
-			voice.setSelection(position);
-
-			position = ((ArrayAdapter<String>) fort.getAdapter()).getPosition(t.fort);
-			fort.setSelection(position);
-
-			position = 0;
-			for (HashMap<String, ?> hashmap : typesData) {
-				if (hashmap.get("txt").equals(t.levels[0])) {
-					difficulty.setSelection(position);
-					break;
-				}
+			voice.setSelection(findPosition((ArrayAdapter<String>) voice.getAdapter(), t.voice));
+			fort.setSelection(findPosition((ArrayAdapter<String>) fort.getAdapter(), t.fort));
+			difficulty.setSelection(findPosition(typesData, "level", Integer.valueOf(t.hogs.get(0).level)));
+			grave.setSelection(findPosition(gravesData, "txt", t.grave));
+			flag.setSelection(findPosition(flagsData, "txt", t.flag));
+	
+			for (int i = 0; i < Team.HEDGEHOGS_PER_TEAM; i++) {
+				hogHat.get(i).setSelection(findPosition(hatsData, "txt", t.hogs.get(i).hat));
+				hogName.get(i).setText(t.hogs.get(i).name);
 			}
-
-			position = 0;
-			for (HashMap<String, ?> hashmap : gravesData) {
-				if (hashmap.get("txt").equals(t.grave)) {
-					grave.setSelection(position);
-					break;
-				}
-			}
-
-			position = 0;
-			for (HashMap<String, ?> hashmap : typesData) {
-				if (hashmap.get("txt").equals(t.flag)) {
-					flag.setSelection(position);
-					break;
-				}
-			}
-
-			for (int i = 0; i < Team.maxNumberOfHogs; i++) {
-				position = 0;
-				for (HashMap<String, ?> hashmap : hatsData) {
-					if (hashmap.get("txt").equals(t.hats[i])) {
-						hogHat.get(i).setSelection(position);
-					}
-				}
-
-				hogName.get(i).setText(t.hogNames[i]);
-			}
-			this.fileName = t.file;
+		} catch(NoSuchElementException e) {
+			Toast.makeText(getApplicationContext(), R.string.error_team_attribute_not_found, Toast.LENGTH_LONG).show();
+			finish();
 		}
 	}
 
+	int findPosition(ArrayAdapter<String> adapter, String value) throws NoSuchElementException {
+		int position = adapter.getPosition(value);
+		if(position<0) {
+			throw new NoSuchElementException();
+		}
+		return position;
+	}
+	
+	int findPosition(List<? extends Map<String, ?>> data, String key, Object value) throws NoSuchElementException {
+		int position = 0;
+		for (Map<String, ?> map : data) {
+			if (map.get(key).equals(value)) {
+				return position;
+			}
+			position++;
+		}
+		throw new NoSuchElementException();
+	}
 
 	private SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() {
 
@@ -412,5 +398,4 @@
 			}
 		}
 	};
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamListActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,129 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ImageButton;
+import android.widget.SimpleAdapter;
+
+public class TeamListActivity extends ListActivity implements OnItemClickListener {
+	private List<Team> teams;
+	private ImageButton addButton;
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_teamlist);
+		addButton = (ImageButton)findViewById(R.id.btnAdd);
+		addButton.setOnClickListener(new OnClickListener() {
+			public void onClick(View v) {
+				editTeam(null);
+			}
+		});
+	}
+	
+	@Override
+	public void onResume() {
+		super.onResume();
+		updateList();
+		getListView().setOnItemClickListener(this);
+		registerForContextMenu(getListView());
+	}
+	
+	public void onItemClick(AdapterView<?> adapterView, View v, int position, long arg3) {
+		editTeam(teams.get(position).name);
+	}
+	
+	@Override
+	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuinfo){
+		menu.add(ContextMenu.NONE, 0, ContextMenu.NONE, R.string.edit);
+		menu.add(ContextMenu.NONE, 1, ContextMenu.NONE, R.string.delete);
+	}
+	
+	@Override
+	public boolean onContextItemSelected(MenuItem item){
+		AdapterView.AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
+		int position = menuInfo.position;
+		Team team = teams.get(position);
+		switch(item.getItemId()){
+		case 0:
+			editTeam(team.name);
+			return true;
+		case 1:
+			Team.getTeamfileByName(getApplicationContext(), team.name).delete();
+			updateList();
+			return true;
+		}
+		return false;
+	}
+	
+	private void updateList() {
+		teams = FrontendDataUtils.getTeams(getApplicationContext());
+		Collections.sort(teams, Team.NAME_ORDER);
+		SimpleAdapter adapter = new SimpleAdapter(this, teamsToMaps(teams), R.layout.team_selection_entry_simple, new String[]{"txt", "img"}, new int[]{R.id.txtName, R.id.imgDifficulty});
+		setListAdapter(adapter);
+	}
+	
+	private void editTeam(String teamName) {
+		Intent i = new Intent(this, TeamCreatorActivity.class);
+		i.putExtra(TeamCreatorActivity.PARAMETER_EXISTING_TEAMNAME, teamName);
+		startActivity(i);
+	}
+
+	private static final int[] botlevelDrawables = new int[] {
+		R.drawable.human, R.drawable.bot5, R.drawable.bot4, R.drawable.bot3, R.drawable.bot2, R.drawable.bot1
+	};
+	
+	private List<Map<String, ?>> teamsToMaps(List<Team> teams) {
+		List<Map<String, ?>> result = new ArrayList<Map<String,?>>();
+		for(Team t : teams) {
+			HashMap<String, Object> map = new HashMap<String, Object>();
+			map.put("team", t);
+			map.put("txt", t.name);
+			int botlevel = t.hogs.get(0).level;
+			if(botlevel<0 || botlevel>=botlevelDrawables.length) {
+				map.put("img", R.drawable.bot1);
+			} else {
+				map.put("img", botlevelDrawables[botlevel]);
+			}
+			result.add(map);
+		}
+		return result;
+	}
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamSelectionActivity.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-
-package org.hedgewars.hedgeroid;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.view.ContextMenu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.RelativeLayout;
-import android.widget.SimpleAdapter;
-import android.widget.SimpleAdapter.ViewBinder;
-import android.widget.TextView;
-
-public class TeamSelectionActivity extends Activity implements Runnable{
-
-	private static final int ACTIVITY_TEAMCREATION = 0;
-
-	private ImageButton addTeam, back;
-	private ListView availableTeams, selectedTeams;
-	private List<HashMap<String, Object>> availableTeamsList, selectedTeamsList;
-	private TextView txtInfo;
-
-	public void onCreate(Bundle savedInstanceState){
-		super.onCreate(savedInstanceState);
-
-		setContentView(R.layout.team_selector);
-
-		addTeam = (ImageButton) findViewById(R.id.btnAdd);
-		back = (ImageButton) findViewById(R.id.btnBack);
-		txtInfo = (TextView) findViewById(R.id.txtInfo);
-		selectedTeams = (ListView) findViewById(R.id.selectedTeams);
-		availableTeams = (ListView) findViewById(R.id.availableTeams);
-		addTeam.setOnClickListener(addTeamClicker);
-		back.setOnClickListener(backClicker);
-
-		availableTeamsList = new ArrayList<HashMap<String, Object>>();
-		SimpleAdapter adapter = new SimpleAdapter(this, availableTeamsList, R.layout.team_selection_entry_simple, new String[]{"txt", "img"}, new int[]{R.id.txtName, R.id.imgDifficulty});
-		availableTeams.setAdapter(adapter);
-		availableTeams.setOnItemClickListener(availableClicker);
-		registerForContextMenu(availableTeams);
-
-		selectedTeamsList = new ArrayList<HashMap<String, Object>>();
-		adapter = new SimpleAdapter(this, selectedTeamsList, R.layout.team_selection_entry, new String[]{"txt", "img", "color", "count"}, new int[]{R.id.txtName, R.id.imgDifficulty, R.id.teamColor, R.id.teamCount});
-		adapter.setViewBinder(viewBinder);
-		selectedTeams.setAdapter(adapter);
-		selectedTeams.setOnItemClickListener(selectedClicker);
-
-		txtInfo.setText(String.format(getResources().getString(R.string.teams_info_template), selectedTeams.getChildCount()));
-
-		new Thread(this).start();//load the teams from xml async
-	}
-
-	public void run(){
-		List<HashMap<String, Object>> teamsList = FrontendDataUtils.getTeams(this);//teams from xml
-		ArrayList<Team> teamsStartGame = getIntent().getParcelableArrayListExtra("teams");//possible selected teams
-
-		for(HashMap<String, Object> hashmap : teamsList){
-			boolean added = false;
-			for(Team t : teamsStartGame){
-				if(((Team)hashmap.get("team")).equals(t)){//add to available or add to selected
-					selectedTeamsList.add(FrontendDataUtils.teamToMap(t));//create a new hashmap to ensure all variables are entered into the map
-					added = true;
-					break;
-				}
-			}
-			if(!added) availableTeamsList.add(hashmap);
-		}
-
-		this.runOnUiThread(new Runnable(){
-			public void run() {
-				((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-				((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();		
-			}
-		});
-	}
-
-	private ViewBinder viewBinder = new ViewBinder(){
-		public boolean setViewValue(View view, Object data,	String textRepresentation) {
-			switch(view.getId()){
-			case R.id.teamColor:
-				setTeamColor(view, (Integer)data);
-				return true;
-			case R.id.teamCount:
-				setTeamHogCount((ImageView)view, (Integer)data);
-				return true;
-			default:
-				return false;
-			}
-		}
-	};
-
-	public void onActivityResult(int requestCode, int resultCode, Intent data){
-		if(requestCode == ACTIVITY_TEAMCREATION){
-			if(resultCode == Activity.RESULT_OK){
-				updateListViews();
-			}
-		}else{
-			super.onActivityResult(requestCode, resultCode, data);
-		}
-	}
-
-	/*
-	 * Updates the list view when TeamCreationActivity is shutdown and the user returns to this point
-	 */
-	private void updateListViews(){
-		unregisterForContextMenu(availableTeams);
-		availableTeamsList = FrontendDataUtils.getTeams(this);
-		ArrayList<HashMap<String, Object>> toBeRemoved = new ArrayList<HashMap<String, Object>>();
-		for(HashMap<String, Object> hashmap : selectedTeamsList){
-			String name = (String)hashmap.get("txt");
-
-			for(HashMap<String, Object> hash : availableTeamsList){
-				if(name.equals((String)hash.get("txt"))){
-					toBeRemoved.add(hash);
-				}
-			}
-		}
-		for(HashMap<String, Object> hash: toBeRemoved) availableTeamsList.remove(hash);
-
-		SimpleAdapter adapter = new SimpleAdapter(this, availableTeamsList, R.layout.team_selection_entry, new String[]{"txt", "img"}, new int[]{R.id.txtName, R.id.imgDifficulty});
-		availableTeams.setAdapter(adapter);
-		registerForContextMenu(availableTeams);
-		availableTeams.setOnItemClickListener(availableClicker);
-
-
-	}
-
-	private void setTeamColor(int position, int color){
-		View iv = ((RelativeLayout)selectedTeams.getChildAt(position)).findViewById(R.id.teamCount);
-		setTeamColor(iv, color);
-	}
-	private void setTeamColor(View iv, int color){
-		iv.setBackgroundColor(0xFF000000 + color);
-	}
-
-	private void setTeamHogCount(int position, int count){
-		ImageView iv = (ImageView)((RelativeLayout)selectedTeams.getChildAt(position)).findViewById(R.id.teamCount);
-		setTeamHogCount(iv, count);
-	}
-
-	private void setTeamHogCount(ImageView iv, int count){
-
-		switch(count){
-		case 0:
-			iv.setImageResource(R.drawable.teamcount0);
-			break;
-		case 1:
-			iv.setImageResource(R.drawable.teamcount1);
-			break;
-		case 2:
-			iv.setImageResource(R.drawable.teamcount2);
-			break;
-		case 3:
-			iv.setImageResource(R.drawable.teamcount3);
-			break;
-		case 4:
-			iv.setImageResource(R.drawable.teamcount4);
-			break;
-		case 5:
-			iv.setImageResource(R.drawable.teamcount5);
-			break;
-		case 6:
-			iv.setImageResource(R.drawable.teamcount6);
-			break;
-		case 7:
-			iv.setImageResource(R.drawable.teamcount7);
-			break;
-		case 8:
-			iv.setImageResource(R.drawable.teamcount8);
-			break;
-		case 9:
-			iv.setImageResource(R.drawable.teamcount9);
-			break;
-		}
-	}
-
-	public void onBackPressed(){
-		returnTeams();
-		super.onBackPressed();
-	}
-
-	private OnClickListener addTeamClicker = new OnClickListener(){
-		public void onClick(View v) {
-			startActivityForResult(new Intent(TeamSelectionActivity.this, TeamCreatorActivity.class), ACTIVITY_TEAMCREATION);
-		}
-	};
-
-	private OnClickListener backClicker = new OnClickListener(){
-		public void onClick(View v){
-			returnTeams();
-			finish();
-		}
-	};
-
-	private OnItemClickListener availableClicker = new OnItemClickListener(){
-		public void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {
-			selectAvailableTeamsItem(position);
-		}
-	};
-	private OnItemClickListener selectedClicker = new OnItemClickListener(){
-		public void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {
-			availableTeamsList.add((HashMap<String, Object>) selectedTeamsList.get(position));
-			selectedTeamsList.remove(position);
-			((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-			((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-
-			txtInfo.setText(String.format(getResources().getString(R.string.teams_info_template), selectedTeamsList.size()));
-		}
-
-	};
-
-	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuinfo){
-		menu.add(ContextMenu.NONE, 0, ContextMenu.NONE, R.string.select);
-		menu.add(ContextMenu.NONE, 2, ContextMenu.NONE, R.string.edit);
-		menu.add(ContextMenu.NONE, 1, ContextMenu.NONE, R.string.delete);
-
-	}
-	public boolean onContextItemSelected(MenuItem item){
-		AdapterView.AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
-		int position = menuInfo.position;
-		switch(item.getItemId()){
-		case 0://select
-			selectAvailableTeamsItem(position);
-			return true;
-		case 1://delete
-			Team team = (Team)availableTeamsList.get(position).get("team");
-			File f = new File(String.format("%s/%s/%s", TeamSelectionActivity.this.getFilesDir(), Team.DIRECTORY_TEAMS, team.file));
-			f.delete();
-			availableTeamsList.remove(position);
-			((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-			return true;
-		case 2://edit
-			Intent i = new Intent(TeamSelectionActivity.this, TeamCreatorActivity.class);
-			Team t = (Team)availableTeamsList.get(position).get("team");
-			i.putExtra("team", t);
-			startActivityForResult(i, ACTIVITY_TEAMCREATION);
-			return true;
-		}
-		return false;
-	}
-
-	private void selectAvailableTeamsItem(int position){
-		HashMap<String, Object> hash = (HashMap<String, Object>) availableTeamsList.get(position);
-		Team t = (Team)hash.get("team");
-		int[] illegalcolors = new int[selectedTeamsList.size()];
-		for(int i = 0; i < selectedTeamsList.size(); i++){
-			illegalcolors[i] = ((Team)selectedTeamsList.get(i).get("team")).color;
-		}
-		t.setRandomColor(illegalcolors);
-		hash.put("color", t.color);
-		hash.put("count", t.hogCount);
-
-		selectedTeamsList.add(hash);
-		availableTeamsList.remove(position);
-		((SimpleAdapter)availableTeams.getAdapter()).notifyDataSetChanged();
-		((SimpleAdapter)selectedTeams.getAdapter()).notifyDataSetChanged();
-
-		txtInfo.setText(String.format(getResources().getString(R.string.teams_info_template), selectedTeamsList.size()));
-	}
-
-	private void returnTeams(){
-		int teamsCount = selectedTeamsList.size();
-		Intent i = new Intent();
-		Parcelable[] teams = new Parcelable[teamsCount];
-		for(int x = 0 ; x < teamsCount; x++){
-			teams[x] = (Team)selectedTeamsList.get(x).get("team");
-		}
-		i.putExtra("teams", teams);
-		setResult(Activity.RESULT_OK, i);
-
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,154 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+public class TeamlistAdapter extends BaseAdapter {
+	private boolean colorHogcountEnabled = false;
+	private Listener listener;
+	private List<TeamInGame> teams = new ArrayList<TeamInGame>();
+	
+	public void setColorHogcountEnabled(boolean colorHogcountEnabled) {
+		this.colorHogcountEnabled = colorHogcountEnabled;
+		notifyDataSetChanged();
+	}
+	
+	public void setListener(Listener listener) {
+		this.listener = listener;
+	}
+	
+	public int getCount() {
+		return teams.size();
+	}
+	
+	public TeamInGame getItem(int position) {
+		return teams.get(position);
+	}
+	
+	public long getItemId(int position) {
+		return position;
+	}
+	
+	@Override
+	public boolean hasStableIds() {
+		return false;
+	}
+	
+	public void updateTeamlist(Collection<TeamInGame> newTeams) {
+		teams.clear();
+		teams.addAll(newTeams);
+		Collections.sort(teams, TeamInGame.NAME_ORDER);
+		notifyDataSetChanged();
+	}
+	
+	public View getView(int position, View convertView, ViewGroup parent) {
+		View v = convertView;
+		if (v == null) {
+			LayoutInflater vi = LayoutInflater.from(parent.getContext());
+			v = vi.inflate(R.layout.listview_team, null);
+		}
+
+		TeamInGame team = getItem(position);
+		TextView teamNameView = (TextView) v.findViewById(android.R.id.text1);
+		ImageButton colorButton = (ImageButton) v.findViewById(R.id.colorButton);
+		ImageButton hogCountButton = (ImageButton) v.findViewById(R.id.hogCountButton);
+		
+		teamNameView.setText(team.team.name);
+		int teamImage;
+		if(team.ingameAttribs.remoteDriven) {
+			teamImage = R.drawable.team_net_by_level;
+		} else {
+			teamImage = R.drawable.team_local_by_level;
+		}
+		
+		Drawable d = parent.getContext().getResources().getDrawable(teamImage).mutate();
+		d.setLevel(team.team.hogs.get(0).level);
+		teamNameView.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);
+		hogCountButton.getDrawable().setLevel(team.ingameAttribs.hogCount);
+		colorButton.setImageDrawable(new ColorDrawable(TeamIngameAttributes.TEAM_COLORS[team.ingameAttribs.colorIndex]));
+		
+		colorButton.setEnabled(colorHogcountEnabled);
+		hogCountButton.setEnabled(colorHogcountEnabled);
+		
+		colorButton.setOnClickListener(new ButtonClickListener(team, Type.COLOR_BUTTON));
+		hogCountButton.setOnClickListener(new ButtonClickListener(team, Type.HOGCOUNT_BUTTON));
+		
+		if(team.ingameAttribs.remoteDriven) {
+			teamNameView.setClickable(false);
+		} else {
+			teamNameView.setOnClickListener(new ButtonClickListener(team, Type.TEAM_VIEW));
+		}
+		
+		return v;
+	}
+	
+	private static enum Type {COLOR_BUTTON, HOGCOUNT_BUTTON, TEAM_VIEW}
+	private final class ButtonClickListener implements OnClickListener {
+		private final TeamInGame team;
+		private final Type type;
+		
+		public ButtonClickListener(TeamInGame team, Type type) {
+			this.team = team;
+			this.type = type;
+		}
+		
+		public void onClick(View v) {
+			if(listener != null) {
+				switch(type) {
+				case COLOR_BUTTON:
+					listener.onColorClicked(team);
+					break;
+				case HOGCOUNT_BUTTON:
+					listener.onHogcountClicked(team);
+					break;
+				case TEAM_VIEW:
+					listener.onTeamClicked(team);
+					break;
+				default:
+					throw new IllegalStateException();	
+				}
+			}
+		}
+	}
+	
+	public interface Listener {
+		void onTeamClicked(TeamInGame team);
+		void onColorClicked(TeamInGame team);
+		void onHogcountClicked(TeamInGame team);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistFragment.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,119 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class TeamlistFragment extends ListFragment implements TeamlistAdapter.Listener {
+	private TeamlistAdapter adapter;
+	private Button addTeamButton;
+	private RoomStateManager stateManager;
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		try {
+			stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager();
+		} catch(ClassCastException e) {
+			throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
+		}
+		adapter = new TeamlistAdapter();
+		adapter.updateTeamlist(stateManager.getTeams().values());
+		adapter.setColorHogcountEnabled(stateManager.getChiefStatus());
+		adapter.setListener(this);
+		setListAdapter(adapter);
+		stateManager.addListener(roomStateChangeListener);
+	}
+
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		View v = inflater.inflate(R.layout.fragment_teamlist, container, false);
+		addTeamButton = (Button)v.findViewById(R.id.addTeamButton);
+		addTeamButton.setOnClickListener(new OnClickListener() {
+			public void onClick(View v) {
+				new TeamAddDialog(getCurrentTeamNames()).show(getFragmentManager(), "team_add_dialog");
+			}
+		});
+		
+		addTeamButton.setEnabled(stateManager.getTeams().size() < Team.maxNumberOfTeams);
+		
+		return v;
+	}
+	
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		adapter.setListener(null);
+		stateManager.removeListener(roomStateChangeListener);
+	}
+
+	private Collection<String> getCurrentTeamNames() {
+		List<String> names = new ArrayList<String>();
+		for(TeamInGame team : stateManager.getTeams().values()) {
+			names.add(team.team.name);
+		}
+		return names;
+	}
+	
+	public void onColorClicked(TeamInGame team) {
+		stateManager.changeTeamColorIndex(team.team.name, (team.ingameAttribs.colorIndex+1)%TeamIngameAttributes.TEAM_COLORS.length);
+	}
+	
+	public void onHogcountClicked(TeamInGame team) {
+		int newHogCount = team.ingameAttribs.hogCount+1;
+		if(newHogCount>Team.HEDGEHOGS_PER_TEAM) {
+			newHogCount = 1;
+		}
+		stateManager.changeTeamHogCount(team.team.name, newHogCount);
+	}
+	
+	public void onTeamClicked(TeamInGame team) {
+		stateManager.requestRemoveTeam(team.team.name);
+	}
+	
+	private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() {
+		@Override
+		public void onChiefStatusChanged(boolean isChief) {
+			adapter.setColorHogcountEnabled(isChief);
+		};
+		
+		@Override
+		public void onTeamsChanged(Map<String, TeamInGame> teams) {
+			adapter.updateTeamlist(teams.values());
+			addTeamButton.setEnabled(teams.size() < Team.maxNumberOfTeams);
+		};
+	};
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TextImageAdapter.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TextImageAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -2,9 +2,10 @@
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,10 +14,9 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-
 package org.hedgewars.hedgeroid;
 import java.util.ArrayList;
 import java.util.HashMap;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/UserInput/TouchInterface.java	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/UserInput/TouchInterface.java	Sun Nov 18 23:10:26 2012 +0400
@@ -2,9 +2,10 @@
  * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
  * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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 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; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,9 +14,8 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-
 package org.hedgewars.hedgeroid.UserInput;
 
 import org.hedgewars.hedgeroid.SDLActivity;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Utils.java	Sun Nov 18 23:09:29 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,221 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.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
- */
-
-
-package org.hedgewars.hedgeroid;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.os.Environment;
-import android.util.Log;
-
-public class Utils {
-
-	private static final String ROOT_DIR = "Data/";
-
-	/**
-	 * get the path to which we should download all the data files
-	 * @param c context 
-	 * @return absolute path
-	 */
-	public static String getCachePath(Context c){
-		if(Build.VERSION.SDK_INT < 8){//8 == Build.VERSION_CODES.FROYO
-			return PreFroyoSDCardDir.getDownloadPath(c) + '/';
-		}else{
-			return FroyoSDCardDir.getDownloadPath(c) + '/';
-		}
-	}
-
-	public static String getDataPath(Context c){
-		return getCachePath(c) + ROOT_DIR;
-	}
-
-	static class FroyoSDCardDir{
-		public static String getDownloadPath(Context c){
-			File f =  c.getExternalCacheDir();
-			if(f != null){
-				return f.getAbsolutePath();
-			}else{
-				return null;
-			}	
-		}
-	}
-
-	static class PreFroyoSDCardDir{
-		public static String getDownloadPath(Context c){
-			if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
-				if(Environment.getExternalStorageDirectory() != null)
-					return Environment.getExternalStorageDirectory().getAbsolutePath() + "/Hedgewars/";				
-			}
-			return null;
-		}
-	}
-
-	/**
-	 * Get files from dirName, dir name is relative to {@link getDownloadPath}
-	 * @param dirName
-	 * @param c context
-	 * @return string of files
-	 */
-	public static String[] getFileNamesFromRelativeDir(Context c, String dirName){
-		String prefix = getDataPath(c);
-		File f = new File(prefix + dirName);
-
-		if(f.exists() && f.isDirectory()) return f.list();
-		else{
-
-			Log.e("Utils::", "Couldn't find dir: " + dirName);
-			return new String[0];
-		}
-	}
-
-	/**
-	 * Return a File array with all the files from dirName
-	 * @param c
-	 * @param dirName
-	 * @return
-	 */
-	public static File[] getFilesFromRelativeDir(Context c, String dirName){
-		String prefix = getDataPath(c);
-		File f = new File(prefix + dirName);
-
-		if(f.exists() && f.isDirectory()) return f.listFiles();
-		else {
-			Log.e("Utils::", "Dir not found: " + dirName);
-			return new File[0];
-		}
-	}
-
-	/**
-	 * Checks if this directory has a file with suffix suffix
-	 * @param f - directory
-	 * @return
-	 */
-	public static boolean hasFileWithSuffix(File f, String suffix){
-		if(f.isDirectory()){
-			for(String s : f.list()){
-				if(s.endsWith(suffix)) return true;
-			}
-			return false;
-		}else{
-			return false;
-		}
-	}
-
-	/**
-	 * Gives back all dirs which contain a file with suffix fileSuffix
-	 * @param c
-	 * @param path
-	 * @param fileSuffix
-	 * @return
-	 */
-	public static List<String> getDirsWithFileSuffix(Context c, String path, String fileSuffix){
-		File[] files = getFilesFromRelativeDir(c,path);
-		ArrayList<String> ret = new ArrayList<String>();
-
-		for(File f : files){
-			if(hasFileWithSuffix(f, fileSuffix)) ret.add(f.getName());
-		}
-		return ret;
-	}
-
-	/**
-	 * Get all files from directory dir which have the given suffix
-	 * @param c
-	 * @param dir
-	 * @param suffix
-	 * @param removeSuffix
-	 * @return
-	 */
-	public static ArrayList<String> getFilesFromDirWithSuffix(Context c, String dir, String suffix, boolean removeSuffix){
-		String[] files = Utils.getFileNamesFromRelativeDir(c, dir);
-		ArrayList<String> ret = new ArrayList<String>();
-		for(String s : files){
-			if(s.endsWith(suffix)){
-				if(removeSuffix) ret.add(s.substring(0, s.length()-suffix.length()));
-				else ret.add(s);
-			}
-		}
-		return ret;
-	}
-
-	/**
-	 * Moves resources pointed to by sourceResId (from @res/raw/) to the app's private data directory
-	 * @param c
-	 * @param sourceResId
-	 * @param directory
-	 */
-	public static void resRawToFilesDir(Context c, int sourceResId, String directory){
-		byte[] buffer = new byte[1024];
-		InputStream bis = null;
-		BufferedOutputStream bos = null;
-		File schemesDirFile = new File(c.getFilesDir().getAbsolutePath() + '/' + directory);
-		schemesDirFile.mkdirs();
-		String schemesDirPath = schemesDirFile.getAbsolutePath() + '/';
-
-		//Get an array with the resource files ID
-		TypedArray ta = c.getResources().obtainTypedArray(sourceResId);
-		int[] resIds = new int[ta.length()];
-		for(int i = 0; i < ta.length(); i++){
-			resIds[i] = ta.getResourceId(i, 0);
-		}
-
-		for(int id : resIds){
-			String fileName = c.getResources().getResourceEntryName(id);
-			File f = new File(schemesDirPath + fileName);
-			try {
-				if(!f.createNewFile()){
-					f.delete();
-					f.createNewFile();
-				}
-
-				bis = c.getResources().openRawResource(id);
-				bos = new BufferedOutputStream(new FileOutputStream(f), 1024);
-				int read = 0;
-				while((read = bis.read(buffer)) != -1){
-					bos.write(buffer, 0, read);
-				}
-
-			} catch (IOException e) {
-				e.printStackTrace();
-			}finally{
-				if(bis != null)
-					try { 
-						bis.close();
-					} catch (IOException e) {
-						e.printStackTrace();
-					}
-					if(bos != null)
-						try {
-							bos.close();
-						} catch (IOException e) {
-							e.printStackTrace();
-						}
-			}
-		}
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/WeaponsetCreatorActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,8 @@
+package org.hedgewars.hedgeroid;
+
+import android.support.v4.app.FragmentActivity;
+
+// TODO
+public class WeaponsetCreatorActivity extends FragmentActivity {
+	public static final String PARAMETER_EXISTING_WEAPONSETNAME="existingWeaponsetName";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/WeaponsetListActivity.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,126 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.SimpleAdapter;
+import android.widget.Toast;
+
+public class WeaponsetListActivity extends ListActivity implements OnItemClickListener {
+	private List<Weaponset> userWeaponsets;
+	private Button addButton;
+	
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_weaponsetlist);
+		addButton = (Button)findViewById(R.id.addButton);
+		addButton.setOnClickListener(new OnClickListener() {
+			public void onClick(View v) {
+				editWeaponset(null);
+			}
+		});
+	}
+	
+	@Override
+	public void onResume() {
+		super.onResume();
+		updateList();
+		getListView().setOnItemClickListener(this);
+		registerForContextMenu(getListView());
+	}
+	
+	private List<Map<String, ?>> weaponsetsToMap(List<Weaponset> weaponsets) {
+		List<Map<String, ?>> result = new ArrayList<Map<String, ?>>();
+		for(Weaponset weaponset : weaponsets) {
+			result.add(Collections.singletonMap("txt", weaponset.name));
+		}
+		return result;
+	}
+	
+	public void onItemClick(AdapterView<?> adapterView, View v, int position, long arg3) {
+		editWeaponset(userWeaponsets.get(position).name);
+	}
+	
+	@Override
+	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuinfo){
+		menu.add(ContextMenu.NONE, 0, ContextMenu.NONE, R.string.edit);
+		menu.add(ContextMenu.NONE, 1, ContextMenu.NONE, R.string.delete);
+	}
+	
+	@Override
+	public boolean onContextItemSelected(MenuItem item){
+		AdapterView.AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
+		int position = menuInfo.position;
+		Weaponset weaponset = userWeaponsets.get(position);
+		switch(item.getItemId()){
+		case 0:
+			editWeaponset(weaponset.name);
+			return true;
+		case 1:
+			try {
+				Weaponsets.deleteUserWeaponset(this, weaponset.name);
+			} catch (IOException e) {
+				Toast.makeText(this.getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_SHORT).show();
+			}
+			updateList();
+			return true;
+		}
+		return false;
+	}
+	
+	private void updateList() {
+		try {
+			userWeaponsets = Weaponsets.loadUserWeaponsets(this);
+		} catch (IOException e) {
+			Toast.makeText(this, R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+			finish();
+		}
+		Collections.sort(userWeaponsets, Weaponset.NAME_ORDER);
+		ListAdapter adapter = new SimpleAdapter(this, weaponsetsToMap(userWeaponsets), android.R.layout.simple_list_item_1, new String[]{"txt"}, new int[]{android.R.id.text1});
+		setListAdapter(adapter);
+	}
+	
+	private void editWeaponset(String weaponsetName) {
+		Intent i = new Intent(this, WeaponsetCreatorActivity.class);
+		i.putExtra(WeaponsetCreatorActivity.PARAMETER_EXISTING_WEAPONSETNAME, weaponsetName);
+		startActivity(i);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/AndroidTypeMapper.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,63 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.frontlib;
+
+import com.sun.jna.DefaultTypeMapper;
+import com.sun.jna.FromNativeContext;
+import com.sun.jna.ToNativeContext;
+import com.sun.jna.TypeConverter;
+import com.sun.jna.TypeMapper;
+
+class AndroidTypeMapper extends DefaultTypeMapper {
+	static final int NATIVE_INT_SIZE = 4;
+	static final int NATIVE_SIZE_T_SIZE = 4;
+	static final int NATIVE_BOOL_SIZE = 1;
+    public static final TypeMapper INSTANCE = new AndroidTypeMapper();
+    
+    protected AndroidTypeMapper() {
+        addTypeConverter(Boolean.class, new BooleanConverter());
+        addTypeConverter(NativeSizeT.class, new SizeTConverter());
+    }
+
+    private static final class BooleanConverter implements TypeConverter {
+    	public Class<Byte> nativeType() {
+    		return Byte.class;
+    	}
+    	public Object fromNative(Object value, FromNativeContext context) {
+    		return ((Byte)value).intValue() != 0 ? Boolean.TRUE : Boolean.FALSE;
+    	}
+    	public Object toNative(Object value, ToNativeContext context) {
+    		return Byte.valueOf((byte)(Boolean.TRUE.equals(value) ? 1 : 0));
+    	}
+    }
+    
+    private static final class SizeTConverter implements TypeConverter {
+    	public Class<Integer> nativeType() {
+    		return Integer.class;
+    	}
+    	public Object fromNative(Object value, FromNativeContext context) {
+    		return NativeSizeT.valueOf((Integer)value);
+    	}
+    	public Object toNative(Object value, ToNativeContext context) {
+    		return Integer.valueOf(value==null ? 0 : ((NativeSizeT)value).intValue());
+    	}
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Flib.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,61 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.frontlib;
+
+import java.util.Collections;
+
+import android.util.Log;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+
+public class Flib {
+	static {
+		System.loadLibrary("SDL_net");
+		System.setProperty("jna.encoding", "UTF8"); // Ugly global setting, but it seems JNA doesn't allow setting this per-library... 
+	}
+	public static final Frontlib INSTANCE = (Frontlib)Native.loadLibrary("frontlib", Frontlib.class, Collections.singletonMap(Library.OPTION_TYPE_MAPPER, AndroidTypeMapper.INSTANCE));
+	
+	static {
+		// We'll just do it here and never quit it again...
+		if(Flib.INSTANCE.flib_init() != 0) {
+			throw new RuntimeException("Unable to initialize frontlib");
+		}
+	}
+	
+	// Hook frontlib logging into Android logging
+	private static final Frontlib.LogCallback logCb = new Frontlib.LogCallback() {
+		public void callback(int level, String message) {
+			if(level >= Frontlib.FLIB_LOGLEVEL_ERROR) {
+				Log.e("Frontlib", message);
+			} else if(level == Frontlib.FLIB_LOGLEVEL_WARNING){
+				Log.w("Frontlib", message);
+			} else if(level == Frontlib.FLIB_LOGLEVEL_INFO){
+				Log.i("Frontlib", message);
+			} else if(level <= Frontlib.FLIB_LOGLEVEL_DEBUG){
+				Log.d("Frontlib", message);
+			}
+		}
+	};
+	static {
+		INSTANCE.flib_log_setLevel(Frontlib.FLIB_LOGLEVEL_INFO);
+		INSTANCE.flib_log_setCallback(logCb);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,1213 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+package org.hedgewars.hedgeroid.frontlib;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.Hog;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.MetaScheme;
+import org.hedgewars.hedgeroid.Datastructures.MetaScheme.Mod;
+import org.hedgewars.hedgeroid.Datastructures.MetaScheme.Setting;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+import com.sun.jna.Callback;
+import com.sun.jna.Library;
+import com.sun.jna.Memory;
+import com.sun.jna.Pointer;
+import com.sun.jna.PointerType;
+import com.sun.jna.Structure;
+
+/**
+ * Here is an introduction to the most important aspects of the JNA code.
+ * 
+ * This interface permits access to the Hedgewars frontend library (frontlib)
+ * from Java. Each function directly contained in the Frontlib interface
+ * represents a mapped C function. The Structure classes (ending in -Struct) are
+ * mappings of C structs, and the PointerType classes (ending in -Ptr) represent
+ * pointers to structs.
+ * 
+ * Quick notes for USING these classes from outside this package:
+ * 
+ * Usage should be fairly straightforward, but there are a few surprising
+ * gotchas. First, when you implement callbacks, YOU are responsible for
+ * ensuring that the callback objects are not garbage-collected while they might
+ * still be called! So make sure you keep them in member variables or similar,
+ * because Java will not know if there are still native references to them.
+ * 
+ * When using Frontlib from outside its package, you only interact with structs
+ * via the PointerType classes. They allow you to get at the data of the struct
+ * with a function called deref(), which creates a plain normal Java object
+ * representing the data (e.g. SchemePtr.deref() will give you a Scheme object).
+ * 
+ * Remember that you usually have to destroy structs that you receive from the
+ * library, because they are owned by the native code, not Java. The recommended
+ * pattern for most cases is to call deref() on the pointer to get a Java object
+ * (that you can keep as long as you like), and then immediately destroy the
+ * struct if it needs destroying. To find out whether and how the struct needs
+ * to be destroyed, see the library's documentation of the function that you got
+ * the struct from.
+ * 
+ * To pass new structs to the library, you can use the static createJavaOwned()
+ * function in each PointerType, which creates a new struct from the Java object
+ * you provide, and returns a pointer to that struct that you can pass to
+ * library functions. This new structure's memory is owned and managed by Java
+ * code, so do not destroy it with frontlib functions!
+ * 
+ * There is a slight mismatch between the data model for the game setup. The
+ * frontlib supports setting initial health and weaponset per-hog, because the
+ * engine allows for that, but currently neither the networking protocol nor the
+ * PC frontend support this feature, so the Android version does not take
+ * advantage of it either and treats both as per-game settings. The initial
+ * health is contained in the game scheme, the weaponset is explicitly part of
+ * the GameConfig. When converting GameConfig to a native flib_gamesetup, both
+ * are automatically copied to all hogs in the game, and for the reverse
+ * conversion the weaponset of the first hog of the first team is used as the
+ * GameConfig weaponset. This means that GameConfig.weaponset will be null if
+ * there are no teams in the game.
+ * 
+ * When starting a network game, you only need to query the GameSetupPtr from
+ * the netconn and use it to create the gameconn - this is preferable to using
+ * your own recreation of the game setup, because that way the same piece of
+ * code is used to determine the game setup on all platforms.
+ * 
+ * The "context" parameter of the callbacks is never needed here because JNA
+ * generates function code for each callback object. Don't worry about it, just
+ * pass null for context and ignore the context parameter in the callbacks.
+ * 
+ * Finally, the library functions are documented in the actual library, not
+ * here, so check the docs there to find out what exactly each function does!
+ * 
+ * Notes about the structure of this class (for the next one who has to touch
+ * this...):
+ * 
+ * Java/C interop is quite fiddly and error-prone, so as long as things work,
+ * try to stick to the established patterns.
+ * 
+ * Structure types should always be hidden from the outside world, because they
+ * can be misused too easily. For example, if you get a Structure from the
+ * library, change a String value in there and pass it back, JNA will re-write
+ * that string using Java-owned memory without freeing the old native-owned
+ * string, which causes a memory leak and possibly a double-free or other Bad
+ * Things (tm). To avoid problems like this, Structure types are only used
+ * internally, to map existing structures to Java types (without modifying them)
+ * or to create brand-new, Java-owned structures. Both operations are exposed to
+ * the outside through the PointerType classes corresponding to the structures
+ * in question.
+ * 
+ * Since all of the struct mapping happens in Java, it is never checked against
+ * the actual struct declarations in the library. That means strange things can
+ * start happening at runtime if the frontlib structs are modified without
+ * changing the mappings here to match. This also applies to the function
+ * signatures: JNA checks whether the functions actually exist when loading the
+ * library, but it has no way of knowing whether the signatures are correct. If
+ * the signatures here deviate from those in the frontlib, you might get stack
+ * corruption.
+ * 
+ * In order to check at least the function signatures, take a look at the file
+ * extra/jnacontrol.c in the frontlib sources. You can validate whether the
+ * function signatures are still correct by copy-pasting them into jnaControl.c
+ * and compiling it against the frontlib headers. The typedefs and #defines in
+ * that file will make the compiler see the Java method signatures as C function
+ * declarations. Since the same functions are already declared in the frontlib
+ * headers, the compiler will give you errors if the signatures don't match.
+ */
+public interface Frontlib extends Library {
+	public static class NetconnPtr extends PointerType { }
+	public static class MapconnPtr extends PointerType { }
+	public static class GameconnPtr extends PointerType { }
+	
+	public static class MetaschemePtr extends PointerType {
+		public MetaScheme deref() {
+			return deref(getPointer());
+		}
+		
+		public static MetaScheme deref(Pointer p) {
+			MetaschemeStruct struct = new MetaschemeStruct(p);
+			struct.read();
+			return struct.toMetaScheme();
+		}
+	}
+	
+	public static class RoomArrayPtr extends PointerType { 
+		public Room[] getRooms(int count) {
+			Pointer ptr = getPointer();
+			if(ptr == null) {
+				return new Room[0];
+			}
+			Pointer[] untypedPtrs = ptr.getPointerArray(0, count);
+			Room[] result = new Room[count];
+			for(int i=0; i<count; i++) {
+				result[i] = RoomPtr.deref(untypedPtrs[i]);
+			}
+			return result;
+		}
+	}
+	
+	public static class RoomPtr extends PointerType {
+		public Room deref() {
+			return deref(getPointer());
+		}
+		
+		public static Room deref(Pointer p) {
+			RoomStruct struct = new RoomStruct(p);
+			struct.read();
+			return struct.toRoomlistRoom();
+		}
+	}
+	
+	public static class TeamPtr extends PointerType {
+		private TeamStruct javaOwnedInstance; 
+		
+		public TeamInGame deref() {
+			TeamStruct struct = new TeamStruct(getPointer());
+			struct.read();
+			return struct.toTeamInGame();
+		}
+		
+		public static TeamPtr createJavaOwned(Team t) {
+			return createJavaOwned(new TeamInGame(t, null));
+		}
+		
+		public static TeamPtr createJavaOwned(TeamInGame ingameTeam) {
+			TeamPtr result = new TeamPtr();
+			result.javaOwnedInstance = new TeamStruct();
+			result.javaOwnedInstance.fillFrom(ingameTeam.team, ingameTeam.ingameAttribs);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class WeaponsetPtr extends PointerType {
+		private WeaponsetStruct javaOwnedInstance; 
+		
+		public Weaponset deref() {
+			WeaponsetStruct struct = new WeaponsetStruct(getPointer());
+			struct.read();
+			return struct.toWeaponset();
+		}
+		
+		public static WeaponsetPtr createJavaOwned(Weaponset weaponset) {
+			WeaponsetPtr result = new WeaponsetPtr();
+			result.javaOwnedInstance = new WeaponsetStruct();
+			result.javaOwnedInstance.fillFrom(weaponset);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class WeaponsetListPtr extends PointerType {
+		private WeaponsetListStruct javaOwnedInstance;
+		
+		public List<Weaponset> deref() {
+			WeaponsetListStruct struct = new WeaponsetListStruct(getPointer());
+			struct.read();
+			return struct.toWeaponsetList();
+		}
+		
+		public static WeaponsetListPtr createJavaOwned(List<Weaponset> list) {
+			WeaponsetListPtr result = new WeaponsetListPtr();
+			result.javaOwnedInstance = new WeaponsetListStruct();
+			result.javaOwnedInstance.fillFrom(list);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class MapRecipePtr extends PointerType {
+		private MapRecipeStruct javaOwnedInstance;
+		
+		public MapRecipe deref() {
+			MapRecipeStruct struct = new MapRecipeStruct(getPointer());
+			struct.read();
+			return struct.toMapRecipe();
+		}
+		
+		public static MapRecipePtr createJavaOwned(MapRecipe recipe) {
+			MapRecipePtr result = new MapRecipePtr();
+			result.javaOwnedInstance = new MapRecipeStruct();
+			result.javaOwnedInstance.fillFrom(recipe);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class SchemePtr extends PointerType {
+		private SchemeStruct javaOwnedInstance;
+		
+		public Scheme deref() {
+			SchemeStruct struct = new SchemeStruct(getPointer());
+			struct.read();
+			return struct.toScheme();
+		}
+		
+		public static SchemePtr createJavaOwned(Scheme scheme) {
+			SchemePtr result = new SchemePtr();
+			result.javaOwnedInstance = new SchemeStruct();
+			result.javaOwnedInstance.fillFrom(scheme);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class SchemelistPtr extends PointerType {
+		private SchemelistStruct javaOwnedInstance;
+		
+		public List<Scheme> deref() {
+			SchemelistStruct struct = new SchemelistStruct(getPointer());
+			struct.read();
+			return struct.toSchemeList();
+		}
+		
+		public static SchemelistPtr createJavaOwned(List<Scheme> schemes) {
+			SchemelistPtr result = new SchemelistPtr();
+			result.javaOwnedInstance = new SchemelistStruct();
+			result.javaOwnedInstance.fillFrom(schemes);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class GameSetupPtr extends PointerType {
+		private GameSetupStruct javaOwnedInstance;
+		
+		public GameConfig deref() {
+			GameSetupStruct struct = new GameSetupStruct(getPointer());
+			struct.read();
+			return struct.toGameConfig();
+		}
+		
+		public static GameSetupPtr createJavaOwned(GameConfig conf) {
+			GameSetupPtr result = new GameSetupPtr();
+			result.javaOwnedInstance = new GameSetupStruct();
+			result.javaOwnedInstance.fillFrom(conf);
+			result.javaOwnedInstance.autoWrite();
+			result.setPointer(result.javaOwnedInstance.getPointer());
+			return result;
+		}
+	}
+	
+	public static class ByteArrayPtr extends PointerType {
+		public byte[] deref(int size) {
+			return getPointer().getByteArray(0, size);
+		}
+		
+		public static byte[] deref(ByteArrayPtr ptr, int size) {
+			if(ptr==null && size==0) {
+				return null;
+			} else {
+				return ptr.deref(size);
+			}
+		}
+		
+		public static ByteArrayPtr createJavaOwned(byte[] buffer) {
+			if(buffer == null || buffer.length == 0) {
+				return null;
+			}
+			// no need for javaOwnedInstance here because PointerType
+			// remembers the memory as its Pointer
+			Pointer ptr = new Memory(buffer.length);
+			ptr.write(0, buffer, 0, buffer.length);
+			ByteArrayPtr result = new ByteArrayPtr();
+			result.setPointer(ptr);
+			return result;
+		}
+	}
+	
+	static class HogStruct extends Structure {
+		public static class ByVal extends HogStruct implements Structure.ByValue {}
+		public static class ByRef extends HogStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"name", "hat", "rounds", "kills", "deaths", "suicides", "difficulty", "initialHealth", "weaponset"};
+
+		public HogStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public HogStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(Hog hog) {
+			difficulty = hog.level;
+			hat = hog.hat;
+			name = hog.name;
+		}
+		
+		public Hog toHog() {
+			return new Hog(name, hat, difficulty);
+		}
+		
+		public String name;
+		public String hat;
+		
+		public int rounds;
+		public int kills;
+		public int deaths;
+		public int suicides;
+	
+		public int difficulty;
+		
+		public int initialHealth;
+		public WeaponsetStruct.ByRef weaponset;
+	}
+	
+	static class TeamStruct extends Structure {
+		public static class ByVal extends TeamStruct implements Structure.ByValue {}
+		public static class ByRef extends TeamStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"hogs", "name", "grave", "fort", "voicepack", "flag", "bindings", "bindingCount", "rounds", "wins", "campaignProgress", "colorIndex", "hogsInGame", "remoteDriven", "ownerName"};
+
+		public TeamStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public TeamStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(Team team, TeamIngameAttributes attrs) {
+			if(team != null) {
+				name = team.name;
+				grave = team.grave;
+				flag = team.flag;
+				voicepack = team.voice;
+				fort = team.fort;
+				if(team.hogs.size() != Team.HEDGEHOGS_PER_TEAM) {
+					throw new IllegalArgumentException();
+				}
+				for(int i=0; i<hogs.length; i++) {
+					hogs[i] = new HogStruct();
+					hogs[i].fillFrom(team.hogs.get(i));
+				}
+			}
+			
+			if(attrs != null) {
+				hogsInGame = attrs.hogCount;
+				ownerName = attrs.ownerName;
+				colorIndex = attrs.colorIndex;
+				remoteDriven = attrs.remoteDriven;
+			}
+		}
+		
+		public void fillFrom(TeamInGame team, WeaponsetStruct.ByRef weaponset, int initialHealth) {
+			fillFrom(team.team, team.ingameAttribs);
+			for(int i=0; i<hogs.length; i++) {
+				hogs[i].initialHealth = initialHealth;
+				hogs[i].weaponset = weaponset;
+			}
+		}
+		
+		public Team toTeam() {
+			List<Hog> hogList = new ArrayList<Hog>();
+			for(int i=0; i<hogs.length; i++) {
+				hogList.add(hogs[i].toHog());
+			}
+			return new Team(name, grave, flag, voicepack, fort, hogList);
+		}
+		
+		public TeamIngameAttributes toTeamIngameAttributes() {
+			return new TeamIngameAttributes(ownerName, colorIndex, hogsInGame, remoteDriven);
+		}
+		
+		public TeamInGame toTeamInGame() {
+			return new TeamInGame(toTeam(), toTeamIngameAttributes());
+		}
+		
+		public HogStruct[] hogs = new HogStruct[Team.HEDGEHOGS_PER_TEAM];
+		public String name;
+		public String grave;
+		public String fort;
+		public String voicepack;
+		public String flag;
+		
+		public Pointer bindings;
+		public int bindingCount;
+		
+		public int rounds;
+		public int wins;
+		public int campaignProgress;
+		
+		public int colorIndex;
+		public int hogsInGame;
+		public boolean remoteDriven;
+		public String ownerName;
+	}
+	
+	static class WeaponsetStruct extends Structure {
+		public static class ByVal extends WeaponsetStruct implements Structure.ByValue {}
+		public static class ByRef extends WeaponsetStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"loadout", "crateprob", "crateammo", "delay", "name"};
+		
+		public WeaponsetStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public WeaponsetStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(Weaponset weaponset) {
+			fillWeaponInfo(loadout, weaponset.loadout);
+			fillWeaponInfo(crateprob, weaponset.crateProb);
+			fillWeaponInfo(crateammo, weaponset.crateAmmo);
+			fillWeaponInfo(delay, weaponset.delay);
+			name = weaponset.name;
+		}
+		
+		private static void fillWeaponInfo(byte[] array, String str) {
+			for(int i=0; i<array.length-1; i++) {
+				array[i] = (byte) (i<str.length() ? str.charAt(i) : '0');
+			}
+			array[array.length-1] = (byte)0;
+		}
+		
+		public Weaponset toWeaponset() {
+			return new Weaponset(name, weaponInfoToString(loadout), weaponInfoToString(crateprob), weaponInfoToString(crateammo), weaponInfoToString(delay));
+		}
+		
+		private static String weaponInfoToString(byte[] array) {
+			try {
+				return new String(array, 0, array.length-1, "ASCII");
+			} catch (UnsupportedEncodingException e) {
+				throw new AssertionError();
+			}
+		}
+		
+		public byte[] loadout = new byte[Weaponset.WEAPONS_COUNT+1];
+		public byte[] crateprob = new byte[Weaponset.WEAPONS_COUNT+1];
+		public byte[] crateammo = new byte[Weaponset.WEAPONS_COUNT+1];
+		public byte[] delay = new byte[Weaponset.WEAPONS_COUNT+1];
+		public String name;
+	}
+	
+	/**
+	 * Represents a flib_weaponset*, for use as part of a flib_weaponset**
+	 */
+	static class WeaponsetPointerByReference extends Structure implements Structure.ByReference {
+		private static String[] FIELD_ORDER = new String[] {"weaponset"};
+		
+		public WeaponsetPointerByReference() { super(); setFieldOrder(FIELD_ORDER); }
+		public WeaponsetPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public WeaponsetStruct.ByRef weaponset;
+	}
+	
+	static class WeaponsetListStruct extends Structure {
+		public static class ByVal extends WeaponsetListStruct implements Structure.ByValue {}
+		public static class ByRef extends WeaponsetListStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"weaponsetCount", "weaponsets"};
+		
+		public WeaponsetListStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public WeaponsetListStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(List<Weaponset> list) {
+			weaponsetCount = list.size();
+			if(weaponsetCount<=0) {
+				weaponsets = null;
+			} else {
+				weaponsets = new WeaponsetPointerByReference();
+				Structure[] structs = weaponsets.toArray(weaponsetCount);
+				
+				for(int i=0; i<weaponsetCount; i++) {
+					WeaponsetPointerByReference pstruct = (WeaponsetPointerByReference)structs[i];
+					pstruct.weaponset = new WeaponsetStruct.ByRef();
+					pstruct.weaponset.fillFrom(list.get(i));
+				}
+			}
+		}
+		
+		/**
+		 * Only use on native-owned structs!
+		 * Calling this method on a Java-owned struct could cause garbage collection of referenced
+		 * structures.
+		 */
+		public List<Weaponset> toWeaponsetList() {
+			if(weaponsetCount<=0) {
+				return new ArrayList<Weaponset>();
+			} else {
+				List<Weaponset> list = new ArrayList<Weaponset>(weaponsetCount);
+				Structure[] structs = weaponsets.toArray(weaponsetCount);
+				
+				for(int i=0; i<weaponsetCount; i++) {
+					WeaponsetPointerByReference pstruct = (WeaponsetPointerByReference)structs[i];
+					list.add(pstruct.weaponset.toWeaponset());
+				}
+				return list;
+			}
+		}
+		
+		public int weaponsetCount;
+		public WeaponsetPointerByReference weaponsets;
+	}
+	
+	static class RoomStruct extends Structure {
+		public static class ByVal extends RoomStruct implements Structure.ByValue {}
+		public static class ByRef extends RoomStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"inProgress", "name", "playerCount", "teamCount", "owner", "map", "scheme", "weapons"};
+		
+		public RoomStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public RoomStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+
+		public Room toRoomlistRoom() {
+			return new Room(name, map, scheme, weapons, owner, playerCount, teamCount, inProgress);
+		}
+		
+	    public boolean inProgress;
+	    public String name;
+	    public int playerCount;
+	    public int teamCount;
+	    public String owner;
+	    public String map;
+	    public String scheme;
+	    public String weapons;
+	}
+	
+	static class MapRecipeStruct extends Structure {
+		public static class ByVal extends MapRecipeStruct implements Structure.ByValue {}
+		public static class ByRef extends MapRecipeStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"mapgen", "name", "seed", "theme", "drawData", "drawDataSize", "templateFilter", "mazeSize"};
+		
+		public MapRecipeStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public MapRecipeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(MapRecipe map) {
+			mapgen = map.mapgen;
+			name = map.name;
+			seed = map.seed;
+			theme = map.theme;
+			byte[] buf = map.getDrawData();
+			if(buf==null || buf.length==0) {
+				drawData = null;
+			} else {
+				drawData = ByteArrayPtr.createJavaOwned(buf).getPointer();
+			}
+			drawDataSize = NativeSizeT.valueOf(buf==null ? 0 : buf.length);
+			templateFilter = map.templateFilter;
+			mazeSize = map.mazeSize;
+		}
+		
+		public MapRecipe toMapRecipe() {
+			byte[] buf;
+			int size = drawDataSize.intValue();
+			if(size>0) {
+				buf = drawData.getByteArray(0, size);
+			} else {
+				buf = null;
+			}
+			return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, buf);
+		}
+		
+		public int mapgen;
+		public String name;
+		public String seed;
+		public String theme;
+		public Pointer drawData;			// We can't use ByteArrayPtr in a struct because JNA will overwrite the value with NULL - probably a bug.
+		public NativeSizeT drawDataSize;
+		public int templateFilter;
+		public int mazeSize;
+	}
+	
+	static class MetaschemeSettingStruct extends Structure {
+		public static class ByVal extends MetaschemeSettingStruct implements Structure.ByValue {}
+		public static class ByRef extends MetaschemeSettingStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"name", "engineCommand", "maxMeansInfinity", "times1000", "min", "max", "def"};
+		
+		public MetaschemeSettingStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public MetaschemeSettingStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(Setting setting) {
+			name = setting.name;
+			engineCommand = setting.engineCommand;
+			maxMeansInfinity = setting.maxMeansInfinity;
+			times1000 = setting.times1000;
+			min = setting.min;
+			max = setting.max;
+			def = setting.def;
+		}
+		
+		public MetaScheme.Setting toMetaSchemeSetting() {
+			return new MetaScheme.Setting(name, engineCommand, maxMeansInfinity, times1000, min, max, def);
+		}
+		
+		public String name;
+		public String engineCommand;
+		public boolean maxMeansInfinity;
+		public boolean times1000;
+		public int min;
+		public int max;
+		public int def;
+	}
+	
+	static class MetaschemeModStruct extends Structure {
+		public static class ByVal extends MetaschemeModStruct implements Structure.ByValue {}
+		public static class ByRef extends MetaschemeModStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"name", "bitmaskIndex"};
+		
+		public MetaschemeModStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public MetaschemeModStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(Mod mod) {
+			name = mod.name;
+			bitmaskIndex = mod.bitmaskIndex;
+		}
+		
+		public MetaScheme.Mod toMetaSchemeMod() {
+			return new MetaScheme.Mod(name, bitmaskIndex);
+		}
+
+		public String name;
+		public int bitmaskIndex;
+
+	}
+	
+	static class MetaschemeStruct extends Structure {
+		public static class ByVal extends MetaschemeStruct implements Structure.ByValue {}
+		public static class ByRef extends MetaschemeStruct implements Structure.ByReference {}
+
+		private static String[] FIELD_ORDER = new String[] {"settingCount", "modCount", "settings", "mods"};
+		
+		public MetaschemeStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public MetaschemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		/**
+		 * Only use on native-owned structs!
+		 * Calling this method on a Java-owned struct could cause garbage collection of referenced
+		 * structures.
+		 */
+		public MetaScheme toMetaScheme() {
+			List<MetaScheme.Setting> settingList = new ArrayList<MetaScheme.Setting>(settingCount);
+			List<MetaScheme.Mod> modList = new ArrayList<MetaScheme.Mod>(modCount);
+			
+			Structure[] settingStructs = settings.toArray(settingCount);
+			Structure[] modStructs = mods.toArray(modCount);
+			
+			for(int i=0; i<settingCount; i++) {
+				MetaschemeSettingStruct mss = (MetaschemeSettingStruct)settingStructs[i];
+				settingList.add(mss.toMetaSchemeSetting());
+			}
+			
+			for(int i=0; i<modCount; i++) {
+				MetaschemeModStruct mms = (MetaschemeModStruct)modStructs[i];
+				modList.add(mms.toMetaSchemeMod());
+			}
+			
+			return new MetaScheme(modList, settingList);
+		}
+		
+		public int settingCount;
+		public int modCount;
+		public MetaschemeSettingStruct.ByRef settings;
+		public MetaschemeModStruct.ByRef mods;
+	}
+	
+	static class SchemeStruct extends Structure {
+		public static class ByVal extends SchemeStruct implements Structure.ByValue {}
+		public static class ByRef extends SchemeStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"name", "settings", "mod"};
+		
+		public SchemeStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public SchemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(Scheme scheme) {
+			MetaScheme meta = MetaScheme.INSTANCE;
+			name = scheme.name;
+			settings = new Memory(AndroidTypeMapper.NATIVE_INT_SIZE * meta.settings.size());
+			for(int i=0; i<meta.settings.size(); i++) {
+				Integer value = scheme.settings.get(meta.settings.get(i).name);
+				settings.setInt(AndroidTypeMapper.NATIVE_INT_SIZE*i, value);
+			}
+			mods = new Memory(AndroidTypeMapper.NATIVE_BOOL_SIZE * meta.mods.size());
+			for(int i=0; i<meta.mods.size(); i++) {
+				Boolean value = scheme.mods.get(meta.mods.get(i).name);
+				mods.setByte(AndroidTypeMapper.NATIVE_BOOL_SIZE*i, (byte)(value ? 1 : 0));
+			}
+		}
+
+		public Scheme toScheme() {
+			Map<String, Integer> settingsMap = new HashMap<String, Integer>();
+			MetaScheme meta = MetaScheme.INSTANCE;
+			for(int i=0; i<meta.settings.size(); i++) {
+				settingsMap.put(meta.settings.get(i).name, settings.getInt(AndroidTypeMapper.NATIVE_INT_SIZE*i));
+			}
+			Map<String, Boolean> modsMap = new HashMap<String, Boolean>();
+			for(int i=0; i<meta.mods.size(); i++) {
+				modsMap.put(meta.mods.get(i).name, mods.getByte(i) != 0 ? Boolean.TRUE : Boolean.FALSE);
+			}
+			return new Scheme(name, settingsMap, modsMap);
+		}
+		
+		public String name;
+		public Pointer settings;
+		public Pointer mods;
+	}
+	
+	/**
+	 * Represents a flib_scheme*, for use as part of a flib_scheme**
+	 */
+	static class SchemePointerByReference extends Structure implements Structure.ByReference {
+		private static String[] FIELD_ORDER = new String[] {"scheme"};
+		
+		public SchemePointerByReference() { super(); setFieldOrder(FIELD_ORDER); }
+		public SchemePointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public SchemeStruct.ByRef scheme;
+	}
+	
+	static class SchemelistStruct extends Structure {
+		public static class ByVal extends SchemelistStruct implements Structure.ByValue {}
+		public static class ByRef extends SchemelistStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"schemeCount", "schemes"};
+		
+		public SchemelistStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public SchemelistStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(List<Scheme> schemeList) {
+			schemeCount = schemeList.size();
+			if(schemeCount<=0) {
+				schemes = null;
+			} else {
+				schemes = new SchemePointerByReference();
+				Structure[] schemePtrStructs = schemes.toArray(schemeCount);
+				
+				for(int i=0; i<this.schemeCount; i++) {
+					SchemePointerByReference spbr = (SchemePointerByReference)schemePtrStructs[i];
+					spbr.scheme = new SchemeStruct.ByRef();
+					spbr.scheme.fillFrom(schemeList.get(i));
+				}
+			}
+		}
+
+		/**
+		 * Only use on native-owned structs!
+		 * Calling this method on a Java-owned struct could cause garbage collection of referenced
+		 * structures.
+		 */
+		public List<Scheme> toSchemeList() {
+			if(schemeCount<=0) {
+				return new ArrayList<Scheme>();
+			} else {
+				List<Scheme> schemeList = new ArrayList<Scheme>(schemeCount);
+				
+				Structure[] schemePtrStructs = schemes.toArray(schemeCount);
+				
+				for(int i=0; i<schemeCount; i++) {
+					SchemePointerByReference spbr2 = (SchemePointerByReference)schemePtrStructs[i];
+					schemeList.add(spbr2.scheme.toScheme());
+				}
+				return schemeList;
+			}
+		}
+		
+		public int schemeCount;
+		public SchemePointerByReference schemes;
+	}
+	
+	/**
+	 * Represents a flib_team*, for use as part of a flib_team**
+	 */
+	static class TeamPointerByReference extends Structure implements Structure.ByReference {
+		private static String[] FIELD_ORDER = new String[] {"team"};
+		
+		public TeamPointerByReference() { super(); setFieldOrder(FIELD_ORDER); }
+		public TeamPointerByReference(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public TeamStruct.ByRef team;
+	}
+	
+	static class TeamlistStruct extends Structure {
+		public static class ByVal extends TeamlistStruct implements Structure.ByValue {}
+		public static class ByRef extends TeamlistStruct implements Structure.ByReference {}
+
+		private static String[] FIELD_ORDER = new String[] {"teamCount", "teams"};
+		
+		public TeamlistStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public TeamlistStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(List<TeamInGame> teamList, WeaponsetStruct.ByRef weaponset, int initialHealth) {
+			teamCount = teamList.size();
+			if(teamCount <= 0) {
+				teams = null;
+			} else {
+				teams = new TeamPointerByReference();
+				Structure[] teamPtrStructs = teams.toArray(teamCount);
+				
+				for(int i=0; i<this.teamCount; i++) {
+					TeamPointerByReference tpbr = (TeamPointerByReference)teamPtrStructs[i];
+					tpbr.team = new TeamStruct.ByRef();
+					tpbr.team.fillFrom(teamList.get(i), weaponset, initialHealth);
+				}
+			}
+		}
+
+		public List<TeamInGame> toTeamInGameList() {
+			if(teamCount<=0) {
+				return new ArrayList<TeamInGame>();
+			} else {
+				List<TeamInGame> result = new ArrayList<TeamInGame>(teamCount);
+				Structure[] structs = teams.toArray(teamCount);
+				
+				for(int i=0; i<teamCount; i++) {
+					TeamPointerByReference struct = (TeamPointerByReference)structs[i];
+					result.add(struct.team.toTeamInGame());
+				}
+				return result;
+			}
+		}
+		
+		public int teamCount;
+		public TeamPointerByReference teams;
+	}
+	
+	static class GameSetupStruct extends Structure {
+		public static class ByVal extends GameSetupStruct implements Structure.ByValue {}
+		public static class ByRef extends GameSetupStruct implements Structure.ByReference {}
+		private static String[] FIELD_ORDER = new String[] {"script", "gamescheme", "map", "teamlist"};
+		
+		public GameSetupStruct() { super(); setFieldOrder(FIELD_ORDER); }
+		public GameSetupStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
+		
+		public void fillFrom(GameConfig conf) {
+			script = conf.style;
+			gamescheme = new SchemeStruct.ByRef();
+			gamescheme.fillFrom(conf.scheme);
+			map = new MapRecipeStruct.ByRef();
+			map.fillFrom(conf.map);
+			
+			/*
+			 * At this point we deviate from the usual copying pattern because the frontlib
+			 * expects per-hog weapons and initial health, but the UI models them as per-
+			 * game, so we extract them from the config here and pass them on to be included
+			 * in each hog.
+			 */
+			WeaponsetStruct.ByRef wss = new WeaponsetStruct.ByRef();
+			wss.fillFrom(conf.weaponset);
+			int initialHealth = conf.scheme.getHealth();
+			
+			teamlist = new TeamlistStruct.ByRef();
+			teamlist.fillFrom(conf.teams, wss, initialHealth);
+		}
+		
+		public GameConfig toGameConfig() {
+			Scheme scheme = gamescheme != null ? gamescheme.toScheme() : null;
+			MapRecipe mapRecipe = map != null ? map.toMapRecipe() : null;
+			List<TeamInGame> teams = teamlist != null ? teamlist.toTeamInGameList() : null;
+			
+			WeaponsetStruct weaponsetStruct = teamlist != null && teamlist.teamCount>0 ? teamlist.teams.team.hogs[0].weaponset : null;
+			Weaponset weaponset = weaponsetStruct != null ? weaponsetStruct.toWeaponset() : null;
+			return new GameConfig(script, scheme, mapRecipe, teams, weaponset);
+		}
+
+		public String script;
+		public SchemeStruct.ByRef gamescheme;
+		public MapRecipeStruct.ByRef map;
+		public TeamlistStruct.ByRef teamlist;
+	}
+	
+	/*
+	 * Callback interfaces. The context parameter is never needed here and
+	 * should always be ignored. Be sure to keep a reference to each callback
+	 * for as long as they might be called by native code, to avoid premature
+	 * garbage collection.
+	 */
+	public static interface VoidCallback extends Callback {
+		void callback(Pointer context);
+	}
+	
+	public static interface StrCallback extends Callback {
+		void callback(Pointer context, String arg1);
+	}
+	
+	public static interface IntCallback extends Callback {
+		void callback(Pointer context, int arg1);
+	}
+	
+	public static interface IntStrCallback extends Callback {
+		void callback(Pointer context, int arg1, String arg2);
+	}
+	
+	public static interface StrIntCallback extends Callback {
+		void callback(Pointer context, String arg1, int arg2);
+	}
+	
+	public static interface StrStrCallback extends Callback {
+		void callback(Pointer context, String arg1, String arg2);
+	}
+	
+	public static interface StrStrBoolCallback extends Callback {
+		void callback(Pointer context, String arg1, String arg2, boolean arg3);
+	}
+	
+	public static interface RoomCallback extends Callback {
+		void callback(Pointer context, RoomPtr arg1);
+	}
+	
+	public static interface RoomListCallback extends Callback {
+		void callback(Pointer context, RoomArrayPtr arg1, int count);
+	}
+	
+	public static interface StrRoomCallback extends Callback {
+		void callback(Pointer context, String arg1, RoomPtr arg2);
+	}
+	
+	public static interface BoolCallback extends Callback {
+		void callback(Pointer context, boolean arg1);
+	}
+	
+	public static interface StrBoolCallback extends Callback {
+		void callback(Pointer context, String arg1, boolean arg2);
+	}
+	
+	public static interface TeamCallback extends Callback {
+		void callback(Pointer context, TeamPtr arg1);
+	}
+	
+	public static interface BytesCallback extends Callback {
+		void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size);
+	}
+	
+	public static interface BytesBoolCallback extends Callback {
+		void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size, boolean arg3);
+	}
+	
+	public static interface SchemeCallback extends Callback {
+		void callback(Pointer context, SchemePtr arg1);
+	}
+	
+	public static interface MapIntCallback extends Callback {
+		void callback(Pointer context, MapRecipePtr arg1, int arg2);
+	}
+	
+	public static interface WeaponsetCallback extends Callback {
+		void callback(Pointer context, WeaponsetPtr arg1);
+	}
+	
+	public static interface MapimageCallback extends Callback {
+		void callback(Pointer context, ByteArrayPtr buffer, int hedgehogCount);
+	}
+	
+	public static interface LogCallback extends Callback {
+		void callback(int level, String logMessage);
+	}
+	
+	// frontlib.h
+    int flib_init();
+    void flib_quit();
+	
+    // hwconsts.h
+    int flib_get_teamcolor(int colorIndex);
+    int flib_get_teamcolor_count();
+    int flib_get_hedgehogs_per_team();
+    int flib_get_weapons_count();
+	MetaschemePtr flib_get_metascheme();
+	
+    // net/netconn.h
+	static final int NETCONN_STATE_CONNECTING = 0;
+	static final int NETCONN_STATE_LOBBY = 1;
+	static final int NETCONN_STATE_ROOM = 2;
+	static final int NETCONN_STATE_DISCONNECTED = 10;
+	
+	static final int NETCONN_DISCONNECT_NORMAL = 0;
+	static final int NETCONN_DISCONNECT_SERVER_TOO_OLD = 1;
+	static final int NETCONN_DISCONNECT_AUTH_FAILED = 2;
+	static final int NETCONN_DISCONNECT_CONNLOST = 3;
+	static final int NETCONN_DISCONNECT_INTERNAL_ERROR = 100;
+	
+	static final int NETCONN_ROOMLEAVE_ABANDONED = 0;
+	static final int NETCONN_ROOMLEAVE_KICKED = 1;
+	
+	static final int NETCONN_MSG_TYPE_PLAYERINFO = 0;
+	static final int NETCONN_MSG_TYPE_SERVERMESSAGE = 1;
+	static final int NETCONN_MSG_TYPE_WARNING = 2;
+	static final int NETCONN_MSG_TYPE_ERROR = 3;
+	
+	static final int NETCONN_MAPCHANGE_FULL = 0;
+	static final int NETCONN_MAPCHANGE_MAP = 1;
+	static final int NETCONN_MAPCHANGE_MAPGEN = 2;
+	static final int NETCONN_MAPCHANGE_DRAWNMAP = 3;
+	static final int NETCONN_MAPCHANGE_MAZE_SIZE = 4;
+	static final int NETCONN_MAPCHANGE_TEMPLATE = 5;
+	static final int NETCONN_MAPCHANGE_THEME = 6;
+	static final int NETCONN_MAPCHANGE_SEED = 7;
+    
+	NetconnPtr flib_netconn_create(String playerName, String dataDirPath, String host, int port);
+	void flib_netconn_destroy(NetconnPtr conn);
+
+	void flib_netconn_tick(NetconnPtr conn);
+	boolean flib_netconn_is_chief(NetconnPtr conn);
+	String flib_netconn_get_playername(NetconnPtr conn);
+	GameSetupPtr flib_netconn_create_gamesetup(NetconnPtr conn);
+	int flib_netconn_send_quit(NetconnPtr conn, String quitmsg);
+	int flib_netconn_send_chat(NetconnPtr conn, String chat);
+	int flib_netconn_send_teamchat(NetconnPtr conn, String msg);
+	int flib_netconn_send_password(NetconnPtr conn, String passwd);
+	int flib_netconn_send_nick(NetconnPtr conn, String nick);
+	int flib_netconn_send_request_roomlist(NetconnPtr conn);
+	int flib_netconn_send_joinRoom(NetconnPtr conn, String room);
+	int flib_netconn_send_createRoom(NetconnPtr conn, String room);
+	int flib_netconn_send_renameRoom(NetconnPtr conn, String roomName);
+	int flib_netconn_send_leaveRoom(NetconnPtr conn, String msg);
+	int flib_netconn_send_toggleReady(NetconnPtr conn);
+	int flib_netconn_send_addTeam(NetconnPtr conn, TeamPtr team);
+	int flib_netconn_send_removeTeam(NetconnPtr conn, String teamname);
+	int flib_netconn_send_engineMessage(NetconnPtr conn, ByteArrayPtr message, NativeSizeT size);
+	int flib_netconn_send_teamHogCount(NetconnPtr conn, String teamname, int hogcount);
+	int flib_netconn_send_teamColor(NetconnPtr conn, String teamname, int colorIndex);
+	int flib_netconn_send_weaponset(NetconnPtr conn, WeaponsetPtr weaponset);
+	int flib_netconn_send_map(NetconnPtr conn, MapRecipePtr map);
+	int flib_netconn_send_mapName(NetconnPtr conn, String mapName);
+	int flib_netconn_send_mapGen(NetconnPtr conn, int mapGen);
+	int flib_netconn_send_mapTemplate(NetconnPtr conn, int templateFilter);
+	int flib_netconn_send_mapMazeSize(NetconnPtr conn, int mazeSize);
+	int flib_netconn_send_mapSeed(NetconnPtr conn, String seed);
+	int flib_netconn_send_mapTheme(NetconnPtr conn, String theme);
+	int flib_netconn_send_mapDrawdata(NetconnPtr conn, ByteArrayPtr drawData, NativeSizeT size);
+	int flib_netconn_send_script(NetconnPtr conn, String scriptName);
+	int flib_netconn_send_scheme(NetconnPtr conn, SchemePtr scheme);
+	int flib_netconn_send_roundfinished(NetconnPtr conn, boolean withoutError);
+	int flib_netconn_send_ban(NetconnPtr conn, String playerName);
+	int flib_netconn_send_kick(NetconnPtr conn, String playerName);
+	int flib_netconn_send_playerInfo(NetconnPtr conn, String playerName);
+	int flib_netconn_send_playerFollow(NetconnPtr conn, String playerName);
+	int flib_netconn_send_startGame(NetconnPtr conn);
+	int flib_netconn_send_toggleRestrictJoins(NetconnPtr conn);
+	int flib_netconn_send_toggleRestrictTeams(NetconnPtr conn);
+	int flib_netconn_send_clearAccountsCache(NetconnPtr conn);
+	int flib_netconn_send_setServerVar(NetconnPtr conn, String name, String value);
+	int flib_netconn_send_getServerVars(NetconnPtr conn);
+	
+	void flib_netconn_onMessage(NetconnPtr conn, IntStrCallback callback, Pointer context);
+	void flib_netconn_onClientFlags(NetconnPtr conn, StrStrBoolCallback callback, Pointer context);
+	void flib_netconn_onChat(NetconnPtr conn, StrStrCallback callback, Pointer context);
+	void flib_netconn_onConnected(NetconnPtr conn, VoidCallback callback, Pointer context);
+	void flib_netconn_onDisconnected(NetconnPtr conn, IntStrCallback callback, Pointer context);
+	void flib_netconn_onRoomlist(NetconnPtr conn, RoomListCallback callback, Pointer context);
+	void flib_netconn_onRoomAdd(NetconnPtr conn, RoomCallback callback, Pointer context);
+	void flib_netconn_onRoomDelete(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onRoomUpdate(NetconnPtr conn, StrRoomCallback callback, Pointer context);
+	void flib_netconn_onLobbyJoin(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onLobbyLeave(NetconnPtr conn, StrStrCallback callback, Pointer context);
+	void flib_netconn_onNickTaken(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onPasswordRequest(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onEnterRoom(NetconnPtr conn, BoolCallback callback, Pointer context);
+	void flib_netconn_onLeaveRoom(NetconnPtr conn, IntStrCallback callback, Pointer context);
+	void flib_netconn_onTeamAdd(NetconnPtr conn, TeamCallback callback, Pointer context);
+	void flib_netconn_onTeamDelete(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onRoomJoin(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onRoomLeave(NetconnPtr conn, StrStrCallback callback, Pointer context);
+	void flib_netconn_onRunGame(NetconnPtr conn, VoidCallback callback, Pointer context);
+	void flib_netconn_onTeamAccepted(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onHogCountChanged(NetconnPtr conn, StrIntCallback callback, Pointer context);
+	void flib_netconn_onTeamColorChanged(NetconnPtr conn, StrIntCallback callback, Pointer context);
+	void flib_netconn_onEngineMessage(NetconnPtr conn, BytesCallback callback, Pointer context);
+	void flib_netconn_onSchemeChanged(NetconnPtr conn, SchemeCallback callback, Pointer context);
+	void flib_netconn_onMapChanged(NetconnPtr conn, MapIntCallback callback, Pointer context);
+	void flib_netconn_onScriptChanged(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onWeaponsetChanged(NetconnPtr conn, WeaponsetCallback callback, Pointer context);
+	void flib_netconn_onServerVar(NetconnPtr conn, StrStrCallback callback, Pointer context);
+
+	// ipc/gameconn.h
+	static final int GAME_END_FINISHED = 0;
+	static final int GAME_END_INTERRUPTED = 1;
+	static final int GAME_END_HALTED = 2;
+	static final int GAME_END_ERROR = 3;
+	
+	GameconnPtr flib_gameconn_create(String playerName, GameSetupPtr setup, boolean netgame);
+	GameconnPtr flib_gameconn_create_playdemo(ByteArrayPtr demo, NativeSizeT size);
+	GameconnPtr flib_gameconn_create_loadgame(String playerName, ByteArrayPtr save, NativeSizeT size);
+	GameconnPtr flib_gameconn_create_campaign(String playerName, String seed, String script);
+
+	void flib_gameconn_destroy(GameconnPtr conn);
+	int flib_gameconn_getport(GameconnPtr conn);
+	void flib_gameconn_tick(GameconnPtr conn);
+
+	int flib_gameconn_send_enginemsg(GameconnPtr conn, ByteArrayPtr data, NativeSizeT len);
+	int flib_gameconn_send_textmsg(GameconnPtr conn, int msgtype, String msg);
+	int flib_gameconn_send_chatmsg(GameconnPtr conn, String playername, String msg);
+	int flib_gameconn_send_quit(GameconnPtr conn);
+	int flib_gameconn_send_cmd(GameconnPtr conn, String cmdString);
+	
+	void flib_gameconn_onConnect(GameconnPtr conn, VoidCallback callback, Pointer context);
+	void flib_gameconn_onDisconnect(GameconnPtr conn, IntCallback callback, Pointer context);
+	void flib_gameconn_onErrorMessage(GameconnPtr conn, StrCallback callback, Pointer context);
+	void flib_gameconn_onChat(GameconnPtr conn, StrBoolCallback callback, Pointer context);
+	void flib_gameconn_onGameRecorded(GameconnPtr conn, BytesBoolCallback callback, Pointer context);
+	void flib_gameconn_onEngineMessage(GameconnPtr conn, BytesCallback callback, Pointer context);
+	
+	// ipc/mapconn.h
+	public static final int MAPIMAGE_WIDTH = 256;
+	public static final int MAPIMAGE_HEIGHT = 128;
+	public static final int MAPIMAGE_BYTES = (MAPIMAGE_WIDTH/8*MAPIMAGE_HEIGHT);
+	
+	MapconnPtr flib_mapconn_create(MapRecipePtr mapdesc);
+	void flib_mapconn_destroy(MapconnPtr conn);
+	int flib_mapconn_getport(MapconnPtr conn);
+	void flib_mapconn_onSuccess(MapconnPtr conn, MapimageCallback callback, Pointer context);
+	void flib_mapconn_onFailure(MapconnPtr conn, StrCallback callback, Pointer context);
+	void flib_mapconn_tick(MapconnPtr conn);
+	
+	// model/map.h
+	public static final int MAPGEN_REGULAR = 0;
+	public static final int MAPGEN_MAZE = 1;
+	public static final int MAPGEN_DRAWN = 2;
+	public static final int MAPGEN_NAMED = 3;
+
+	public static final int TEMPLATEFILTER_ALL = 0;
+	public static final int TEMPLATEFILTER_SMALL = 1;
+	public static final int TEMPLATEFILTER_MEDIUM = 2;
+	public static final int TEMPLATEFILTER_LARGE = 3;
+	public static final int TEMPLATEFILTER_CAVERN = 4;
+	public static final int TEMPLATEFILTER_WACKY = 5;
+
+	public static final int MAZE_SIZE_SMALL_TUNNELS = 0;
+	public static final int MAZE_SIZE_MEDIUM_TUNNELS = 1;
+	public static final int MAZE_SIZE_LARGE_TUNNELS = 2;
+	public static final int MAZE_SIZE_SMALL_ISLANDS = 3;
+	public static final int MAZE_SIZE_MEDIUM_ISLANDS = 4;
+	public static final int MAZE_SIZE_LARGE_ISLANDS = 5;
+		
+	// model/schemelist.h
+	SchemelistPtr flib_schemelist_from_ini(String filename);
+	int flib_schemelist_to_ini(String filename, SchemelistPtr list);
+	void flib_schemelist_destroy(SchemelistPtr list);
+	
+	// model/team.h
+	TeamPtr flib_team_from_ini(String filename);
+	int flib_team_to_ini(String filename, TeamPtr team);
+	void flib_team_destroy(TeamPtr team);
+	
+	// model/weapon.h
+	WeaponsetListPtr flib_weaponsetlist_from_ini(String filename);
+	int flib_weaponsetlist_to_ini(String filename, WeaponsetListPtr weaponsets);
+	void flib_weaponsetlist_destroy(WeaponsetListPtr list);
+	
+	// model/gamesetup.h
+	void flib_gamesetup_destroy(GameSetupPtr gamesetup);
+	
+	// util/logging.h
+	public static final int FLIB_LOGLEVEL_ALL = -100;
+	public static final int FLIB_LOGLEVEL_DEBUG = -1;
+	public static final int FLIB_LOGLEVEL_INFO = 0;
+	public static final int FLIB_LOGLEVEL_WARNING = 1;
+	public static final int FLIB_LOGLEVEL_ERROR = 2;
+	public static final int FLIB_LOGLEVEL_NONE = 100;
+	
+    void flib_log_setLevel(int level);
+    void flib_log_setCallback(LogCallback callback);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/NativeSizeT.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,58 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.frontlib;
+
+/**
+ * This class represents the native C type size_t. On Android, this type could be mapped with int,
+ * but we use a separate type to make it easier to adapt for other platforms if anyone wants to use
+ * the mappings elsewhere. 
+ */
+public final class NativeSizeT extends Number {
+	private static final long serialVersionUID = 1L;
+	private final long value;
+	
+	private NativeSizeT(long value) {
+		this.value = value;
+	}
+	
+	public static NativeSizeT valueOf(long l) {
+		return new NativeSizeT(l);
+	}
+	
+	@Override
+	public int intValue() {
+		return (int)value;
+	}
+	
+	@Override
+	public long longValue() {
+		return value;
+	}
+
+	@Override
+	public double doubleValue() {
+		return value;
+	}
+
+	@Override
+	public float floatValue() {
+		return value;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ClientFlagsUpdate.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,48 @@
+package org.hedgewars.hedgeroid.netplay;
+
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+
+final class ClientFlagsUpdate {
+	public static final char FLAG_ADMIN = 'a';
+	public static final char FLAG_CHIEF = 'h';
+	public static final char FLAG_READY = 'r';
+	public static final char FLAG_REGISTERED = 'u';
+	
+	public final String nick, flags;
+	public final boolean newFlagState;
+	
+	public ClientFlagsUpdate(String nick, String flags, boolean newFlagState) {
+		this.nick = nick;
+		this.flags = flags;
+		this.newFlagState = newFlagState;
+	}
+
+	public Player applyTo(Player p) {
+		return new Player(
+				p.name,
+				updatedFlag(FLAG_REGISTERED, p.registered),
+				updatedFlag(FLAG_ADMIN, p.admin));
+	}
+	
+	public PlayerInRoom applyTo(PlayerInRoom p) {
+		return new PlayerInRoom(
+				this.applyTo(p.player),
+				updatedFlag(FLAG_READY, p.ready),
+				updatedFlag(FLAG_CHIEF, p.roomChief));
+	}
+	
+	public boolean appliesTo(char flag) {
+		return flags.indexOf(flag) != -1;
+	}
+	
+	private boolean updatedFlag(char flag, boolean oldValue) {
+		return appliesTo(flag) ? newFlagState : oldValue;
+	}
+	
+	@Override
+	public String toString() {
+		return "ClientFlagsUpdate [nick=" + nick + ", flags=" + flags
+				+ ", newFlagState=" + newFlagState + "]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/GameMessageListener.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,34 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+/**
+ * Interface with several event callbacks that represent network messages which are interesting
+ * for a running game, e.g. because they concern the lifecycle of the game or because they contain
+ * data that needs to be passed on.
+ * 
+ * These functions might be called on any thread.
+ */
+public interface GameMessageListener {
+	void onChatMessage(String nick, String message);
+	void onEngineMessage(byte[] em);
+	void onMessage(int type, String message);
+	void onNetDisconnected();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/MessageLog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,169 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.RelativeSizeSpan;
+import android.text.style.StyleSpan;
+import android.util.Log;
+
+public class MessageLog {
+	private static final int BACKLOG_LINES = 200;
+	
+	private static final int INFO_COLOR = Color.GRAY;
+	private static final int PLAYERINFO_COLOR = Color.GREEN;
+	private static final int CHAT_COLOR = Color.GREEN;
+	private static final int MECHAT_COLOR = Color.CYAN;
+	private static final int WARN_COLOR = Color.RED;
+	private static final int ERROR_COLOR = Color.RED;
+	
+	private final Context context;
+	private List<Listener> observers = new LinkedList<Listener>();
+	private List<CharSequence> log = new LinkedList<CharSequence>();
+	
+	public MessageLog(Context context) {
+		this.context = context;
+	}
+	
+	private Spanned makeLogTime() {
+		String time = DateFormat.getTimeFormat(context).format(new Date());
+		return withColor("[" + time + "] ", INFO_COLOR);
+	}
+	
+	private static Spanned span(CharSequence s, Object o) {
+		Spannable spannable = new SpannableString(s);
+		spannable.setSpan(o, 0, s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+		return spannable;
+	}
+	
+	private static Spanned withColor(CharSequence s, int color) {
+		return span(s, new ForegroundColorSpan(color));
+	}
+	
+	private static Spanned bold(CharSequence s) {
+		return span(s, new StyleSpan(Typeface.BOLD));
+	}
+	
+	private void append(CharSequence msg) {
+		SpannableStringBuilder ssb = new SpannableStringBuilder();
+		ssb.append(makeLogTime()).append(msg);
+		appendRaw(ssb);
+	}
+	
+	private void appendRaw(CharSequence msg) {
+		if(log.size() > BACKLOG_LINES) {
+			log.remove(0);
+			for(Listener o : observers) {
+				o.lineRemoved();
+			}
+		}
+		log.add(msg);
+		for(Listener o : observers) {
+			o.lineAdded(msg);
+		}
+	}
+	
+	void appendPlayerJoin(String playername) {
+		append(withColor("***" + context.getResources().getString(R.string.log_player_join, playername), INFO_COLOR));
+	}
+	
+	void appendPlayerLeave(String playername, String partMsg) {
+		String msg = "***";
+		if(partMsg != null) {
+			msg += context.getResources().getString(R.string.log_player_leave_with_msg, playername, partMsg);
+		} else {
+			msg += context.getResources().getString(R.string.log_player_leave, playername);
+		}
+		append(withColor(msg, INFO_COLOR));
+	}
+	
+	void appendChat(String playerName, String msg) {
+		if(msg.startsWith("/me ")) {
+			append(withColor("*"+playerName+" "+msg.substring(4), MECHAT_COLOR));
+		} else {
+			Spanned name = bold(playerName+": ");
+			Spanned fullMessage = withColor(TextUtils.concat(name, msg), CHAT_COLOR);
+			append(fullMessage);			
+		}
+	}
+	
+	void appendMessage(int type, String msg) {
+		switch(type) {
+		case Frontlib.NETCONN_MSG_TYPE_ERROR:
+			append(withColor("***"+msg, ERROR_COLOR));
+			break;
+		case Frontlib.NETCONN_MSG_TYPE_WARNING:
+			append(withColor("***"+msg, WARN_COLOR));
+			break;
+		case Frontlib.NETCONN_MSG_TYPE_PLAYERINFO:
+			append(withColor(msg.replace("\n", " "), PLAYERINFO_COLOR));
+			break;
+		case Frontlib.NETCONN_MSG_TYPE_SERVERMESSAGE:
+			appendRaw(span(TextUtils.concat("\n", Html.fromHtml(msg), "\n"), new RelativeSizeSpan(1.5f)));
+			break;
+		default:
+			Log.e("MessageLog", "Unknown messagetype "+type);
+		}
+	}
+	
+	void clear() {
+		for(Listener o : observers) {
+			o.clear();
+		}
+		log.clear();
+	}
+	
+	public void addListener(Listener o) {
+		observers.add(o);
+	}
+	
+	public void removeListener(Listener o) {
+		observers.remove(o);
+	}
+	
+	public static interface Listener {
+		void lineAdded(CharSequence text);
+		void lineRemoved();
+		void clear();
+	}
+
+	public Collection<CharSequence> getLog() {
+		return Collections.unmodifiableList(log);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetRoomState.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,185 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.*;
+import static org.hedgewars.hedgeroid.util.ObjectUtils.equal;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.hedgewars.hedgeroid.BasicRoomState;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType;
+
+/**
+ * This class manages the room state in a network game.
+ */
+class NetRoomState extends BasicRoomState {
+	final Map<String, TeamInGame> requestedTeams = new TreeMap<String, TeamInGame>();
+	private Netplay netplay;
+	
+	public NetRoomState(Netplay netplay) {
+		this.netplay = netplay;
+		initRoomState(false);
+	}
+
+	public void changeWeaponset(Weaponset weaponset) {
+		if(getChiefStatus() && !equal(weaponset, getWeaponset())) {
+			sendToNet(MSG_SEND_WEAPONSET, weaponset);
+			setWeaponset(weaponset);
+		}
+	}
+	
+	public void changeMapRecipe(MapRecipe mapRecipe) {
+		if(getChiefStatus() && !equal(mapRecipe, getMapRecipe())) {
+			sendToNet(MSG_SEND_MAP, mapRecipe);
+			setMapRecipe(mapRecipe);
+		}
+	}
+	
+	public void changeMapNameAndGenerator(String mapName) {
+		if(getChiefStatus() && !equal(mapName, getMapRecipe().name)) {
+			int newGenerator = MapRecipe.generatorForMapname(mapName);
+			if(newGenerator != getMapRecipe().mapgen) {
+				sendToNet(MSG_SEND_MAP_GENERATOR, newGenerator, null);
+			}
+			sendToNet(MSG_SEND_MAP_NAME, mapName);
+			setMapRecipe(getMapRecipe().withName(mapName).withMapgen(newGenerator));
+		}
+	}
+	
+	public void changeMapTemplate(int template) {
+		if(getChiefStatus() && template != getMapRecipe().templateFilter) {
+			sendToNet(MSG_SEND_MAP_TEMPLATE, template, null);
+			setMapRecipe(getMapRecipe().withTemplateFilter(template));
+		}
+	}
+	
+	public void changeMazeSize(int mazeSize) {
+		if(getChiefStatus() && mazeSize != getMapRecipe().mazeSize) {
+			sendToNet(MSG_SEND_MAZE_SIZE, mazeSize, 0);
+			setMapRecipe(getMapRecipe().withMazeSize(mazeSize));
+		}
+	}
+	
+	public void changeMapSeed(String seed) {
+		if(getChiefStatus() && !equal(seed, getMapRecipe().seed)) {
+			sendToNet(MSG_SEND_MAP_SEED, seed);
+			setMapRecipe(getMapRecipe().withSeed(seed));
+		}
+	}
+	
+	public void changeMapTheme(String theme) {
+		if(getChiefStatus() && !equal(theme, getMapRecipe().theme)) {
+			sendToNet(MSG_SEND_MAP_THEME, theme);
+			setMapRecipe(getMapRecipe().withTheme(theme));
+		}
+	}
+	
+	public void changeMapDrawdata(byte[] drawdata) {
+		if(getChiefStatus() && !Arrays.equals(drawdata, getMapRecipe().getDrawData())) {
+			sendToNet(MSG_SEND_MAP_DRAWDATA, drawdata);
+			setMapRecipe(getMapRecipe().withDrawData(drawdata));
+		}
+	}
+	
+	public void changeGameStyle(String gameStyle) {
+		if(getChiefStatus() && !equal(gameStyle, getGameStyle())) {
+			sendToNet(MSG_SEND_GAMESTYLE, gameStyle);
+			setGameStyle(gameStyle);
+		}
+	}
+	
+	public void changeScheme(Scheme scheme) {
+		if(getChiefStatus() && !equal(scheme, getScheme())) {
+			sendToNet(MSG_SEND_SCHEME, scheme);
+			setScheme(scheme);
+		}
+	}
+	
+	void initRoomState(boolean chief) {
+		setTeams(Collections.<String, TeamInGame>emptyMap());
+		requestedTeams.clear();
+		
+		setChief(chief);
+		setGameStyle(GameConfig.DEFAULT_STYLE);
+		setMapRecipe(MapRecipe.makeRandomMap(0, "seed", GameConfig.DEFAULT_THEME));
+		setScheme(netplay.defaultScheme);
+		setWeaponset(netplay.defaultWeaponset);
+		sendFullConfig();
+	}
+	
+	void sendFullConfig() {
+		if(getChiefStatus()) {
+			sendToNet(MSG_SEND_GAMESTYLE, getGameStyle());
+			sendToNet(MSG_SEND_SCHEME, getScheme());
+			sendToNet(MSG_SEND_WEAPONSET, getWeaponset());
+			sendToNet(MSG_SEND_MAP, getMapRecipe());
+		}
+	}
+	
+	private boolean sendToNet(ToNetMsgType what, Object obj) {
+		return netplay.sendToNet(what, 0, obj);
+	}
+	
+	private boolean sendToNet(ToNetMsgType what, int arg1, Object obj) {
+		return netplay.sendToNet(what, arg1, obj);
+	}
+
+	public void requestAddTeam(Team team, int colorIndex) {
+		TeamIngameAttributes tia = new TeamIngameAttributes(netplay.getPlayerName(), colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, false);
+		TeamInGame newTeamInGame = new TeamInGame(team, tia);
+		requestedTeams.put(team.name, newTeamInGame);
+		sendToNet(MSG_SEND_ADD_TEAM, newTeamInGame);
+	}
+
+	public void requestRemoveTeam(String teamname) {
+		sendToNet(MSG_SEND_REMOVE_TEAM, teamname);
+	}
+
+	public void changeTeamColorIndex(String teamname, int colorIndex) {
+		if(getChiefStatus()) {
+			TeamInGame team = getTeams().get(teamname);
+			if(team.ingameAttribs.colorIndex != colorIndex) {
+				sendToNet(MSG_SEND_TEAM_COLOR_INDEX, colorIndex, teamname);
+				putTeam(team.withAttribs(team.ingameAttribs.withColorIndex(colorIndex)));
+			}
+		}
+	}
+
+	public void changeTeamHogCount(String teamname, int hogcount) {
+		if(getChiefStatus()) {
+			TeamInGame team = getTeams().get(teamname);
+			if(team.ingameAttribs.hogCount != hogcount) {
+				sendToNet(MSG_SEND_TEAM_HOG_COUNT, hogcount, teamname);
+				putTeam(team.withAttribs(team.ingameAttribs.withHogCount(hogcount)));
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,535 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.*;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.RoomStateManager;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Schemes;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+import org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType;
+import org.hedgewars.hedgeroid.util.ObservableTreeMap;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+import android.util.Pair;
+
+
+/**
+ * This class manages the application's networking state.
+ */
+public class Netplay {
+	public static enum State { NOT_CONNECTED, CONNECTING, LOBBY, ROOM }
+	
+	// Extras in broadcasts
+	public static final String EXTRA_PLAYERNAME = "playerName";
+	public static final String EXTRA_MESSAGE = "message";
+	public static final String EXTRA_HAS_ERROR = "hasError";
+	public static final String EXTRA_REASON = "reason";
+	
+	private static final String ACTIONPREFIX = "org.hedgewars.hedgeroid.netconn.";
+	public static final String ACTION_DISCONNECTED = ACTIONPREFIX+"DISCONNECTED";
+	public static final String ACTION_CONNECTED = ACTIONPREFIX+"CONNECTED";
+	public static final String ACTION_PASSWORD_REQUESTED = ACTIONPREFIX+"PASSWORD_REQUESTED";
+	public static final String ACTION_ENTERED_ROOM_FROM_LOBBY = ACTIONPREFIX+"ENTERED_ROOM";
+	public static final String ACTION_LEFT_ROOM = ACTIONPREFIX+"LEFT_ROOM";
+	public static final String ACTION_STATE_CHANGED = ACTIONPREFIX+"STATE_CHANGED";
+	
+	public static final String DEFAULT_SERVER = "netserver.hedgewars.org";
+	public static final int DEFAULT_PORT = 46631;
+		
+	private final Context appContext;
+	private final LocalBroadcastManager broadcastManager;
+	private final FromNetHandler fromNetHandler = new FromNetHandler();
+	public final Scheme defaultScheme;
+	public final Weaponset defaultWeaponset;
+	
+	private State state = State.NOT_CONNECTED;
+	private String playerName;
+	
+	// null or stale if not in room state
+	private final NetRoomState netRoomState = new NetRoomState(this);
+	
+	// null if there is no running connection (==state is NOT_CONNECTED)
+	private ThreadedNetConnection connection;
+	
+	public final ObservableTreeMap<String, Player> lobbyPlayerlist = new ObservableTreeMap<String, Player>();
+	public final ObservableTreeMap<String, PlayerInRoom> roomPlayerlist = new ObservableTreeMap<String, PlayerInRoom>();
+	public final Roomlist roomList = new Roomlist();
+	public final MessageLog lobbyChatlog;
+	public final MessageLog roomChatlog;
+	
+	private final List<GameMessageListener> gameMessageListeners = new LinkedList<GameMessageListener>();
+	private final List<RunGameListener> runGameListeners = new LinkedList<RunGameListener>();
+	
+	public Netplay(Context appContext, Scheme defaultScheme, Weaponset defaultWeaponset) {
+		this.appContext = appContext;
+		broadcastManager = LocalBroadcastManager.getInstance(appContext);
+		lobbyChatlog = new MessageLog(appContext);
+		roomChatlog = new MessageLog(appContext);
+		this.defaultScheme = defaultScheme;
+		this.defaultWeaponset = defaultWeaponset;
+	}
+	
+	public RoomStateManager getRoomStateManager() {
+		return netRoomState;
+	}
+	
+	private void clearLobbyState() {
+		lobbyPlayerlist.clear();
+		roomList.clear();
+		lobbyChatlog.clear();
+	}
+	
+	private void initRoomState(boolean chief) {
+		roomChatlog.clear();
+		roomPlayerlist.clear();
+		netRoomState.initRoomState(chief);
+	}
+	
+	public void registerGameMessageListener(GameMessageListener listener) {
+		gameMessageListeners.add(listener);
+	}
+	
+	public void unregisterGameMessageListener(GameMessageListener listener) {
+		gameMessageListeners.remove(listener);
+	}
+	
+	public void registerRunGameListener(RunGameListener listener) {
+		runGameListeners.add(listener);
+	}
+	
+	public void unregisterRunGameListener(RunGameListener listener) {
+		runGameListeners.remove(listener);
+	}
+	
+	public void connectToDefaultServer(String playerName) {
+		connect(playerName, DEFAULT_SERVER, DEFAULT_PORT);
+	}
+	
+	/**
+	 * Establish a new connection. Only call if the current state is NOT_CONNECTED.
+	 * 
+	 * The state will switch to CONNECTING immediately. After that, it can asynchronously change to any other state.
+	 * State changes are indicated by broadcasts. In particular, if an error occurs while trying to connect, the state
+	 * will change back to NOT_CONNECTED and an ACTION_DISCONNECTED broadcast is sent.
+	 */
+	public void connect(String name, String host, int port) {
+		playerName = name;
+		if(state != State.NOT_CONNECTED) {
+			throw new IllegalStateException("Attempt to start a new connection while the old one was still running.");
+		}
+		
+		clearLobbyState();
+		changeState(State.CONNECTING);
+		connection = ThreadedNetConnection.startConnection(appContext, fromNetHandler, name, host, port);
+		connection.setFastTickRate(true);
+	}
+	
+	public void sendNick(String nick) {
+		playerName = nick;
+		sendToNet(MSG_SEND_NICK, nick);
+	}
+	public void sendPassword(String password) { sendToNet(MSG_SEND_PASSWORD, password); }
+	public void sendQuit(String message) { sendToNet(MSG_SEND_QUIT, message); }
+	public void sendRoomlistRequest() { sendToNet(MSG_SEND_ROOMLIST_REQUEST); }
+	public void sendPlayerInfoQuery(String name) { sendToNet(MSG_SEND_PLAYER_INFO_REQUEST, name); }
+	public void sendChat(String s) { sendToNet(MSG_SEND_CHAT, s); }
+	public void sendTeamChat(String s) { sendToNet(MSG_SEND_TEAMCHAT, s); }
+	public void sendFollowPlayer(String nick) { sendToNet(MSG_SEND_FOLLOW_PLAYER, nick); }
+	public void sendJoinRoom(String name) { sendToNet(MSG_SEND_JOIN_ROOM, name); }
+	public void sendCreateRoom(String name) { sendToNet(MSG_SEND_CREATE_ROOM, name); }
+	public void sendLeaveRoom(String message) { sendToNet(MSG_SEND_LEAVE_ROOM, message); }
+	public void sendKick(String player) { sendToNet(MSG_SEND_KICK, player); }
+	public void sendEngineMessage(byte[] engineMessage) { sendToNet(MSG_SEND_ENGINE_MESSAGE, engineMessage); }
+	public void sendRoundFinished(boolean withoutError) { sendToNet(MSG_SEND_ROUND_FINISHED, Boolean.valueOf(withoutError)); }
+	public void sendToggleReady() { sendToNet(MSG_SEND_TOGGLE_READY); }
+	public void sendStartGame() { sendToNet(MSG_SEND_START_GAME); }
+	
+	public void disconnect() { sendToNet(MSG_DISCONNECT, "User Quit"); }
+	
+	private static Netplay instance;
+	
+	/**
+	 * Retrieve the single app-wide instance of the netplay interface, creating it if it
+	 * does not exist yet.
+	 * 
+	 * @param applicationContext
+	 * @return
+	 */
+	public static Netplay getAppInstance(Context applicationContext) {
+		if(instance == null) {
+			// We will need some default values for rooms, best load them here
+			Scheme defaultScheme = null;
+			Weaponset defaultWeaponset = null;
+			try {
+				List<Scheme> schemes = Schemes.loadBuiltinSchemes(applicationContext);
+				for(Scheme scheme : schemes) {
+					if(scheme.name.equals(GameConfig.DEFAULT_SCHEME)) {
+						defaultScheme = scheme;
+					}
+				}
+				List<Weaponset> weaponsets = Weaponsets.loadBuiltinWeaponsets(applicationContext);
+				for(Weaponset weaponset : weaponsets) {
+					if(weaponset.name.equals(GameConfig.DEFAULT_WEAPONSET)) {
+						defaultWeaponset = weaponset;
+					}
+				}
+			} catch(IOException e) {
+				throw new RuntimeException(e);
+			}
+			
+			if(defaultScheme==null || defaultWeaponset==null) {
+				throw new RuntimeException("Unable to load default scheme or weaponset");
+			}
+			
+			instance = new Netplay(applicationContext, defaultScheme, defaultWeaponset);
+		}
+		return instance;
+	}
+
+	public State getState() {
+		return state;
+	}
+	
+	private void changeState(State newState) {
+		if(newState != state) {
+			state = newState;
+			broadcastManager.sendBroadcastSync(new Intent(ACTION_STATE_CHANGED));
+		}
+	}
+	
+	public boolean isChief() {
+		if(netRoomState != null) {
+			return netRoomState.getChiefStatus();
+		} else {
+			return false;
+		}
+	}
+	
+	public String getPlayerName() {
+		return playerName;
+	}
+	
+	boolean sendToNet(ToNetMsgType what) {
+		return sendToNet(what, 0, null);
+	}
+	
+	boolean sendToNet(ToNetMsgType what, Object obj) {
+		return sendToNet(what, 0, obj);
+	}
+	
+	boolean sendToNet(ToNetMsgType what, int arg1, Object obj) {
+		if(connection != null) {
+			Handler handler = connection.toNetHandler;
+			return handler.sendMessage(handler.obtainMessage(what.ordinal(), arg1, 0, obj));
+		} else {
+			return false;
+		}
+	}
+	
+	private MessageLog getCurrentLog() {
+		if(state == State.ROOM) {
+			return roomChatlog;
+		} else {
+			return lobbyChatlog;
+		}
+	}
+	
+	public static enum FromNetMsgType {
+		MSG_LOBBY_JOIN,
+		MSG_LOBBY_LEAVE,
+		MSG_ROOM_JOIN,
+		MSG_ROOM_LEAVE,
+		MSG_CLIENT_FLAGS,
+		MSG_CHAT,
+		MSG_MESSAGE,
+		MSG_ROOM_ADD,
+		MSG_ROOM_UPDATE,
+		MSG_ROOM_DELETE,
+		MSG_ROOMLIST,
+		MSG_CONNECTED,
+		MSG_DISCONNECTED,
+		MSG_PASSWORD_REQUEST,
+		MSG_ENTER_ROOM_FROM_LOBBY,
+		MSG_LEAVE_ROOM,
+		MSG_TEAM_ADDED,
+		MSG_TEAM_DELETED,
+		MSG_TEAM_ACCEPTED,
+		MSG_TEAM_COLOR_CHANGED,
+		MSG_HOG_COUNT_CHANGED,
+		MSG_ENGINE_MESSAGE,
+		MSG_RUN_GAME,
+		MSG_SCHEME_CHANGED,
+		MSG_MAP_CHANGED,
+		MSG_SCRIPT_CHANGED,
+		MSG_WEAPONSET_CHANGED;
+		
+		static final List<FromNetMsgType> values = Collections.unmodifiableList(Arrays.asList(FromNetMsgType.values()));
+	}
+	
+	/**
+	 * Processes messages from the networking system. Always runs on the main thread.
+	 */
+	@SuppressLint("HandlerLeak")
+	final class FromNetHandler extends Handler {
+		public FromNetHandler() {
+			super(Looper.getMainLooper());
+		}
+		
+		@SuppressWarnings("unchecked")
+		@Override
+		public void handleMessage(Message msg) {
+			switch(FromNetMsgType.values.get(msg.what)) {
+			case MSG_LOBBY_JOIN: {
+				String name = (String)msg.obj;
+				lobbyPlayerlist.put(name, new Player(name, false, false));
+				lobbyChatlog.appendPlayerJoin(name);
+				break;
+			}
+			case MSG_LOBBY_LEAVE: {
+				Pair<String, String> args = (Pair<String, String>)msg.obj;
+				lobbyPlayerlist.remove(args.first);
+				lobbyChatlog.appendPlayerLeave(args.first, args.second);
+				break;
+			}
+			case MSG_ROOM_JOIN: {
+				String name = (String)msg.obj;
+				Player p = lobbyPlayerlist.get(name);
+				if(p==null) {
+					Log.w("Netplay", "Unknown player joined room: "+name);
+					p = new Player(name, false, false);
+				}
+				roomPlayerlist.put(name, new PlayerInRoom(p, false, false));
+				roomChatlog.appendPlayerJoin(name);
+				break;
+			}
+			case MSG_ROOM_LEAVE: {
+				Pair<String, String> args = (Pair<String, String>)msg.obj;
+				roomPlayerlist.remove(args.first);
+				roomChatlog.appendPlayerLeave(args.first, args.second);
+				break;
+			}
+			case MSG_CLIENT_FLAGS: {
+				ClientFlagsUpdate upd = (ClientFlagsUpdate)msg.obj;
+				PlayerInRoom pir = roomPlayerlist.get(upd.nick);
+				if(pir != null) {
+					roomPlayerlist.put(upd.nick, upd.applyTo(pir));
+				}
+				Player p = lobbyPlayerlist.get(upd.nick);
+				if(p != null) {
+					lobbyPlayerlist.put(upd.nick, upd.applyTo(p));
+				} else {
+					Log.w("Netplay", "Received client flags for unknown player "+upd.nick);
+				}
+				if(playerName.equals(upd.nick) && upd.appliesTo(ClientFlagsUpdate.FLAG_CHIEF)) {
+					netRoomState.setChief(upd.newFlagState);
+				}
+				break;
+			}
+			case MSG_CHAT: {
+				Pair<String, String> args = (Pair<String, String>)msg.obj;
+				getCurrentLog().appendChat(args.first, args.second);
+				for(GameMessageListener listener : gameMessageListeners) {
+					listener.onChatMessage(args.first, args.second);
+				}
+				break;
+			}
+			case MSG_MESSAGE: {
+				getCurrentLog().appendMessage(msg.arg1, (String)msg.obj);
+				for(GameMessageListener listener : gameMessageListeners) {
+					listener.onMessage(1, (String)msg.obj);
+				}
+				break;
+			}
+			case MSG_ROOM_ADD: {
+				Room room = (Room)msg.obj;
+				roomList.addRoomWithNewId(room);
+				break;
+			}
+			case MSG_ROOM_UPDATE: {
+				Pair<String, Room> args = (Pair<String, Room>)msg.obj;
+				roomList.updateRoom(args.first, args.second);
+				break;
+			}
+			case MSG_ROOM_DELETE: {
+				roomList.remove((String)msg.obj);
+				break;
+			}
+			case MSG_ROOMLIST: {
+				Room[] rooms = (Room[])msg.obj;
+				roomList.updateList(rooms);
+				break;
+			}
+			case MSG_CONNECTED: {
+				playerName = (String)msg.obj;
+				changeState(State.LOBBY);
+				broadcastManager.sendBroadcast(new Intent(ACTION_CONNECTED));
+				break;
+			}
+			case MSG_DISCONNECTED: {
+				Pair<Boolean, String> args = (Pair<Boolean, String>)msg.obj;
+				for(GameMessageListener listener : gameMessageListeners) {
+					listener.onNetDisconnected();
+				}
+				changeState(State.NOT_CONNECTED);
+				connection = null;
+				Intent intent = new Intent(ACTION_DISCONNECTED);
+				intent.putExtra(EXTRA_HAS_ERROR, args.first);
+				intent.putExtra(EXTRA_MESSAGE, args.second);
+				broadcastManager.sendBroadcastSync(intent);
+				break;
+			}
+			case MSG_PASSWORD_REQUEST: {
+				Intent intent = new Intent(ACTION_PASSWORD_REQUESTED);
+				intent.putExtra(EXTRA_PLAYERNAME, (String)msg.obj);
+				broadcastManager.sendBroadcast(intent);
+				break;
+			}
+			case MSG_ENTER_ROOM_FROM_LOBBY: {
+				initRoomState((Boolean)msg.obj);
+				changeState(State.ROOM);
+				Intent intent = new Intent(ACTION_ENTERED_ROOM_FROM_LOBBY);
+				broadcastManager.sendBroadcastSync(intent);
+				break;
+			}
+			case MSG_LEAVE_ROOM: {
+				changeState(State.LOBBY);
+				Intent intent = new Intent(ACTION_LEFT_ROOM);
+				intent.putExtra(EXTRA_MESSAGE, (String)msg.obj);
+				intent.putExtra(EXTRA_REASON, msg.arg1);
+				broadcastManager.sendBroadcastSync(intent);
+				break;
+			}
+			case MSG_TEAM_ADDED: {
+				TeamInGame newTeam = (TeamInGame)msg.obj;
+				if(isChief()) {
+					int freeColor = TeamInGame.getUnusedOrRandomColorIndex(netRoomState.getTeams().values());
+					sendToNet(MSG_SEND_TEAM_HOG_COUNT, newTeam.ingameAttribs.hogCount, newTeam.team.name);
+					sendToNet(MSG_SEND_TEAM_COLOR_INDEX, freeColor, newTeam.team.name);
+					newTeam = newTeam.withAttribs(newTeam.ingameAttribs.withColorIndex(freeColor));
+				}
+				netRoomState.putTeam(newTeam);
+				break;
+			}
+			case MSG_TEAM_DELETED: {
+				netRoomState.removeTeam((String)msg.obj);
+				break;
+			}
+			case MSG_TEAM_ACCEPTED: {
+				TeamInGame requestedTeam = netRoomState.requestedTeams.remove(msg.obj);
+				if(requestedTeam!=null) {
+					netRoomState.putTeam(requestedTeam);
+					if(isChief()) {
+						// Not strictly necessary, but QtFrontend does it...
+						sendToNet(MSG_SEND_TEAM_HOG_COUNT, requestedTeam.ingameAttribs.hogCount, requestedTeam.team.name);
+					}
+				} else {
+					Log.e("Netplay", "Got accepted message for team that was never requested.");
+				}
+				break;
+			}
+			case MSG_TEAM_COLOR_CHANGED: {
+				TeamInGame oldEntry = netRoomState.getTeams().get((String)msg.obj);
+				if(oldEntry != null) {
+					/*
+					 * If we are chief, we ignore colors from the outside. They only come from the server
+					 * when someone adds a team then, and we override that choice anyway.
+					 * Worse, that color message arrives *after* we have overridden the color, so it would
+					 * re-override it right back.
+					 */
+					if(!isChief()) {
+						TeamIngameAttributes newAttribs = oldEntry.ingameAttribs.withColorIndex(msg.arg1);
+						netRoomState.putTeam(oldEntry.withAttribs(newAttribs));
+					}
+				} else {
+					Log.e("Netplay", "Color update for unknown team "+msg.obj);
+				}
+				break;
+			}
+			case MSG_HOG_COUNT_CHANGED: {
+				TeamInGame oldEntry = netRoomState.getTeams().get((String)msg.obj);
+				if(oldEntry != null) {
+					TeamIngameAttributes newAttribs = oldEntry.ingameAttribs.withHogCount(msg.arg1);
+					netRoomState.putTeam(oldEntry.withAttribs(newAttribs));
+				} else {
+					Log.e("Netplay", "Hog count update for unknown team "+msg.obj);
+				}
+				break;
+			}
+			case MSG_ENGINE_MESSAGE: {
+				byte[] em = (byte[])msg.obj;
+				for(GameMessageListener listener : gameMessageListeners) {
+					listener.onEngineMessage(em);
+				}
+				break;
+			}
+			case MSG_RUN_GAME: {
+				GameConfig config = (GameConfig)msg.obj;
+				for(RunGameListener listener : runGameListeners) {
+					listener.runGame(config);
+				}
+				break;
+			}
+			case MSG_MAP_CHANGED: {
+				netRoomState.setMapRecipe((MapRecipe)msg.obj);
+				break;
+			}
+			case MSG_SCHEME_CHANGED: {
+				netRoomState.setScheme((Scheme)msg.obj);
+				break;
+			}
+			case MSG_SCRIPT_CHANGED: {
+				netRoomState.setGameStyle((String)msg.obj);
+				break;
+			}
+			case MSG_WEAPONSET_CHANGED: {
+				netRoomState.setWeaponset((Weaponset)msg.obj);
+				break;
+			}
+			default: {
+				Log.e("FromNetHandler", "Unknown message type: "+msg.what);
+				break;
+			}
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Roomlist.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,58 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.RoomWithId;
+import org.hedgewars.hedgeroid.util.ObservableTreeMap;
+
+public class Roomlist extends ObservableTreeMap<String, RoomWithId> {
+	private long nextId = 1;
+	
+	public void updateList(Room[] newRooms) {
+		Map<String, RoomWithId> newMap = new TreeMap<String, RoomWithId>();
+		for(Room room : newRooms) {
+			RoomWithId oldEntry = get(room.name);
+			if(oldEntry == null) {
+				newMap.put(room.name, new RoomWithId(room, nextId++));
+			} else {
+				newMap.put(room.name, new RoomWithId(room, oldEntry.id));
+			}
+		}
+		replaceContent(newMap);
+	}
+	
+	public void addRoomWithNewId(Room room) {
+		put(room.name, new RoomWithId(room, nextId++));
+	}
+	
+	public void updateRoom(String name, Room room) {
+		RoomWithId oldEntry = get(name);
+		if(oldEntry == null) {
+			addRoomWithNewId(room);
+		} else {
+			remove(name);
+			put(room.name, new RoomWithId(room, oldEntry.id));
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RunGameListener.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,26 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+
+public interface RunGameListener {
+	void runGame(GameConfig config);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ThreadedNetConnection.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,578 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.netplay;
+
+import static org.hedgewars.hedgeroid.netplay.Netplay.FromNetMsgType.*;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.ByteArrayPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BytesCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.IntStrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapIntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapRecipePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.NetconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomArrayPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomListCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.SchemeCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.SchemePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrIntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrRoomCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrStrBoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrStrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.WeaponsetCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.WeaponsetPtr;
+import org.hedgewars.hedgeroid.frontlib.NativeSizeT;
+import org.hedgewars.hedgeroid.netplay.Netplay.FromNetHandler;
+import org.hedgewars.hedgeroid.netplay.Netplay.FromNetMsgType;
+import org.hedgewars.hedgeroid.util.FileUtils;
+import org.hedgewars.hedgeroid.util.TickHandler;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.Pair;
+
+import com.sun.jna.Pointer;
+
+/**
+ * This class handles the actual communication with the networking library, running on a separate thread.
+ * 
+ * In order to process net messages, this class regularly runs a tick() function on the frontlib. This
+ * usually happens several times per second, but it can be slowed down a lot if no fast reaction to
+ * events is required (e.g. to conserve battery if the application is in the background).
+ */
+class ThreadedNetConnection {
+	private static final long TICK_INTERVAL_FAST = 100;
+	private static final long TICK_INTERVAL_SLOW = 5000;
+	private static final Frontlib FLIB = Flib.INSTANCE;
+	
+	public final ToNetHandler toNetHandler;
+	
+	private final Context appContext;
+	private final FromNetHandler fromNetHandler;
+	private final TickHandler tickHandler;
+
+	/**
+	 * conn can only be null while connecting (the first thing in the thread), and directly after disconnecting,
+	 * in the same message (the looper is shut down on disconnect, so there will be no messages after that).
+	 */
+	private NetconnPtr conn;
+	private String playerName;
+	
+	private ThreadedNetConnection(Context appContext, FromNetHandler fromNetHandler) {
+		this.appContext = appContext;
+		this.fromNetHandler = fromNetHandler;
+		
+		HandlerThread thread = new HandlerThread("NetThread");
+		thread.start();
+		toNetHandler = new ToNetHandler(thread.getLooper());
+		tickHandler = new TickHandler(thread.getLooper(), TICK_INTERVAL_FAST, tickCb);
+	}
+	
+	private void connect(final String name, final String host, final int port) {
+		toNetHandler.post(new Runnable() {
+			public void run() {
+				playerName = name == null ? "Player" : name;
+				File dataPath;
+				try {
+					dataPath = FileUtils.getDataPathFile(appContext);
+				} catch (FileNotFoundException e) {
+					shutdown(true, appContext.getString(R.string.sdcard_not_mounted));
+					return;
+				}
+				conn = FLIB.flib_netconn_create(playerName, dataPath.getAbsolutePath()+"/", host, port);
+				if(conn == null) {
+					shutdown(true, appContext.getString(R.string.error_connection_failed));
+					return;
+				}
+
+				FLIB.flib_netconn_onSchemeChanged(conn, cfgSchemeCb, null);
+				FLIB.flib_netconn_onClientFlags(conn, clientFlagsCb, null);
+				FLIB.flib_netconn_onChat(conn, chatCb, null);
+				FLIB.flib_netconn_onConnected(conn, connectedCb, null);
+				FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
+				FLIB.flib_netconn_onEngineMessage(conn, engineMessageCb, null);
+				FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null);
+				FLIB.flib_netconn_onHogCountChanged(conn, hogCountChangedCb, null);
+				FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null);
+				FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
+				FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
+				FLIB.flib_netconn_onMapChanged(conn, mapChangedCb, null);
+				FLIB.flib_netconn_onMessage(conn, messageCb, null);
+				FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null);
+				FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
+				FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
+				FLIB.flib_netconn_onRoomJoin(conn, roomJoinCb, null);
+				FLIB.flib_netconn_onRoomLeave(conn, roomLeaveCb, null);
+				FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
+				FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
+				FLIB.flib_netconn_onRunGame(conn, runGameCb, null);
+				FLIB.flib_netconn_onScriptChanged(conn, scriptChangedCb, null);
+				// FLIB.flib_netconn_onServerVar(conn, serverVarCb, null);
+				FLIB.flib_netconn_onTeamAccepted(conn, teamAcceptedCb, null);
+				FLIB.flib_netconn_onTeamAdd(conn, teamAddedCb, null);
+				FLIB.flib_netconn_onTeamColorChanged(conn, teamColorChangedCb, null);
+				FLIB.flib_netconn_onTeamDelete(conn, teamDeletedCb, null);
+				FLIB.flib_netconn_onWeaponsetChanged(conn, weaponsetChangedCb, null);
+				
+				tickHandler.start();
+			}
+		});
+	}
+	
+	public static ThreadedNetConnection startConnection(Context appContext, FromNetHandler fromNetHandler, String playerName, String host, int port) {
+		ThreadedNetConnection result = new ThreadedNetConnection(appContext, fromNetHandler);
+		result.connect(playerName, host, port);
+		return result;
+	}
+	
+	public void setFastTickRate(boolean fastTickRate) {
+		tickHandler.setInterval(fastTickRate ? TICK_INTERVAL_FAST : TICK_INTERVAL_SLOW);
+	}
+	
+	private final Runnable tickCb = new Runnable() {
+		public void run() {
+			FLIB.flib_netconn_tick(conn);
+		}
+	};
+	
+	private final SchemeCallback cfgSchemeCb = new SchemeCallback() {
+		public void callback(Pointer context, SchemePtr schemePtr) {
+			sendFromNet(MSG_SCHEME_CHANGED, schemePtr.deref());
+		}
+	};
+	
+	private final MapIntCallback mapChangedCb = new MapIntCallback() {
+		public void callback(Pointer context, MapRecipePtr mapPtr, int updateType) {
+			sendFromNet(MSG_MAP_CHANGED, updateType, mapPtr.deref());
+		}
+	};
+	
+	private final StrCallback scriptChangedCb = new StrCallback() {
+		public void callback(Pointer context, String script) {
+			sendFromNet(MSG_SCRIPT_CHANGED, script);
+		}
+	};
+	
+	private final WeaponsetCallback weaponsetChangedCb = new WeaponsetCallback() {
+		public void callback(Pointer context, WeaponsetPtr weaponsetPtr) {
+			sendFromNet(MSG_WEAPONSET_CHANGED, weaponsetPtr.deref());				
+		}
+	};
+	
+	private final StrCallback lobbyJoinCb = new StrCallback() {
+		public void callback(Pointer context, String name) {
+			sendFromNet(MSG_LOBBY_JOIN, name);
+		}
+	};
+	
+	private final StrStrCallback lobbyLeaveCb = new StrStrCallback() {
+		public void callback(Pointer context, String name, String msg) {
+			sendFromNet(MSG_LOBBY_LEAVE, Pair.create(name, msg));
+		}
+	};
+	
+	private final StrCallback roomJoinCb = new StrCallback() {
+		public void callback(Pointer context, String name) {
+			sendFromNet(MSG_ROOM_JOIN, name);
+		}
+	};
+	
+	private final StrStrCallback roomLeaveCb = new StrStrCallback() {
+		public void callback(Pointer context, String name, String message) {
+			sendFromNet(MSG_ROOM_LEAVE, Pair.create(name, message));
+		}
+	};
+	
+	private final StrStrBoolCallback clientFlagsCb = new StrStrBoolCallback() {
+		public void callback(Pointer context, String nick, String flags, boolean newFlagsState) {
+			sendFromNet(MSG_CLIENT_FLAGS, new ClientFlagsUpdate(nick, flags, newFlagsState));
+		}
+	};
+	
+	private final StrStrCallback chatCb = new StrStrCallback() {
+		public void callback(Pointer context, String name, String msg) {
+			sendFromNet(MSG_CHAT, Pair.create(name, msg));
+		}
+	};
+	
+	private final IntStrCallback messageCb = new IntStrCallback() {
+		public void callback(Pointer context, int type, String msg) {
+			sendFromNet(MSG_MESSAGE, type, msg);
+		}
+	};
+	
+	private final RoomCallback roomAddCb = new RoomCallback() {
+		public void callback(Pointer context, RoomPtr roomPtr) {
+			sendFromNet(MSG_ROOM_ADD, roomPtr.deref());
+		}
+	};
+	
+	private final StrRoomCallback roomUpdateCb = new StrRoomCallback() {
+		public void callback(Pointer context, String name, RoomPtr roomPtr) {
+			sendFromNet(MSG_ROOM_UPDATE, Pair.create(name, roomPtr.deref()));
+		}
+	};
+	
+	private final StrCallback roomDeleteCb = new StrCallback() {
+		public void callback(Pointer context, final String name) {
+			sendFromNet(MSG_ROOM_DELETE, name);
+		}
+	};
+	
+	private final RoomListCallback roomlistCb = new RoomListCallback() {
+		public void callback(Pointer context, RoomArrayPtr arg1, int count) {
+			sendFromNet(MSG_ROOMLIST, arg1.getRooms(count));
+		}
+	};
+	
+	private final VoidCallback connectedCb = new VoidCallback() {
+		public void callback(Pointer context) {
+			FLIB.flib_netconn_send_request_roomlist(conn);
+			playerName = FLIB.flib_netconn_get_playername(conn);
+			sendFromNet(MSG_CONNECTED, playerName);
+		}
+	};
+	
+	private final StrCallback passwordRequestCb = new StrCallback() {
+		public void callback(Pointer context, String nickname) {
+			sendFromNet(MSG_PASSWORD_REQUEST, playerName);
+		}
+	};
+	
+	private final BoolCallback enterRoomCb = new BoolCallback() {
+		public void callback(Pointer context, boolean isChief) {
+			sendFromNet(MSG_ENTER_ROOM_FROM_LOBBY, isChief);
+		}
+	};
+	
+	private final IntStrCallback leaveRoomCb = new IntStrCallback() {
+		public void callback(Pointer context, int reason, String message) {
+			sendFromNet(MSG_LEAVE_ROOM, reason, message);
+		}
+	};
+	
+	private final TeamCallback teamAddedCb = new TeamCallback() {
+		public void callback(Pointer context, TeamPtr team) {
+			sendFromNet(MSG_TEAM_ADDED, team.deref());
+		}
+	};
+	
+	private final StrCallback teamDeletedCb = new StrCallback() {
+		public void callback(Pointer context, String teamName) {
+			sendFromNet(MSG_TEAM_DELETED, teamName);
+		}
+	};
+	
+	private final StrCallback teamAcceptedCb = new StrCallback() {
+		public void callback(Pointer context, String teamName) {
+			sendFromNet(MSG_TEAM_ACCEPTED, teamName);
+		}
+	};
+	
+	private final StrIntCallback teamColorChangedCb = new StrIntCallback() {
+		public void callback(Pointer context, String teamName, int colorIndex) {
+			sendFromNet(MSG_TEAM_COLOR_CHANGED, colorIndex, teamName);
+		}
+	};
+	
+	private final StrIntCallback hogCountChangedCb = new StrIntCallback() {
+		public void callback(Pointer context, String teamName, int hogCount) {
+			sendFromNet(MSG_HOG_COUNT_CHANGED, hogCount, teamName);
+		}
+	};
+	
+	private final BytesCallback engineMessageCb = new BytesCallback() {
+		public void callback(Pointer context, ByteArrayPtr buffer, NativeSizeT size) {
+			sendFromNet(MSG_ENGINE_MESSAGE, buffer.deref(size.intValue()));
+		}
+	};
+	
+	private final VoidCallback runGameCb = new VoidCallback() {
+		public void callback(Pointer context) {
+			GameSetupPtr configPtr = FLIB.flib_netconn_create_gamesetup(conn);
+			sendFromNet(MSG_RUN_GAME, configPtr.deref());
+			FLIB.flib_gamesetup_destroy(configPtr);
+		}
+	};
+	
+	private void shutdown(boolean error, String message) {
+		if(conn != null) {
+			FLIB.flib_netconn_destroy(conn);
+			conn = null;
+		}
+		tickHandler.stop();
+		toNetHandler.getLooper().quit();
+		sendFromNet(MSG_DISCONNECTED, Pair.create(error, message));
+	}
+	
+	private final IntStrCallback disconnectCb = new IntStrCallback() {
+		public void callback(Pointer context, int reason, String message) {
+			Boolean error = reason != Frontlib.NETCONN_DISCONNECT_NORMAL;
+			String messageForUser = createDisconnectUserMessage(appContext.getResources(), reason, message);
+			shutdown(error, messageForUser);
+		}
+	};
+	
+	private static String createDisconnectUserMessage(Resources res, int reason, String message) {
+		switch(reason) {
+		case Frontlib.NETCONN_DISCONNECT_AUTH_FAILED:
+			return res.getString(R.string.error_auth_failed);
+		case Frontlib.NETCONN_DISCONNECT_CONNLOST:
+			return res.getString(R.string.error_connection_lost);
+		case Frontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
+			return res.getString(R.string.error_unexpected, message);
+		case Frontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
+			return res.getString(R.string.error_server_too_old);
+		default:
+			return message;
+		}
+	}
+	
+	private boolean sendFromNet(FromNetMsgType what, Object obj) {
+		return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), obj));
+	}
+	
+	private boolean sendFromNet(FromNetMsgType what, int arg1, Object obj) {
+		return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), arg1, 0, obj));
+	}
+	
+	static enum ToNetMsgType {
+		MSG_SEND_NICK,
+		MSG_SEND_PASSWORD,
+		MSG_SEND_QUIT,
+		MSG_SEND_ROOMLIST_REQUEST,
+		MSG_SEND_PLAYER_INFO_REQUEST,
+		MSG_SEND_CHAT,
+		MSG_SEND_TEAMCHAT,
+		MSG_SEND_FOLLOW_PLAYER,
+		MSG_SEND_JOIN_ROOM,
+		MSG_SEND_CREATE_ROOM,
+		MSG_SEND_LEAVE_ROOM,
+		MSG_SEND_KICK,
+		MSG_SEND_ADD_TEAM,
+		MSG_SEND_REMOVE_TEAM,
+		MSG_DISCONNECT,
+		MSG_SEND_TEAM_COLOR_INDEX,
+		MSG_SEND_TEAM_HOG_COUNT,
+		MSG_SEND_ENGINE_MESSAGE,
+		MSG_SEND_ROUND_FINISHED,
+		MSG_SEND_TOGGLE_READY,
+		MSG_SEND_START_GAME,
+		MSG_SEND_WEAPONSET,
+		MSG_SEND_MAP,
+		MSG_SEND_MAP_NAME,
+		MSG_SEND_MAP_GENERATOR,
+		MSG_SEND_MAP_TEMPLATE,
+		MSG_SEND_MAZE_SIZE,
+		MSG_SEND_MAP_SEED,
+		MSG_SEND_MAP_THEME,
+		MSG_SEND_MAP_DRAWDATA,
+		MSG_SEND_GAMESTYLE,
+		MSG_SEND_SCHEME;
+		
+		static final List<ThreadedNetConnection.ToNetMsgType> values = Collections.unmodifiableList(Arrays.asList(ToNetMsgType.values()));
+	}
+	
+	/**
+	 * Processes messages to the networking system. Runs on a non-main thread.
+	 */
+	@SuppressLint("HandlerLeak")
+	public final class ToNetHandler extends Handler {
+		
+		public ToNetHandler(Looper looper) {
+			super(looper);
+		}
+		
+		@Override
+		public void handleMessage(Message msg) {
+			switch(ToNetMsgType.values.get(msg.what)) {
+			case MSG_SEND_NICK: {
+				FLIB.flib_netconn_send_nick(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_PASSWORD: {
+				FLIB.flib_netconn_send_password(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_QUIT: {
+				FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_ROOMLIST_REQUEST: {
+				FLIB.flib_netconn_send_request_roomlist(conn);
+				break;
+			}
+			case MSG_SEND_PLAYER_INFO_REQUEST: {
+				FLIB.flib_netconn_send_playerInfo(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_CHAT: {
+				if(FLIB.flib_netconn_send_chat(conn, (String)msg.obj) == 0) {
+					sendFromNet(MSG_CHAT, Pair.create(playerName, (String)msg.obj));
+				}
+				break;
+			}
+			case MSG_SEND_TEAMCHAT: {
+				FLIB.flib_netconn_send_teamchat(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_FOLLOW_PLAYER: {
+				FLIB.flib_netconn_send_playerFollow(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_JOIN_ROOM: {
+				FLIB.flib_netconn_send_joinRoom(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_CREATE_ROOM: {
+				FLIB.flib_netconn_send_createRoom(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_LEAVE_ROOM: {
+				if(FLIB.flib_netconn_send_leaveRoom(conn, (String)msg.obj) == 0) {
+					sendFromNet(MSG_LEAVE_ROOM, -1, "");
+				}
+				break;
+			}
+			case MSG_SEND_KICK: {
+				FLIB.flib_netconn_send_kick(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_ADD_TEAM: {
+				FLIB.flib_netconn_send_addTeam(conn, TeamPtr.createJavaOwned((TeamInGame)msg.obj));
+				break;
+			}
+			case MSG_SEND_REMOVE_TEAM: {
+				if(FLIB.flib_netconn_send_removeTeam(conn, (String)msg.obj)==0) {
+					sendFromNet(MSG_TEAM_DELETED, msg.obj);
+				}
+				break;
+			}
+			case MSG_DISCONNECT: {
+				FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
+				shutdown(false, "User quit");
+				break;
+			}
+			case MSG_SEND_TEAM_COLOR_INDEX: {
+				FLIB.flib_netconn_send_teamColor(conn, (String)msg.obj, msg.arg1);
+				break;
+			}
+			case MSG_SEND_TEAM_HOG_COUNT: {
+				FLIB.flib_netconn_send_teamHogCount(conn, (String)msg.obj, msg.arg1);
+				break;
+			}
+			case MSG_SEND_ENGINE_MESSAGE: {
+				byte[] message = (byte[])msg.obj;
+				ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(message);
+				FLIB.flib_netconn_send_engineMessage(conn, ptr, NativeSizeT.valueOf(message.length));
+				break;
+			}
+			case MSG_SEND_ROUND_FINISHED: {
+				FLIB.flib_netconn_send_roundfinished(conn, (Boolean)msg.obj);
+				break;
+			}
+			case MSG_SEND_TOGGLE_READY: {
+				FLIB.flib_netconn_send_toggleReady(conn);
+				break;
+			}
+			case MSG_SEND_START_GAME: {
+				FLIB.flib_netconn_send_startGame(conn);
+				break;
+			}
+			case MSG_SEND_WEAPONSET: {
+				FLIB.flib_netconn_send_weaponset(conn, WeaponsetPtr.createJavaOwned((Weaponset)msg.obj));
+				break;
+			}
+			case MSG_SEND_MAP: {
+				FLIB.flib_netconn_send_map(conn, MapRecipePtr.createJavaOwned((MapRecipe)msg.obj));
+				break;
+			}
+			case MSG_SEND_MAP_NAME: {
+				FLIB.flib_netconn_send_mapName(conn, (String)msg.obj);
+				break;
+			}
+			case MSG_SEND_MAP_GENERATOR: {
+				FLIB.flib_netconn_send_mapGen(conn, msg.arg1);
+				break;
+			}
+			case MSG_SEND_MAP_TEMPLATE: {
+				FLIB.flib_netconn_send_mapTemplate(conn, msg.arg1);
+				break;
+			}
+			case MSG_SEND_MAZE_SIZE: {
+				FLIB.flib_netconn_send_mapMazeSize(conn, msg.arg1);
+				break;
+			}
+			case MSG_SEND_MAP_SEED: {
+				FLIB.flib_netconn_send_mapSeed(conn, (String) msg.obj);
+				break;
+			}
+			case MSG_SEND_MAP_THEME: {
+				FLIB.flib_netconn_send_mapTheme(conn, (String) msg.obj);
+				break;
+			}
+			case MSG_SEND_MAP_DRAWDATA: {
+				byte[] message = (byte[])msg.obj;
+				ByteArrayPtr ptr = ByteArrayPtr.createJavaOwned(message);
+				FLIB.flib_netconn_send_mapDrawdata(conn, ptr, NativeSizeT.valueOf(message.length));
+				break;
+			}
+			case MSG_SEND_GAMESTYLE: {
+				FLIB.flib_netconn_send_script(conn, (String) msg.obj);
+				break;
+			}
+			case MSG_SEND_SCHEME: {
+				FLIB.flib_netconn_send_scheme(conn, SchemePtr.createJavaOwned((Scheme) msg.obj));
+				break;
+			}
+			default: {
+				Log.e("ToNetHandler", "Unknown message type: "+msg.what);
+				break;
+			}
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/CalmDownHandler.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,62 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * This class allows you to define a runnable that is called when there has been
+ * no activity for a set amount of time, where activity is determined by calls
+ * to the activity() method of the handler. It is used to update the map preview
+ * when there have been no updates to the relevant map information for a time,
+ * to prevent triggering several updates at once when different parts of the
+ * information change.
+ */
+public final class CalmDownHandler extends Handler {
+	int runningMessagesCounter = 0;
+	final Runnable inactivityRunnable;
+	final long inactivityMs;
+	boolean stopped;
+
+	public CalmDownHandler(Looper looper, Runnable runnable, long inactivityMs) {
+		super(looper);
+		this.inactivityRunnable = runnable;
+		this.inactivityMs = inactivityMs;
+	}
+	
+	public void activity() {
+		runningMessagesCounter++;
+		sendMessageDelayed(obtainMessage(), inactivityMs);
+	}
+	
+	@Override
+	public void handleMessage(Message msg) {
+		runningMessagesCounter--;
+		if(runningMessagesCounter==0 && !stopped) {
+			inactivityRunnable.run();
+		}
+	}
+	
+	public void stop() {
+		stopped = true;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/FileUtils.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,259 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+public class FileUtils {
+	private static final String ROOT_DIR = "Data";
+	private static final String TAG = FileUtils.class.getSimpleName();
+
+	/**
+	 * @return true if the data path is currently available. However, it can vanish at any time so
+	 * normally you should just try to use it and rely on the exceptions.
+	 */
+	public static boolean isDataPathAvailable() {
+		return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
+	}
+	
+	/**
+	 * get the path to which we should download all the data files
+	 * @param c context 
+	 * @return The directory
+	 * @throws FileNotFoundException if external storage is not available at the moment
+	 */
+	public static File getCachePath(Context c) throws FileNotFoundException {
+		File cachePath = null;
+		if(Build.VERSION.SDK_INT < 8){//8 == Build.VERSION_CODES.FROYO
+			cachePath = PreFroyoSDCardDir.getDownloadPath(c);
+		} else {
+			cachePath = FroyoSDCardDir.getDownloadPath(c);
+		}
+		if(cachePath==null) {
+			throw new FileNotFoundException("External storage is currently unavailable");
+		} else {
+			return cachePath;
+		}
+	}
+
+	public static File getDataPathFile(Context c, String...subpath) throws FileNotFoundException {
+		File file = new File(getCachePath(c), ROOT_DIR);
+		for(String pathcomponent : subpath) {
+			file = new File(file, pathcomponent);
+		}
+		return file;
+	}
+	
+	@TargetApi(8)
+	private static class FroyoSDCardDir{
+		public static File getDownloadPath(Context c){
+			return c.getExternalCacheDir();
+		}
+	}
+
+	private static class PreFroyoSDCardDir{
+		public static File getDownloadPath(Context c){
+			if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
+				File extStorageDir = Environment.getExternalStorageDirectory();
+				if(extStorageDir != null) {
+					return new File(extStorageDir, "Hedgewars");
+				}
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * Return a File array with all the files from dirName
+	 * @param c
+	 * @param dirName
+	 * @return
+	 * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dirName" does not exist
+	 */
+	public static File[] getFilesFromRelativeDir(Context c, String dirName) throws FileNotFoundException {
+		File f = getDataPathFile(c, dirName);
+
+		if(f.isDirectory()) {
+			return f.listFiles();
+		} else {
+			throw new FileNotFoundException("Directory "+dirName+" does not exist.");
+		}
+	}
+
+	/**
+	 * Checks if this directory has a file with suffix suffix
+	 * @param f - directory
+	 * @return
+	 */
+	public static boolean hasFileWithSuffix(File f, String suffix){
+		if(f.isDirectory()){
+			for(String s : f.list()){
+				if(s.endsWith(suffix)) return true;
+			}
+			return false;
+		}else{
+			return false;
+		}
+	}
+
+	/**
+	 * Gives back all dirs which contain a file with suffix fileSuffix
+	 * @param c
+	 * @param path
+	 * @param fileSuffix
+	 * @return
+	 * @throws FileNotFoundException If the sdcard is not available or the subdirectory "path" does not exist
+	 */
+	public static List<String> getDirsWithFileSuffix(Context c, String path, String fileSuffix) throws FileNotFoundException{
+		File[] files = getFilesFromRelativeDir(c,path);
+		ArrayList<String> ret = new ArrayList<String>();
+
+		for(File f : files){
+			if(hasFileWithSuffix(f, fileSuffix)) ret.add(f.getName());
+		}
+		return ret;
+	}
+
+	/**
+	 * Get all files from directory dir which have the given suffix
+	 * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dir" does not exist
+	 */
+	public static List<String> getFileNamesFromDirWithSuffix(Context c, String dir, String suffix, boolean removeSuffix) throws FileNotFoundException{
+		File[] files = FileUtils.getFilesFromRelativeDir(c, dir);
+		List<String> ret = new ArrayList<String>();
+		for(File file : files){
+			String s = file.getName();
+			if(s.endsWith(suffix)){
+				if(removeSuffix) ret.add(s.substring(0, s.length()-suffix.length()));
+				else ret.add(s);
+			}
+		}
+		return ret;
+	}
+
+	/**
+	 * Close a resource (possibly null), ignoring any IOException.
+	 */
+	public static void closeQuietly(Closeable c) {
+		if(c!=null) {
+			try {
+				c.close();
+			} catch(IOException e) {
+				Log.w(TAG, e);
+			}
+		}
+	}
+	
+	/**
+	 * Write all data from the input stream to the file, creating or overwriting it.
+	 * The input stream will be closed.
+	 * 
+	 * @throws IOException
+	 */
+	public static void writeStreamToFile(InputStream is, File file) throws IOException {
+		OutputStream os = null;
+		byte[] buffer = new byte[8192];
+		try {
+			os = new FileOutputStream(file);
+			int size;
+			while((size=is.read(buffer)) != -1) {
+				os.write(buffer, 0, size);
+			}
+			os.close(); // Important to close this non-quietly, in case of exceptions when flushing
+		} finally {
+			FileUtils.closeQuietly(is);
+			FileUtils.closeQuietly(os);
+		}
+	}
+	
+	/**
+	 * Moves resources pointed to by sourceResId (from @res/raw/) to the app's private data directory
+	 * @param c
+	 * @param sourceResId
+	 * @param directory
+	 */
+	public static void resRawToFilesDir(Context c, int sourceResId, int targetFilenames, String directory) throws IOException {
+		File targetDir = new File(c.getFilesDir(), directory);
+		targetDir.mkdirs();
+
+		//Get an array with the resource files ID
+		Resources resources = c.getResources();
+		TypedArray ta = resources.obtainTypedArray(sourceResId);
+		TypedArray filenames = resources.obtainTypedArray(targetFilenames);
+		for(int i = 0; i < ta.length(); i++){
+			int resId =  ta.getResourceId(i, 0);
+			String fileName = filenames.getString(i);
+			File f = new File(targetDir, fileName);
+			writeStreamToFile(resources.openRawResource(resId), f);
+		}
+	}
+
+	public static String readToString(InputStream is) throws IOException {
+		try {
+			ByteArrayOutputStream os = new ByteArrayOutputStream();
+			byte[] buffer = new byte[8192];
+			int size;
+			while((size=is.read(buffer)) != -1) {
+				os.write(buffer, 0, size);
+			}
+			return new String(os.toByteArray());
+		} finally {
+			closeQuietly(is);
+		}
+	}
+	
+	private static final char[] badFilenameChars = new char[] { '/', '\\', ':', '*', '?', '\"', '<', '>', '|', '.', '\0' };
+	
+	/**
+	 * Modify the given String so that it can be used as part of a filename
+	 * without causing problems from illegal/special characters.
+	 * 
+	 * The result should be similar to the input, but isn't necessarily
+	 * reversible.
+	 */
+	public static String replaceBadChars(String name) {
+		if (name == null || name.trim().length()==0) {
+			return "_";
+		}
+		name = name.trim();
+		for (char badChar : badFilenameChars) {
+			name = name.replace(badChar, '_');
+		}
+		return name;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObjectUtils.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,32 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+public final class ObjectUtils {
+	public static boolean equal(Object o1, Object o2) {
+		if(o1==o2) {
+			return true;
+		} else if(o1==null || o2 == null) {
+			return false;
+		} else {
+			return o1.equals(o2);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObservableTreeMap.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,62 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import android.database.DataSetObservable;
+
+public class ObservableTreeMap<K,V> extends DataSetObservable {
+	private final Map<K, V> map = new TreeMap<K, V>();
+	
+	public void replaceContent(Map<? extends K, ? extends V> newMap) {
+		map.clear();
+		map.putAll(newMap);
+		notifyChanged();
+	}
+	
+	public void put(K key, V value) {
+		map.put(key, value);
+		notifyChanged();
+	}
+	
+	public V get(K key) {
+		return map.get(key);
+	}
+	
+	public void remove(K key) {
+		if(map.remove(key) != null) {
+			notifyChanged();
+		}
+	}
+	
+	public void clear() {
+		if(!map.isEmpty()) {
+			map.clear();
+			notifyChanged();
+		}
+	}
+	
+	public Map<K, V> getMap() {
+		return Collections.unmodifiableMap(map);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObservableTreeMapAdapter.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,94 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.database.DataSetObserver;
+import android.widget.BaseAdapter;
+
+public abstract class ObservableTreeMapAdapter<K,V> extends BaseAdapter {
+	private boolean sourceChanged = true;
+	private List<V> entries = new ArrayList<V>();
+	private ObservableTreeMap<K, V> source;
+	
+	private DataSetObserver observer = new DataSetObserver() {
+		@Override
+		public void onChanged() {
+			sourceChanged = true;
+			notifyDataSetChanged();
+		}
+		
+		@Override
+		public void onInvalidated() {
+			invalidate();
+		}
+	};
+	
+	abstract protected Comparator<V> getEntryOrder();
+	
+	protected List<V> getEntries() {
+		if(sourceChanged) {
+			entries.clear();
+			entries.addAll(source.getMap().values());
+			Collections.sort(entries, getEntryOrder());
+			sourceChanged = false;
+		}
+		return entries;
+	}
+	
+	public int getCount() {
+		return getEntries().size();
+	}
+
+	public V getItem(int position) {
+		return getEntries().get(position);
+	}
+	
+	public long getItemId(int position) {
+		return position;
+	}
+	
+	@Override
+	public boolean hasStableIds() {
+		return false;
+	}
+	
+	public void setSource(ObservableTreeMap<K,V> source) {
+		if(this.source != null) {
+			this.source.unregisterObserver(observer);
+		}
+		this.source = source;
+		this.source.registerObserver(observer);
+		sourceChanged = true;
+		notifyDataSetChanged();
+	}
+	
+	public void invalidate() {
+		if(source != null) {
+			source.unregisterObserver(observer);
+		}
+		source = null;
+		notifyDataSetInvalidated();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TextInputDialog.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,148 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+/**
+ * A generic text input dialog with configurable text. The Activity must implement the callback
+ * interface TextInputDialogListener, which will be called by the dialog if it is submitted or cancelled.
+ */
+public class TextInputDialog extends DialogFragment {
+	private static final String BUNDLE_DIALOG_ID = "dialogId";
+	private static final String BUNDLE_TITLE_TEXT = "title";
+	private static final String BUNDLE_MESSAGE_TEXT = "message";
+	private static final String BUNDLE_HINT_TEXT = "hint";
+	
+	private int dialogId, titleText, messageText, hintText;
+	private TextInputDialogListener listener;
+	
+	public interface TextInputDialogListener {
+		void onTextInputDialogSubmitted(int dialogId, String text);
+		void onTextInputDialogCancelled(int dialogId);
+	}
+	
+	/**
+	 * The dialogId is only used for passing back to the callback on the activity, the
+	 * other parameters are text resource IDs. Pass 0 for any of them to not use this
+	 * text.
+	 */
+	public TextInputDialog(int dialogId, int titleText, int messageText, int hintText) {
+		this.dialogId = dialogId;
+		this.titleText = titleText;
+		this.messageText = messageText;
+		this.hintText = hintText;
+	}
+	
+	public TextInputDialog() {
+		// Only for reflection-based instantiation by the framework
+	}
+	
+	@Override
+	public void onAttach(Activity activity) {
+		super.onAttach(activity);
+		try {
+			listener = (TextInputDialogListener) activity;
+		} catch(ClassCastException e) {
+			throw new ClassCastException("Activity " + activity + " must implement TextInputDialogListener to use TextInputDialog.");
+		}
+	}
+	
+	@Override
+	public void onDetach() {
+		super.onDetach();
+		listener = null;
+	}
+	
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+		if(savedInstanceState != null) {
+			dialogId = savedInstanceState.getInt(BUNDLE_DIALOG_ID, dialogId);
+			titleText = savedInstanceState.getInt(BUNDLE_TITLE_TEXT, titleText);
+			messageText = savedInstanceState.getInt(BUNDLE_MESSAGE_TEXT, messageText);
+			hintText = savedInstanceState.getInt(BUNDLE_HINT_TEXT, hintText);
+		}
+		
+		final EditText editText = new EditText(getActivity());
+		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+		
+		if(titleText != 0) {
+			builder.setTitle(titleText);
+		}
+		if(messageText != 0) {
+			builder.setTitle(messageText);
+		}
+		if(hintText != 0) {
+			editText.setHint(hintText);
+		}
+		
+		editText.setId(android.R.id.text1);
+		editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
+		editText.setSingleLine();
+
+		builder.setView(editText);
+		builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int which) {
+				dialog.cancel();
+			}
+		});
+		
+		editText.setOnEditorActionListener(new OnEditorActionListener() {
+			public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+				listener.onTextInputDialogSubmitted(dialogId, v.getText().toString());
+				dismiss();
+				return true;
+			}
+		});
+		
+		builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+			public void onClick(DialogInterface dialog, int which) {
+				listener.onTextInputDialogSubmitted(dialogId, editText.getText().toString());
+			}
+		});
+
+		return builder.create();
+	}
+	
+	@Override
+	public void onSaveInstanceState(Bundle icicle) {
+		super.onSaveInstanceState(icicle);
+		icicle.putInt(BUNDLE_DIALOG_ID, dialogId);
+		icicle.putInt(BUNDLE_TITLE_TEXT, titleText);
+		icicle.putInt(BUNDLE_MESSAGE_TEXT, messageText);
+		icicle.putInt(BUNDLE_HINT_TEXT, hintText);
+	}
+	
+	@Override
+	public void onCancel(DialogInterface dialog) {
+		super.onCancel(dialog);
+		listener.onTextInputDialogCancelled(dialogId);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TickHandler.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,73 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * This class handles regularly calling a specified runnable
+ * on the looper provided in the constructor. The first call
+ * occurs without delay (though still via the looper), all
+ * following calls are delayed by (approximately) the interval.
+ * The interval can be changed at any time, which will cause
+ * an immediate execution of the runnable again.
+ */
+public class TickHandler extends Handler {
+	private final Runnable callback;
+	private int messageId;
+	private long interval;
+	private boolean running;
+	
+	public TickHandler(Looper looper, long interval, Runnable callback) {
+		super(looper);
+		this.callback = callback;
+		this.interval = interval;
+	}
+	
+	public synchronized void stop() {
+		messageId++;
+		running = false;
+	}
+	
+	public synchronized void start() {
+		messageId++;
+		sendMessage(obtainMessage(messageId));
+		running = true;
+	}
+	
+	public synchronized void setInterval(long interval) {
+		this.interval = interval;
+		if(running) {
+			start();
+		}
+	}
+	
+	@Override
+	public synchronized void handleMessage(Message msg) {
+		if(msg.what == messageId) {
+			callback.run();
+		}
+		if(msg.what == messageId) {
+			sendMessageDelayed(obtainMessage(messageId), interval);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/UiUtils.java	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,53 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.hedgewars.hedgeroid.util;
+
+import org.hedgewars.hedgeroid.R;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+public final class UiUtils {
+	private UiUtils() {
+		throw new AssertionError("This class is not meant to be instantiated");
+	}
+
+	public static View createVerticalTabIndicator(TabHost tabHost, int label, int icon) {
+		LayoutInflater inflater = (LayoutInflater) tabHost.getContext()
+				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+		View view = inflater.inflate(R.layout.tab_indicator_vertical,
+				tabHost.getTabWidget(), false);
+
+		final TextView tv = (TextView) view.findViewById(R.id.title);
+		tv.setText(label);
+
+		if (icon != 0) {
+			ImageView iconView = (ImageView) view.findViewById(R.id.icon);
+			iconView.setImageResource(icon);
+		}
+
+		return view;
+	}
+}
Binary file project_files/AudioMono/Sounds/voices/Pirate/Firepunch2.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Pirate/Firepunch3.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Pirate/Firepunch4.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Pirate/Firepunch5.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Pirate/Firepunch6.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Robot/Firepunch2.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Robot/Firepunch3.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Robot/Firepunch4.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Robot/Firepunch5.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Robot/Firepunch6.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Singer/Firepunch2.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Singer/Firepunch3.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Singer/Firepunch4.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Singer/Firepunch5.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Singer/Firepunch6.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Surfer/Firepunch2.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Surfer/Firepunch3.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Surfer/Firepunch4.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Surfer/Firepunch5.ogg has changed
Binary file project_files/AudioMono/Sounds/voices/Surfer/Firepunch6.ogg has changed
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m	Sun Nov 18 23:10:26 2012 +0400
@@ -226,6 +226,7 @@
     NSString *seed = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuid);
     CFRelease(uuid);
     NSString *seedCmd = [[NSString alloc] initWithFormat:@"eseed {%@}", seed];
+    [seed release];
 
     // pick a random static map
     NSArray *listOfMaps = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:MAPS_DIRECTORY() error:NULL];
--- a/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj	Sun Nov 18 23:10:26 2012 +0400
@@ -1206,6 +1206,7 @@
 				1D60588D0D05DD3D006BFB54 /* Resources */,
 				1D60588E0D05DD3D006BFB54 /* Sources */,
 				1D60588F0D05DD3D006BFB54 /* Frameworks */,
+				6137A859164732120043D108 /* Update Revision Information */,
 			);
 			buildRules = (
 				9283015B0F10E46D00CC5A3C /* PBXBuildRule */,
@@ -1474,6 +1475,20 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
+		6137A859164732120043D108 /* Update Revision Information */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Update Revision Information";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "HEDGEWARS_REVISION=`/usr/local/bin/hg identify -n ${SOURCE_DIR}|sed -e 's/\\+//'`\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $HEDGEWARS_REVISION\" \"${TARGET_BUILD_DIR}\"/\"${INFOPLIST_PATH}\"";
+		};
 		6179928A114AE0C800BA94A9 /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
--- a/project_files/HedgewarsMobile/Info.plist	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/HedgewarsMobile/Info.plist	Sun Nov 18 23:10:26 2012 +0400
@@ -28,6 +28,8 @@
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
+	<string>${HEDGEWARS_REVISION}</string>
+	<key>CFBundleShortVersionString</key>
 	<string>1.3.2</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/cmdlineClient/cmdlineClient.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,475 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <frontlib.h>
+#include <util/logging.h>
+#include <util/util.h>
+#include <base64/base64.h>
+#include <model/schemelist.h>
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+#include <conio.h>
+#include <windows.h>
+
+#define ENGINE_DIR ".\\"
+#define CONFIG_DIR "..\\share\\hedgewars"
+#define DATA_DIR CONFIG_DIR"\\Data"
+
+static flib_netconn *netconn;
+static flib_gameconn *gameconn;
+static flib_mapconn *mapconn;
+static char nickname[128];
+static flib_metascheme *metacfg;
+static bool netConnected = false;
+
+// Callback function that will be called when the map is rendered
+static void handleMapGenerated(void *context, const uint8_t *bitmap, int numHedgehogs) {
+	printf("Drawing map for %i brave little hogs...", numHedgehogs);
+
+	// Draw the map as ASCII art
+	for(int y=0; y<MAPIMAGE_HEIGHT; y+=8) {
+		for(int x=0; x<MAPIMAGE_WIDTH; x+=6) {
+			int pixelnum = x + y*MAPIMAGE_WIDTH;
+			bool pixel = bitmap[pixelnum>>3] & (1<<(7-(pixelnum&7)));
+			printf(pixel ? "#" : " ");
+		}
+		printf("\n");
+	}
+
+	flib_mapconn_destroy(mapconn);
+	mapconn = NULL;
+}
+
+static void onGameDisconnect(void *context, int reason) {
+	flib_log_i("Connection closed. Reason: %i", reason);
+	flib_gameconn_destroy(gameconn);
+	gameconn = NULL;
+	if(netconn) {
+		flib_netconn_send_roundfinished(netconn, reason==GAME_END_FINISHED);
+	}
+}
+
+// Callback function that will be called on error
+static void handleMapFailure(void *context, const char *errormessage) {
+	flib_log_e("Map rendering failed: %s", errormessage);
+	flib_mapconn_destroy(mapconn);
+	mapconn = NULL;
+}
+
+static void startEngineMap(int port) {
+	char cmdbuffer[255];
+	char argbuffer[255];
+	snprintf(cmdbuffer, 255, "%shwengine.exe", ENGINE_DIR);
+	snprintf(argbuffer, 255, "%s %i landpreview", CONFIG_DIR, port);
+	ShellExecute(NULL, NULL, cmdbuffer, argbuffer, NULL, SW_HIDE);
+}
+
+static void startEngineGame(int port) {
+	char cmdbuffer[255];
+	char argbuffer[255];
+	char base64PlayerName[255];
+	base64_encode(nickname, strlen(nickname), base64PlayerName, sizeof(base64PlayerName));
+	snprintf(cmdbuffer, 255, "%shwengine.exe", ENGINE_DIR);
+	snprintf(argbuffer, 255, "%s 1024 768 32 %i 0 0 0 10 10 %s 0 0 %s 0 0 en.txt", CONFIG_DIR, port, DATA_DIR, base64PlayerName);
+	ShellExecute(NULL, NULL, cmdbuffer, argbuffer, NULL, SW_HIDE);
+}
+
+void handleNetDisconnect(void *context, int reason, const char *message) {
+	printf("Disconnected: %s", message);
+	flib_netconn_destroy(netconn);
+	netconn = NULL;
+}
+
+/*void printRoomList() {
+	const flib_roomlist *roomlist = flib_netconn_get_roomlist(netconn);
+	if(roomlist) {
+		if(roomlist->roomCount>0) {
+			for(int i=0; i<roomlist->roomCount; i++) {
+				if(i>0) {
+					printf(", ");
+				}
+				flib_room *room = roomlist->rooms[i];
+				printf("%s", room->name);
+			}
+		} else {
+			puts("Unfortunately, there are no rooms at the moment.");
+		}
+	} else {
+		puts("Sorry, due to an error the room list is not available.");
+	}
+	puts("\n");
+}*/
+
+void printTeamList() {
+	flib_gamesetup *setup = flib_netconn_create_gamesetup(netconn);
+	if(setup) {
+		puts("The following teams are in this room:");
+		for(int i=0; i<setup->teamlist->teamCount; i++) {
+			if(i>0) {
+				printf(", ");
+			}
+			printf("%s", setup->teamlist->teams[i]->name);
+		}
+		puts("\n");
+	} else {
+		puts("Sorry, due to an error the team list is not available.");
+	}
+	flib_gamesetup_destroy(setup);
+}
+
+void handleNetConnected(void *context) {
+	printf("You enter the lobby of a strange house inhabited by hedgehogs. Looking around, you see hallways branching off to these rooms:\n");
+	//printRoomList();
+	printf("\n\nNow, you can chat by just entering text, or join a room with /join <roomname>.");
+	printf(" You can also /quit or let me /describe <roomname>. Once in a room, you can /add <teamname> and set yourself /ready. You can also /list the available rooms (in the lobby) or the teams (in a room).\n");
+	netConnected = true;
+}
+
+void handleChat(void *context, const char *nick, const char *msg) {
+	if(gameconn) {
+		flib_gameconn_send_chatmsg(gameconn, nick, msg);
+	}
+	printf("%s: %s\n", nick, msg);
+}
+
+void handleEnterRoom(void *context, bool isChief) {
+	puts("You have entered the room.");
+}
+
+void handleRoomJoin(void *context, const char *nick) {
+	if(strcmp(nick, nickname)) {
+		printf("%s is here.\n", nick);
+	}
+}
+
+void handleRoomLeave(void *context, const char *nick, const char *partmsg) {
+	if(strcmp(nick, nickname)) {
+		printf("%s leaves.\n", nick);
+	}
+}
+
+void handleReady(void *context, const char *nick, bool ready) {
+	if(strcmp(nick, nickname)) {
+		if(ready) {
+			printf("%s is ready to go.\n", nick);
+		} else {
+			printf("%s is not ready.\n", nick);
+		}
+	} else {
+		if(ready) {
+			printf("You are ready to go.\n");
+		} else {
+			printf("You are not ready.\n");
+		}
+	}
+}
+
+void handleEmFromNet(void *context, const uint8_t *em, size_t size) {
+	if(gameconn) {
+		flib_gameconn_send_enginemsg(gameconn, em, size);
+	}
+}
+
+void handleEmFromEngine(void *context, const uint8_t *em, size_t size) {
+	if(netconn) {
+		flib_netconn_send_engineMessage(netconn, em, size);
+	}
+}
+
+void handleChatFromGame(void *context, const char *message, bool teamchat) {
+	if(netconn) {
+		if(teamchat) {
+			flib_netconn_send_teamchat(netconn, message);
+		} else {
+			flib_netconn_send_chat(netconn, message);
+		}
+	}
+}
+
+void handleRunGame(void *context) {
+	flib_gamesetup *gamesetup = flib_netconn_create_gamesetup(netconn);
+	if(gameconn) {
+		flib_log_e("Request to start game, but a game is already running.");
+	} else if(gamesetup) {
+		gameconn = flib_gameconn_create(nickname, gamesetup, true);
+		flib_gameconn_onEngineMessage(gameconn, handleEmFromEngine, NULL);
+		flib_gameconn_onDisconnect(gameconn, onGameDisconnect, NULL);
+		flib_gameconn_onChat(gameconn, handleChatFromGame, NULL);
+		startEngineGame(flib_gameconn_getport(gameconn));
+	}
+	flib_gamesetup_destroy(gamesetup);
+}
+
+void handleNickTaken(void *context, const char *nick) {
+	printf("The nickname %s is already in use, please choose a different one:\n", nick);
+	flib_gets(nickname, sizeof(nickname));
+	flib_netconn_send_nick(netconn, nickname);
+}
+
+void handlePwRequest(void *context, const char *nick) {
+	printf("A password is required to log in as %s, please enter (warning: shown in cleartext):\n", nick);
+	char password[256];
+	flib_gets(password, sizeof(password));
+	flib_netconn_send_password(netconn, password);
+}
+
+void handleMessage(void *context, int type, const char *msg) {
+	if(gameconn) {
+		flib_gameconn_send_textmsg(gameconn, 1, msg);
+	}
+	printf("*** %s\n", msg);
+}
+
+void handleTeamAccepted(void *context, const char *teamname) {
+	printf("The team %s has been accepted.\n", teamname);
+}
+
+void handleMapChanged(void *context, const flib_map *map, int changetype) {
+	if(map->mapgen != MAPGEN_NAMED && changetype != NETCONN_MAPCHANGE_THEME) {
+		if(mapconn) {
+			flib_mapconn_destroy(mapconn);
+			mapconn = NULL;
+		}
+		mapconn = flib_mapconn_create(map);
+		if(mapconn) {
+			flib_mapconn_onSuccess(mapconn, handleMapGenerated, NULL);
+			flib_mapconn_onFailure(mapconn, handleMapFailure, NULL);
+			startEngineMap(flib_mapconn_getport(mapconn));
+		}
+	} else if(map->mapgen == MAPGEN_NAMED) {
+		printf("The map %s has been selected.\n", map->name);
+	}
+}
+
+void handleLeaveRoom(void *context, int reason, const char *msg) {
+	if(reason == NETCONN_ROOMLEAVE_ABANDONED) {
+		printf("The chief has abandoned the room.");
+	} else if(reason == NETCONN_ROOMLEAVE_KICKED) {
+		printf("You have been kicked from the room.");
+	}
+	if(msg) {
+		printf(" (%s)", msg);
+	}
+	puts(" You are back in the lobby.");
+}
+
+void handleSchemeChanged(void *context, const flib_scheme *scheme) {
+	printf("Game scheme: %s.\n", scheme->name);
+}
+
+void handleWeaponsetChanged(void *context, const flib_weaponset *weaponset) {
+	printf("Weaponset: %s.\n", weaponset->name);
+}
+
+void handleHogcountChanged(void *context, const char *team, int count) {
+	printf("Team %s will send %i hogs into the fight.\n", team, count);
+}
+
+void handleRoomAdd(void *context, const flib_room *room) {
+	printf("%s created a new room called %s.\n", room->owner, room->name);
+}
+
+void handleRoomDelete(void *context, const char *roomName) {
+	printf("The room %s has collapsed.\n", roomName);
+}
+
+void handleScriptChanged(void *context, const char *script) {
+	printf("Game Type: %s\n", script);
+}
+
+void handleTeamAdd(void *context, const flib_team *team) {
+	printf("%s puts the team %s to the planning board.\n", team->ownerName, team->name);
+}
+
+void handleTeamDelete(void *context, const char *teamName) {
+	printf("The team %s decided not to fight this battle after all.\n", teamName);
+}
+
+void handleTeamColorChanged(void *context, const char *name, int colorIndex) {
+	static const char* colorNames[] = {"red", "blue", "teal", "purple", "pink", "green", "orange", "brown", "yellow"};
+	const char *colorName = "strange";
+	if(colorIndex>=0 && colorIndex < 9) {
+		colorName = colorNames[colorIndex];
+	}
+	printf("The team %s will wear %s uniforms today.\n", name, colorName);
+}
+
+void tick() {
+	if(gameconn) {
+		flib_gameconn_tick(gameconn);
+	}
+	if(netconn) {
+		flib_netconn_tick(netconn);
+	}
+	if(mapconn) {
+		flib_mapconn_tick(mapconn);
+	}
+}
+
+static HANDLE hStdin;
+
+static int init() {
+	hStdin = GetStdHandle(STD_INPUT_HANDLE);
+	if(hStdin == INVALID_HANDLE_VALUE) {
+		flib_log_e("Unable to get stdin handle");
+		return 1;
+	}
+	if(!flib_init(0)) {
+		flib_log_setLevel(FLIB_LOGLEVEL_WARNING);
+		freopen( "CON", "w", stdout );
+		freopen( "CON", "w", stderr );
+		metacfg = flib_metascheme_from_ini("metasettings.ini");
+		if(!metacfg) {
+			flib_quit();
+			return -1;
+		} else {
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int main(int argc, char *argv[]) {
+	if(init()) {
+		return -1;
+	}
+
+	puts("Please enter a nickname:");
+	flib_gets(nickname, sizeof(nickname));
+
+	netconn = flib_netconn_create(nickname, metacfg, DATA_DIR"\\", "140.247.62.101", 46631);
+	if(!netconn) {
+		flib_quit();
+		return -1;
+	}
+
+	flib_netconn_onConnected(netconn, handleNetConnected, NULL);
+	flib_netconn_onDisconnected(netconn, handleNetDisconnect, NULL);
+	flib_netconn_onChat(netconn, handleChat, NULL);
+	flib_netconn_onEnterRoom(netconn, handleEnterRoom, NULL);
+	flib_netconn_onRunGame(netconn, handleRunGame, NULL);
+	flib_netconn_onEngineMessage(netconn, handleEmFromNet, NULL);
+	flib_netconn_onRoomJoin(netconn, handleRoomJoin, NULL);
+	flib_netconn_onRoomLeave(netconn, handleRoomLeave, NULL);
+	flib_netconn_onReadyState(netconn, handleReady, NULL);
+	flib_netconn_onNickTaken(netconn, handleNickTaken, NULL);
+	flib_netconn_onPasswordRequest(netconn, handlePwRequest, NULL);
+	flib_netconn_onMessage(netconn, handleMessage, NULL);
+	flib_netconn_onTeamAccepted(netconn, handleTeamAccepted, NULL);
+	flib_netconn_onMapChanged(netconn, handleMapChanged, NULL);
+	flib_netconn_onLeaveRoom(netconn, handleLeaveRoom, NULL);
+	flib_netconn_onCfgScheme(netconn, handleSchemeChanged, NULL);
+	flib_netconn_onWeaponsetChanged(netconn, handleWeaponsetChanged, NULL);
+	flib_netconn_onHogCountChanged(netconn, handleHogcountChanged, NULL);
+	flib_netconn_onRoomAdd(netconn, handleRoomAdd, NULL);
+	flib_netconn_onRoomDelete(netconn, handleRoomDelete, NULL);
+	flib_netconn_onScriptChanged(netconn, handleScriptChanged, NULL);
+	flib_netconn_onTeamAdd(netconn, handleTeamAdd, NULL);
+	flib_netconn_onTeamDelete(netconn, handleTeamDelete, NULL);
+	flib_netconn_onTeamColorChanged(netconn, handleTeamColorChanged, NULL);
+
+	INPUT_RECORD inputRecord;
+	DWORD eventCount = 0;
+
+	while(netconn || gameconn) {
+		tick();
+		if(netconn && netConnected) {
+			while(PeekConsoleInput(hStdin, &inputRecord, 1, &eventCount) && eventCount>0) {
+				if(inputRecord.EventType != KEY_EVENT) {
+					ReadConsoleInput(hStdin, &inputRecord, 1, &eventCount);
+				} else {
+					printf("%s: ", nickname);
+					char input[256];
+					if(!flib_gets(input, sizeof(input))) {
+						if(!memcmp("/quit", input, strlen("/quit"))) {
+							flib_netconn_send_quit(netconn, "Player quit.");
+						} else if(!memcmp("/describe ", input, strlen("/describe "))) {
+							const char *roomname = input+strlen("/describe ");
+							/*const flib_roomlist *roomlist = flib_netconn_get_roomlist(netconn);
+							flib_room *room = flib_roomlist_find(roomlist, roomname);
+							if(!room) {
+								puts("Unknown room.");
+							} else {
+								char *text = flib_asprintf(
+										"%s is a room created by %s, where %i players (%i teams) are %s on %s%s, using the %s scheme and %s weaponset.",
+										room->name,
+										room->owner,
+										room->playerCount,
+										room->teamCount,
+										room->inProgress ? "fighting" : "preparing to fight",
+										room->map[0]=='+' ? "" : "the map ",
+										!strcmp("+rnd+", room->map) ? "a random map" :
+												!strcmp("+maze+", room->map) ? "a random maze" :
+												!strcmp("+drawn+", room->map) ? "a hand-drawn map" :
+												room->map,
+										room->scheme,
+										room->weapons);
+								if(text) {
+									puts(text);
+								}
+								free(text);
+							}*/
+						} else if(!memcmp("/join ", input, strlen("/join "))) {
+							const char *roomname = input+strlen("/join ");
+							flib_netconn_send_joinRoom(netconn, roomname);
+						} else if(!memcmp("/ready", input, strlen("/ready"))) {
+							flib_netconn_send_toggleReady(netconn);
+						} else if(!memcmp("/loglevel ", input, strlen("/loglevel "))) {
+							int loglevel = atoi(input+strlen("/loglevel "));
+							flib_log_setLevel(loglevel);
+						} else if(!memcmp("/list", input, strlen("/list"))) {
+							if(flib_netconn_is_in_room_context(netconn)) {
+								printTeamList();
+							} else {
+								puts("From this big and expansive lobby, hallways branch off to these rooms:");
+								//printRoomList();
+							}
+						} else if(!memcmp("/addteam ", input, strlen("/addteam "))) {
+							const char *teamname = input+strlen("/addteam ");
+							if(!flib_contains_dir_separator(teamname)) {
+								char *teamfilename = flib_asprintf("%s.hwt", teamname);
+								if(teamfilename) {
+									flib_team *team = flib_team_from_ini(teamfilename);
+									if(team) {
+										flib_netconn_send_addTeam(netconn, team);
+									} else {
+										printf("Teamfile %s not found.\n", teamfilename);
+									}
+									flib_team_destroy(team);
+								}
+								free(teamfilename);
+							}
+						} else if(strlen(input)>0) {
+							flib_netconn_send_chat(netconn, input);
+						}
+					}
+				}
+			}
+		}
+		fflush(stdout);
+		Sleep(10);
+	}
+
+
+	flib_metascheme_release(metacfg);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/Android.mk	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := frontlib
+
+LOCAL_CFLAGS := -I$(LOCAL_PATH)/../Android-build/SDL-android-project/jni/SDL_net -std=c99 -I$(LOCAL_PATH)/../Android-build/SDL-android-project/jni/SDL/include  
+
+LOCAL_SRC_FILES := base64/base64.c iniparser/iniparser.c \
+	iniparser/dictionary.c ipc/gameconn.c ipc/ipcbase.c \
+	ipc/ipcprotocol.c ipc/mapconn.c md5/md5.c model/scheme.c \
+	model/gamesetup.c model/map.c model/mapcfg.c model/room.c \
+	model/schemelist.c model/team.c model/teamlist.c model/weapon.c \
+	net/netbase.c net/netconn_callbacks.c net/netconn_send.c \
+	net/netconn.c net/netprotocol.c util/buffer.c util/inihelper.c \
+	util/logging.c util/util.c frontlib.c hwconsts.c socket.c \
+	extra/jnacontrol.c
+
+LOCAL_SHARED_LIBRARIES += SDL SDL_net
+LOCAL_LDLIBS += -lz
+
+include $(BUILD_SHARED_LIBRARY)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/base64/base64.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,572 @@
+/* base64.c -- Encode binary data using printable characters.
+   Copyright (C) 1999-2001, 2004-2006, 2009-2012 Free Software Foundation, Inc.
+
+   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; either version 2, or (at your option)
+   any later version.
+
+   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, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Simon Josefsson.  Partially adapted from GNU MailUtils
+ * (mailbox/filter_trans.c, as of 2004-11-28).  Improved by review
+ * from Paul Eggert, Bruno Haible, and Stepan Kasal.
+ *
+ * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
+ *
+ * Be careful with error checking.  Here is how you would typically
+ * use these functions:
+ *
+ * bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
+ * if (!ok)
+ *   FAIL: input was not valid base64
+ * if (out == NULL)
+ *   FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN
+ *
+ * size_t outlen = base64_encode_alloc (in, inlen, &out);
+ * if (out == NULL && outlen == 0 && inlen != 0)
+ *   FAIL: input too long
+ * if (out == NULL)
+ *   FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN.
+ *
+ */
+
+/* Get prototype. */
+#include "base64.h"
+
+/* Get malloc. */
+#include <stdlib.h>
+
+/* Get UCHAR_MAX. */
+#include <limits.h>
+
+#include <string.h>
+
+/* C89 compliant way to cast 'char' to 'unsigned char'. */
+static inline unsigned char
+to_uchar (char ch)
+{
+  return ch;
+}
+
+/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
+   If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
+   possible.  If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
+   terminate the output buffer. */
+void
+base64_encode (const char *restrict in, size_t inlen,
+               char *restrict out, size_t outlen)
+{
+  static const char b64str[64] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  while (inlen && outlen)
+    {
+      *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
+      if (!--outlen)
+        break;
+      *out++ = b64str[((to_uchar (in[0]) << 4)
+                       + (--inlen ? to_uchar (in[1]) >> 4 : 0))
+                      & 0x3f];
+      if (!--outlen)
+        break;
+      *out++ =
+        (inlen
+         ? b64str[((to_uchar (in[1]) << 2)
+                   + (--inlen ? to_uchar (in[2]) >> 6 : 0))
+                  & 0x3f]
+         : '=');
+      if (!--outlen)
+        break;
+      *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '=';
+      if (!--outlen)
+        break;
+      if (inlen)
+        inlen--;
+      if (inlen)
+        in += 3;
+    }
+
+  if (outlen)
+    *out = '\0';
+}
+
+/* Allocate a buffer and store zero terminated base64 encoded data
+   from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
+   the length of the encoded data, excluding the terminating zero.  On
+   return, the OUT variable will hold a pointer to newly allocated
+   memory that must be deallocated by the caller.  If output string
+   length would overflow, 0 is returned and OUT is set to NULL.  If
+   memory allocation failed, OUT is set to NULL, and the return value
+   indicates length of the requested memory block, i.e.,
+   BASE64_LENGTH(inlen) + 1. */
+size_t
+base64_encode_alloc (const char *in, size_t inlen, char **out)
+{
+  size_t outlen = 1 + BASE64_LENGTH (inlen);
+
+  /* Check for overflow in outlen computation.
+   *
+   * If there is no overflow, outlen >= inlen.
+   *
+   * If the operation (inlen + 2) overflows then it yields at most +1, so
+   * outlen is 0.
+   *
+   * If the multiplication overflows, we lose at least half of the
+   * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
+   * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
+   * (inlen > 4).
+   */
+  if (inlen > outlen)
+    {
+      *out = NULL;
+      return 0;
+    }
+
+  *out = malloc (outlen);
+  if (!*out)
+    return outlen;
+
+  base64_encode (in, inlen, *out, outlen);
+
+  return outlen - 1;
+}
+
+/* With this approach this file works independent of the charset used
+   (think EBCDIC).  However, it does assume that the characters in the
+   Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255.  POSIX
+   1003.1-2001 require that char and unsigned char are 8-bit
+   quantities, though, taking care of that problem.  But this may be a
+   potential problem on non-POSIX C99 platforms.
+
+   IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
+   as the formal parameter rather than "x".  */
+#define B64(_)                                  \
+  ((_) == 'A' ? 0                               \
+   : (_) == 'B' ? 1                             \
+   : (_) == 'C' ? 2                             \
+   : (_) == 'D' ? 3                             \
+   : (_) == 'E' ? 4                             \
+   : (_) == 'F' ? 5                             \
+   : (_) == 'G' ? 6                             \
+   : (_) == 'H' ? 7                             \
+   : (_) == 'I' ? 8                             \
+   : (_) == 'J' ? 9                             \
+   : (_) == 'K' ? 10                            \
+   : (_) == 'L' ? 11                            \
+   : (_) == 'M' ? 12                            \
+   : (_) == 'N' ? 13                            \
+   : (_) == 'O' ? 14                            \
+   : (_) == 'P' ? 15                            \
+   : (_) == 'Q' ? 16                            \
+   : (_) == 'R' ? 17                            \
+   : (_) == 'S' ? 18                            \
+   : (_) == 'T' ? 19                            \
+   : (_) == 'U' ? 20                            \
+   : (_) == 'V' ? 21                            \
+   : (_) == 'W' ? 22                            \
+   : (_) == 'X' ? 23                            \
+   : (_) == 'Y' ? 24                            \
+   : (_) == 'Z' ? 25                            \
+   : (_) == 'a' ? 26                            \
+   : (_) == 'b' ? 27                            \
+   : (_) == 'c' ? 28                            \
+   : (_) == 'd' ? 29                            \
+   : (_) == 'e' ? 30                            \
+   : (_) == 'f' ? 31                            \
+   : (_) == 'g' ? 32                            \
+   : (_) == 'h' ? 33                            \
+   : (_) == 'i' ? 34                            \
+   : (_) == 'j' ? 35                            \
+   : (_) == 'k' ? 36                            \
+   : (_) == 'l' ? 37                            \
+   : (_) == 'm' ? 38                            \
+   : (_) == 'n' ? 39                            \
+   : (_) == 'o' ? 40                            \
+   : (_) == 'p' ? 41                            \
+   : (_) == 'q' ? 42                            \
+   : (_) == 'r' ? 43                            \
+   : (_) == 's' ? 44                            \
+   : (_) == 't' ? 45                            \
+   : (_) == 'u' ? 46                            \
+   : (_) == 'v' ? 47                            \
+   : (_) == 'w' ? 48                            \
+   : (_) == 'x' ? 49                            \
+   : (_) == 'y' ? 50                            \
+   : (_) == 'z' ? 51                            \
+   : (_) == '0' ? 52                            \
+   : (_) == '1' ? 53                            \
+   : (_) == '2' ? 54                            \
+   : (_) == '3' ? 55                            \
+   : (_) == '4' ? 56                            \
+   : (_) == '5' ? 57                            \
+   : (_) == '6' ? 58                            \
+   : (_) == '7' ? 59                            \
+   : (_) == '8' ? 60                            \
+   : (_) == '9' ? 61                            \
+   : (_) == '+' ? 62                            \
+   : (_) == '/' ? 63                            \
+   : -1)
+
+static const signed char b64[0x100] = {
+  B64 (0), B64 (1), B64 (2), B64 (3),
+  B64 (4), B64 (5), B64 (6), B64 (7),
+  B64 (8), B64 (9), B64 (10), B64 (11),
+  B64 (12), B64 (13), B64 (14), B64 (15),
+  B64 (16), B64 (17), B64 (18), B64 (19),
+  B64 (20), B64 (21), B64 (22), B64 (23),
+  B64 (24), B64 (25), B64 (26), B64 (27),
+  B64 (28), B64 (29), B64 (30), B64 (31),
+  B64 (32), B64 (33), B64 (34), B64 (35),
+  B64 (36), B64 (37), B64 (38), B64 (39),
+  B64 (40), B64 (41), B64 (42), B64 (43),
+  B64 (44), B64 (45), B64 (46), B64 (47),
+  B64 (48), B64 (49), B64 (50), B64 (51),
+  B64 (52), B64 (53), B64 (54), B64 (55),
+  B64 (56), B64 (57), B64 (58), B64 (59),
+  B64 (60), B64 (61), B64 (62), B64 (63),
+  B64 (64), B64 (65), B64 (66), B64 (67),
+  B64 (68), B64 (69), B64 (70), B64 (71),
+  B64 (72), B64 (73), B64 (74), B64 (75),
+  B64 (76), B64 (77), B64 (78), B64 (79),
+  B64 (80), B64 (81), B64 (82), B64 (83),
+  B64 (84), B64 (85), B64 (86), B64 (87),
+  B64 (88), B64 (89), B64 (90), B64 (91),
+  B64 (92), B64 (93), B64 (94), B64 (95),
+  B64 (96), B64 (97), B64 (98), B64 (99),
+  B64 (100), B64 (101), B64 (102), B64 (103),
+  B64 (104), B64 (105), B64 (106), B64 (107),
+  B64 (108), B64 (109), B64 (110), B64 (111),
+  B64 (112), B64 (113), B64 (114), B64 (115),
+  B64 (116), B64 (117), B64 (118), B64 (119),
+  B64 (120), B64 (121), B64 (122), B64 (123),
+  B64 (124), B64 (125), B64 (126), B64 (127),
+  B64 (128), B64 (129), B64 (130), B64 (131),
+  B64 (132), B64 (133), B64 (134), B64 (135),
+  B64 (136), B64 (137), B64 (138), B64 (139),
+  B64 (140), B64 (141), B64 (142), B64 (143),
+  B64 (144), B64 (145), B64 (146), B64 (147),
+  B64 (148), B64 (149), B64 (150), B64 (151),
+  B64 (152), B64 (153), B64 (154), B64 (155),
+  B64 (156), B64 (157), B64 (158), B64 (159),
+  B64 (160), B64 (161), B64 (162), B64 (163),
+  B64 (164), B64 (165), B64 (166), B64 (167),
+  B64 (168), B64 (169), B64 (170), B64 (171),
+  B64 (172), B64 (173), B64 (174), B64 (175),
+  B64 (176), B64 (177), B64 (178), B64 (179),
+  B64 (180), B64 (181), B64 (182), B64 (183),
+  B64 (184), B64 (185), B64 (186), B64 (187),
+  B64 (188), B64 (189), B64 (190), B64 (191),
+  B64 (192), B64 (193), B64 (194), B64 (195),
+  B64 (196), B64 (197), B64 (198), B64 (199),
+  B64 (200), B64 (201), B64 (202), B64 (203),
+  B64 (204), B64 (205), B64 (206), B64 (207),
+  B64 (208), B64 (209), B64 (210), B64 (211),
+  B64 (212), B64 (213), B64 (214), B64 (215),
+  B64 (216), B64 (217), B64 (218), B64 (219),
+  B64 (220), B64 (221), B64 (222), B64 (223),
+  B64 (224), B64 (225), B64 (226), B64 (227),
+  B64 (228), B64 (229), B64 (230), B64 (231),
+  B64 (232), B64 (233), B64 (234), B64 (235),
+  B64 (236), B64 (237), B64 (238), B64 (239),
+  B64 (240), B64 (241), B64 (242), B64 (243),
+  B64 (244), B64 (245), B64 (246), B64 (247),
+  B64 (248), B64 (249), B64 (250), B64 (251),
+  B64 (252), B64 (253), B64 (254), B64 (255)
+};
+
+#if UCHAR_MAX == 255
+# define uchar_in_range(c) true
+#else
+# define uchar_in_range(c) ((c) <= 255)
+#endif
+
+/* Return true if CH is a character from the Base64 alphabet, and
+   false otherwise.  Note that '=' is padding and not considered to be
+   part of the alphabet.  */
+bool
+isbase64 (char ch)
+{
+  return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
+}
+
+/* Initialize decode-context buffer, CTX.  */
+void
+base64_decode_ctx_init (struct base64_decode_context *ctx)
+{
+  ctx->i = 0;
+}
+
+/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
+   none of those four is a newline, then return *IN.  Otherwise, copy up to
+   4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
+   index CTX->i and setting CTX->i to reflect the number of bytes copied,
+   and return CTX->buf.  In either case, advance *IN to point to the byte
+   after the last one processed, and set *N_NON_NEWLINE to the number of
+   verified non-newline bytes accessible through the returned pointer.  */
+static inline char *
+get_4 (struct base64_decode_context *ctx,
+       char const *restrict *in, char const *restrict in_end,
+       size_t *n_non_newline)
+{
+  if (ctx->i == 4)
+    ctx->i = 0;
+
+  if (ctx->i == 0)
+    {
+      char const *t = *in;
+      if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL)
+        {
+          /* This is the common case: no newline.  */
+          *in += 4;
+          *n_non_newline = 4;
+          return (char *) t;
+        }
+    }
+
+  {
+    /* Copy non-newline bytes into BUF.  */
+    char const *p = *in;
+    while (p < in_end)
+      {
+        char c = *p++;
+        if (c != '\n')
+          {
+            ctx->buf[ctx->i++] = c;
+            if (ctx->i == 4)
+              break;
+          }
+      }
+
+    *in = p;
+    *n_non_newline = ctx->i;
+    return ctx->buf;
+  }
+}
+
+#define return_false                            \
+  do                                            \
+    {                                           \
+      *outp = out;                              \
+      return false;                             \
+    }                                           \
+  while (false)
+
+/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
+   into the output buffer, *OUT, of size *OUTLEN bytes.  Return true if
+   decoding is successful, false otherwise.  If *OUTLEN is too small,
+   as many bytes as possible are written to *OUT.  On return, advance
+   *OUT to point to the byte after the last one written, and decrement
+   *OUTLEN to reflect the number of bytes remaining in *OUT.  */
+static inline bool
+decode_4 (char const *restrict in, size_t inlen,
+          char *restrict *outp, size_t *outleft)
+{
+  char *out = *outp;
+  if (inlen < 2)
+    return false;
+
+  if (!isbase64 (in[0]) || !isbase64 (in[1]))
+    return false;
+
+  if (*outleft)
+    {
+      *out++ = ((b64[to_uchar (in[0])] << 2)
+                | (b64[to_uchar (in[1])] >> 4));
+      --*outleft;
+    }
+
+  if (inlen == 2)
+    return_false;
+
+  if (in[2] == '=')
+    {
+      if (inlen != 4)
+        return_false;
+
+      if (in[3] != '=')
+        return_false;
+    }
+  else
+    {
+      if (!isbase64 (in[2]))
+        return_false;
+
+      if (*outleft)
+        {
+          *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
+                    | (b64[to_uchar (in[2])] >> 2));
+          --*outleft;
+        }
+
+      if (inlen == 3)
+        return_false;
+
+      if (in[3] == '=')
+        {
+          if (inlen != 4)
+            return_false;
+        }
+      else
+        {
+          if (!isbase64 (in[3]))
+            return_false;
+
+          if (*outleft)
+            {
+              *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
+                        | b64[to_uchar (in[3])]);
+              --*outleft;
+            }
+        }
+    }
+
+  *outp = out;
+  return true;
+}
+
+/* Decode base64-encoded input array IN of length INLEN to output array
+   OUT that can hold *OUTLEN bytes.  The input data may be interspersed
+   with newlines.  Return true if decoding was successful, i.e. if the
+   input was valid base64 data, false otherwise.  If *OUTLEN is too
+   small, as many bytes as possible will be written to OUT.  On return,
+   *OUTLEN holds the length of decoded bytes in OUT.  Note that as soon
+   as any non-alphabet, non-newline character is encountered, decoding
+   is stopped and false is returned.  If INLEN is zero, then process
+   only whatever data is stored in CTX.
+
+   Initially, CTX must have been initialized via base64_decode_ctx_init.
+   Subsequent calls to this function must reuse whatever state is recorded
+   in that buffer.  It is necessary for when a quadruple of base64 input
+   bytes spans two input buffers.
+
+   If CTX is NULL then newlines are treated as garbage and the input
+   buffer is processed as a unit.  */
+
+bool
+base64_decode_ctx (struct base64_decode_context *ctx,
+                   const char *restrict in, size_t inlen,
+                   char *restrict out, size_t *outlen)
+{
+  size_t outleft = *outlen;
+  bool ignore_newlines = ctx != NULL;
+  bool flush_ctx = false;
+  unsigned int ctx_i = 0;
+
+  if (ignore_newlines)
+    {
+      ctx_i = ctx->i;
+      flush_ctx = inlen == 0;
+    }
+
+
+  while (true)
+    {
+      size_t outleft_save = outleft;
+      if (ctx_i == 0 && !flush_ctx)
+        {
+          while (true)
+            {
+              /* Save a copy of outleft, in case we need to re-parse this
+                 block of four bytes.  */
+              outleft_save = outleft;
+              if (!decode_4 (in, inlen, &out, &outleft))
+                break;
+
+              in += 4;
+              inlen -= 4;
+            }
+        }
+
+      if (inlen == 0 && !flush_ctx)
+        break;
+
+      /* Handle the common case of 72-byte wrapped lines.
+         This also handles any other multiple-of-4-byte wrapping.  */
+      if (inlen && *in == '\n' && ignore_newlines)
+        {
+          ++in;
+          --inlen;
+          continue;
+        }
+
+      /* Restore OUT and OUTLEFT.  */
+      out -= outleft_save - outleft;
+      outleft = outleft_save;
+
+      {
+        char const *in_end = in + inlen;
+        char const *non_nl;
+
+        if (ignore_newlines)
+          non_nl = get_4 (ctx, &in, in_end, &inlen);
+        else
+          non_nl = in;  /* Might have nl in this case. */
+
+        /* If the input is empty or consists solely of newlines (0 non-newlines),
+           then we're done.  Likewise if there are fewer than 4 bytes when not
+           flushing context and not treating newlines as garbage.  */
+        if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines))
+          {
+            inlen = 0;
+            break;
+          }
+        if (!decode_4 (non_nl, inlen, &out, &outleft))
+          break;
+
+        inlen = in_end - in;
+      }
+    }
+
+  *outlen -= outleft;
+
+  return inlen == 0;
+}
+
+/* Allocate an output buffer in *OUT, and decode the base64 encoded
+   data stored in IN of size INLEN to the *OUT buffer.  On return, the
+   size of the decoded data is stored in *OUTLEN.  OUTLEN may be NULL,
+   if the caller is not interested in the decoded length.  *OUT may be
+   NULL to indicate an out of memory error, in which case *OUTLEN
+   contains the size of the memory block needed.  The function returns
+   true on successful decoding and memory allocation errors.  (Use the
+   *OUT and *OUTLEN parameters to differentiate between successful
+   decoding and memory error.)  The function returns false if the
+   input was invalid, in which case *OUT is NULL and *OUTLEN is
+   undefined. */
+bool
+base64_decode_alloc_ctx (struct base64_decode_context *ctx,
+                         const char *in, size_t inlen, char **out,
+                         size_t *outlen)
+{
+  /* This may allocate a few bytes too many, depending on input,
+     but it's not worth the extra CPU time to compute the exact size.
+     The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
+     input ends with "=" and minus another 1 if the input ends with "==".
+     Dividing before multiplying avoids the possibility of overflow.  */
+  size_t needlen = 3 * (inlen / 4) + 3;
+
+  *out = malloc (needlen);
+  if (!*out)
+    return true;
+
+  if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
+    {
+      free (*out);
+      *out = NULL;
+      return false;
+    }
+
+  if (outlen)
+    *outlen = needlen;
+
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/base64/base64.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,60 @@
+/* base64.h -- Encode binary data using printable characters.
+   Copyright (C) 2004-2006, 2009-2012 Free Software Foundation, Inc.
+   Written by Simon Josefsson.
+
+   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; either version 2, or (at your option)
+   any later version.
+
+   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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef BASE64_H
+# define BASE64_H
+
+/* Get size_t. */
+# include <stddef.h>
+
+/* Get bool. */
+# include <stdbool.h>
+
+/* This uses that the expression (n+(k-1))/k means the smallest
+   integer >= n/k, i.e., the ceiling of n/k.  */
+# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
+
+struct base64_decode_context
+{
+  unsigned int i;
+  char buf[4];
+};
+
+extern bool isbase64 (char ch);
+
+extern void base64_encode (const char *restrict in, size_t inlen,
+                           char *restrict out, size_t outlen);
+
+extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
+
+extern void base64_decode_ctx_init (struct base64_decode_context *ctx);
+
+extern bool base64_decode_ctx (struct base64_decode_context *ctx,
+                               const char *restrict in, size_t inlen,
+                               char *restrict out, size_t *outlen);
+
+extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx,
+                                     const char *in, size_t inlen,
+                                     char **out, size_t *outlen);
+
+#define base64_decode(in, inlen, out, outlen) \
+        base64_decode_ctx (NULL, in, inlen, out, outlen)
+
+#define base64_decode_alloc(in, inlen, out, outlen) \
+        base64_decode_alloc_ctx (NULL, in, inlen, out, outlen)
+
+#endif /* BASE64_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/extra/jnacontrol.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,240 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * This file is not directly part of the frontlib and is not required to build it.
+ * However, it is recommended to include it in compilation when building for Android. The purpose of this file
+ * is to ensure consistency between the function signatures of the JNA Java bindings of the Android port and the
+ * frontlib functions.
+ *
+ * This file, in essence, consists only of function declarations. They are duplicates of function declarations
+ * from the frontlib headers that are referenced from JNA bindings. If the signature of one of these functions
+ * changes in the frontlib, it will no longer match the signature in this file, and the compiler will show an error.
+ * If that happens, you need to update the JNA bindings in Hedgeroid to match the new function signature, and then
+ * update this file.
+ *
+ * The reason for all this is that JNA does not actually know the function signatures of the functions it binds,
+ * it derives them from Java method declarations. If those do not match the actual function signatures, you will
+ * only notice when you suddenly get strange (and possibly hard to track down) problems at runtime. This file is
+ * an attempt to detect these problems at compile time instead. Notice that it will NOT detect changes to structs
+ * or constants though, which also require updates to the JNA bindings.
+ */
+
+/*
+ * Before we include the frontlib headers, we define away the const keyword. This is necessary because there is no
+ * distinction between const and non-const types on the JNA side, and we don't want the compiler to complain because
+ * of bad constness.
+ *
+ * This is so evil, but it works...
+ */
+#define const
+
+#include "../frontlib.h"
+
+/*
+ * Now we map the Java types to the corresponding C types...
+ */
+typedef flib_netconn *NetconnPtr;
+typedef flib_gameconn *GameconnPtr;
+typedef flib_mapconn *MapconnPtr;
+typedef flib_metascheme *MetaschemePtr;
+typedef flib_room **RoomArrayPtr;
+typedef flib_weaponset *WeaponsetPtr;
+typedef flib_weaponsetlist *WeaponsetListPtr;
+typedef flib_map *MapRecipePtr;
+typedef flib_scheme *SchemePtr;
+typedef flib_schemelist *SchemelistPtr;
+
+typedef flib_room *RoomPtr;
+typedef flib_team *TeamPtr;
+typedef flib_gamesetup *GameSetupPtr;
+typedef bool boolean;
+typedef size_t NativeSizeT;
+typedef void *Pointer;
+typedef uint8_t *ByteArrayPtr;
+typedef char *String;
+
+/*
+ * Mapping callback types
+ */
+typedef void (*VoidCallback)(Pointer context);
+typedef void (*StrCallback)(Pointer context, String arg1);
+typedef void (*IntCallback)(Pointer context, int arg1);
+typedef void (*IntStrCallback)(Pointer context, int arg1, String arg2);
+typedef void (*StrIntCallback)(Pointer context, String arg1, int arg2);
+typedef void (*StrStrCallback)(Pointer context, String arg1, String arg2);
+typedef void (*StrStrBoolCallback)(Pointer context, String arg1, String arg2, boolean arg3);
+typedef void (*RoomCallback)(Pointer context, RoomPtr arg1);
+typedef void (*RoomListCallback)(Pointer context, RoomArrayPtr arg1, int arg2);
+typedef void (*StrRoomCallback)(Pointer context, String arg1, RoomPtr arg2);
+typedef void (*BoolCallback)(Pointer context, boolean arg1);
+typedef void (*StrBoolCallback)(Pointer context, String arg1, boolean arg2);
+typedef void (*TeamCallback)(Pointer context, TeamPtr arg1);
+typedef void (*BytesCallback)(Pointer context, const uint8_t *buffer, NativeSizeT size);
+typedef void (*BytesBoolCallback)(Pointer context, const uint8_t *buffer, NativeSizeT size, boolean arg3);
+typedef void (*SchemeCallback)(Pointer context, SchemePtr arg1);
+typedef void (*MapIntCallback)(Pointer context, MapRecipePtr arg1, int arg2);
+typedef void (*WeaponsetCallback)(Pointer context, WeaponsetPtr arg1);
+typedef void (*MapimageCallback)(Pointer context, const uint8_t *mapimage, int hogs);
+typedef void (*LogCallback)(int arg1, String arg2);
+
+/*
+ * Below here are the copypasted method declarations from the JNA bindings
+ */
+
+	// frontlib.h
+    int flib_init();
+    void flib_quit();
+
+    // hwconsts.h
+    int flib_get_teamcolor_count();
+    int flib_get_hedgehogs_per_team();
+    int flib_get_weapons_count();
+	MetaschemePtr flib_get_metascheme();
+
+    // net/netconn.h
+	NetconnPtr flib_netconn_create(String playerName, String dataDirPath, String host, int port);
+	void flib_netconn_destroy(NetconnPtr conn);
+
+	void flib_netconn_tick(NetconnPtr conn);
+	boolean flib_netconn_is_chief(NetconnPtr conn);
+	String flib_netconn_get_playername(NetconnPtr conn);
+	GameSetupPtr flib_netconn_create_gamesetup(NetconnPtr conn);
+	int flib_netconn_send_quit(NetconnPtr conn, String quitmsg);
+	int flib_netconn_send_chat(NetconnPtr conn, String chat);
+	int flib_netconn_send_teamchat(NetconnPtr conn, String msg);
+	int flib_netconn_send_password(NetconnPtr conn, String passwd);
+	int flib_netconn_send_nick(NetconnPtr conn, String nick);
+	int flib_netconn_send_request_roomlist(NetconnPtr conn);
+	int flib_netconn_send_joinRoom(NetconnPtr conn, String room);
+	int flib_netconn_send_createRoom(NetconnPtr conn, String room);
+	int flib_netconn_send_renameRoom(NetconnPtr conn, String roomName);
+	int flib_netconn_send_leaveRoom(NetconnPtr conn, String msg);
+	int flib_netconn_send_toggleReady(NetconnPtr conn);
+	int flib_netconn_send_addTeam(NetconnPtr conn, TeamPtr team);
+	int flib_netconn_send_removeTeam(NetconnPtr conn, String teamname);
+	int flib_netconn_send_engineMessage(NetconnPtr conn, ByteArrayPtr message, NativeSizeT size);
+	int flib_netconn_send_teamHogCount(NetconnPtr conn, String teamname, int hogcount);
+	int flib_netconn_send_teamColor(NetconnPtr conn, String teamname, int colorIndex);
+	int flib_netconn_send_weaponset(NetconnPtr conn, WeaponsetPtr weaponset);
+	int flib_netconn_send_map(NetconnPtr conn, MapRecipePtr map);
+	int flib_netconn_send_mapName(NetconnPtr conn, String mapName);
+	int flib_netconn_send_mapGen(NetconnPtr conn, int mapGen);
+	int flib_netconn_send_mapTemplate(NetconnPtr conn, int templateFilter);
+	int flib_netconn_send_mapMazeSize(NetconnPtr conn, int mazeSize);
+	int flib_netconn_send_mapSeed(NetconnPtr conn, String seed);
+	int flib_netconn_send_mapTheme(NetconnPtr conn, String theme);
+	int flib_netconn_send_mapDrawdata(NetconnPtr conn, ByteArrayPtr drawData, NativeSizeT size);
+	int flib_netconn_send_script(NetconnPtr conn, String scriptName);
+	int flib_netconn_send_scheme(NetconnPtr conn, SchemePtr scheme);
+	int flib_netconn_send_roundfinished(NetconnPtr conn, boolean withoutError);
+	int flib_netconn_send_ban(NetconnPtr conn, String playerName);
+	int flib_netconn_send_kick(NetconnPtr conn, String playerName);
+	int flib_netconn_send_playerInfo(NetconnPtr conn, String playerName);
+	int flib_netconn_send_playerFollow(NetconnPtr conn, String playerName);
+	int flib_netconn_send_startGame(NetconnPtr conn);
+	int flib_netconn_send_toggleRestrictJoins(NetconnPtr conn);
+	int flib_netconn_send_toggleRestrictTeams(NetconnPtr conn);
+	int flib_netconn_send_clearAccountsCache(NetconnPtr conn);
+	int flib_netconn_send_setServerVar(NetconnPtr conn, String name, String value);
+	int flib_netconn_send_getServerVars(NetconnPtr conn);
+
+	void flib_netconn_onMessage(NetconnPtr conn, IntStrCallback callback, Pointer context);
+	void flib_netconn_onClientFlags(NetconnPtr conn, StrStrBoolCallback callback, Pointer context);
+	void flib_netconn_onChat(NetconnPtr conn, StrStrCallback callback, Pointer context);
+	void flib_netconn_onConnected(NetconnPtr conn, VoidCallback callback, Pointer context);
+	void flib_netconn_onDisconnected(NetconnPtr conn, IntStrCallback callback, Pointer context);
+	void flib_netconn_onRoomlist(NetconnPtr conn, RoomListCallback callback, Pointer context);
+	void flib_netconn_onRoomAdd(NetconnPtr conn, RoomCallback callback, Pointer context);
+	void flib_netconn_onRoomDelete(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onRoomUpdate(NetconnPtr conn, StrRoomCallback callback, Pointer context);
+	void flib_netconn_onLobbyJoin(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onLobbyLeave(NetconnPtr conn, StrStrCallback callback, Pointer context);
+	void flib_netconn_onNickTaken(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onPasswordRequest(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onEnterRoom(NetconnPtr conn, BoolCallback callback, Pointer context);
+	void flib_netconn_onLeaveRoom(NetconnPtr conn, IntStrCallback callback, Pointer context);
+	void flib_netconn_onTeamAdd(NetconnPtr conn, TeamCallback callback, Pointer context);
+	void flib_netconn_onTeamDelete(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onRoomJoin(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onRoomLeave(NetconnPtr conn, StrStrCallback callback, Pointer context);
+	void flib_netconn_onRunGame(NetconnPtr conn, VoidCallback callback, Pointer context);
+	void flib_netconn_onTeamAccepted(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onHogCountChanged(NetconnPtr conn, StrIntCallback callback, Pointer context);
+	void flib_netconn_onTeamColorChanged(NetconnPtr conn, StrIntCallback callback, Pointer context);
+	void flib_netconn_onEngineMessage(NetconnPtr conn, BytesCallback callback, Pointer context);
+	void flib_netconn_onSchemeChanged(NetconnPtr conn, SchemeCallback callback, Pointer context);
+	void flib_netconn_onMapChanged(NetconnPtr conn, MapIntCallback callback, Pointer context);
+	void flib_netconn_onScriptChanged(NetconnPtr conn, StrCallback callback, Pointer context);
+	void flib_netconn_onWeaponsetChanged(NetconnPtr conn, WeaponsetCallback callback, Pointer context);
+	void flib_netconn_onServerVar(NetconnPtr conn, StrStrCallback callback, Pointer context);
+
+	// ipc/gameconn.h
+
+	GameconnPtr flib_gameconn_create(String playerName, GameSetupPtr setup, boolean netgame);
+	GameconnPtr flib_gameconn_create_playdemo(ByteArrayPtr demo, NativeSizeT size);
+	GameconnPtr flib_gameconn_create_loadgame(String playerName, ByteArrayPtr save, NativeSizeT size);
+	GameconnPtr flib_gameconn_create_campaign(String playerName, String seed, String script);
+
+	void flib_gameconn_destroy(GameconnPtr conn);
+	int flib_gameconn_getport(GameconnPtr conn);
+	void flib_gameconn_tick(GameconnPtr conn);
+
+	int flib_gameconn_send_enginemsg(GameconnPtr conn, ByteArrayPtr data, NativeSizeT len);
+	int flib_gameconn_send_textmsg(GameconnPtr conn, int msgtype, String msg);
+	int flib_gameconn_send_chatmsg(GameconnPtr conn, String playername, String msg);
+	int flib_gameconn_send_quit(GameconnPtr conn);
+	int flib_gameconn_send_cmd(GameconnPtr conn, String cmdString);
+
+	void flib_gameconn_onConnect(GameconnPtr conn, VoidCallback callback, Pointer context);
+	void flib_gameconn_onDisconnect(GameconnPtr conn, IntCallback callback, Pointer context);
+	void flib_gameconn_onErrorMessage(GameconnPtr conn, StrCallback callback, Pointer context);
+	void flib_gameconn_onChat(GameconnPtr conn, StrBoolCallback callback, Pointer context);
+	void flib_gameconn_onGameRecorded(GameconnPtr conn, BytesBoolCallback callback, Pointer context);
+	void flib_gameconn_onEngineMessage(GameconnPtr conn, BytesCallback callback, Pointer context);
+
+	// ipc/mapconn.h
+	MapconnPtr flib_mapconn_create(MapRecipePtr mapdesc);
+	void flib_mapconn_destroy(MapconnPtr conn);
+	int flib_mapconn_getport(MapconnPtr conn);
+	void flib_mapconn_onSuccess(MapconnPtr conn, MapimageCallback callback, Pointer context);
+	void flib_mapconn_onFailure(MapconnPtr conn, StrCallback callback, Pointer context);
+	void flib_mapconn_tick(MapconnPtr conn);
+
+	// model/schemelist.h
+	SchemelistPtr flib_schemelist_from_ini(String filename);
+	int flib_schemelist_to_ini(String filename, SchemelistPtr list);
+	void flib_schemelist_destroy(SchemelistPtr list);
+
+	// model/team.h
+	TeamPtr flib_team_from_ini(String filename);
+	int flib_team_to_ini(String filename, TeamPtr team);
+	void flib_team_destroy(TeamPtr team);
+
+	// model/weapon.h
+	WeaponsetListPtr flib_weaponsetlist_from_ini(String filename);
+	int flib_weaponsetlist_to_ini(String filename, WeaponsetListPtr weaponsets);
+	void flib_weaponsetlist_destroy(WeaponsetListPtr list);
+
+	// model/gamesetup.h
+	void flib_gamesetup_destroy(GameSetupPtr gamesetup);
+
+	// util/logging.h
+    void flib_log_setLevel(int level);
+    void flib_log_setCallback(LogCallback callback);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/frontlib.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,37 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "frontlib.h"
+#include "util/logging.h"
+#include <SDL_net.h>
+
+int flib_init() {
+	flib_log_d("Initializing frontlib");
+	if(SDLNet_Init()==-1) {
+		flib_log_e("Error in SDLNet_Init: %s", SDLNet_GetError());
+		return -1;
+	}
+
+	return 0;
+}
+
+void flib_quit() {
+	flib_log_d("Shutting down frontlib");
+	SDLNet_Quit();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/frontlib.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,48 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * Public header file for the hedgewars frontent networking library.
+ *
+ * This is the only header you should need to include from frontend code.
+ */
+
+#ifndef FRONTLIB_H_
+#define FRONTLIB_H_
+
+#include "ipc/gameconn.h"
+#include "ipc/mapconn.h"
+#include "net/netconn.h"
+#include "util/logging.h"
+#include "model/schemelist.h"
+
+/**
+ * Call this function before anything else in this library.
+ * Returns 0 on success, -1 on error.
+ */
+int flib_init();
+
+/**
+ * Free resources associated with the library. Call this function once
+ * the library is no longer needed. You can re-initialize the library by calling
+ * flib_init again.
+ */
+void flib_quit();
+
+#endif /* FRONTLIB_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/hwconsts.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,100 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "hwconsts.h"
+
+const uint32_t flib_teamcolors[] = HW_TEAMCOLOR_ARRAY;
+const size_t flib_teamcolor_count = sizeof(flib_teamcolors)/sizeof(uint32_t)-1;
+
+static const flib_metascheme_setting metaSchemeSettings[] = {
+	{ .name = "damagefactor",      .times1000 = false, .engineCommand = "e$damagepct",   .maxMeansInfinity = false, .min = 10, .max = 300,  .def = 100 },
+	{ .name = "turntime",          .times1000 = true,  .engineCommand = "e$turntime",    .maxMeansInfinity = true,  .min = 1,  .max = 9999, .def = 45  },
+	{ .name = "health",            .times1000 = false, .engineCommand = NULL,            .maxMeansInfinity = false, .min = 50, .max = 200,  .def = 100 },
+	{ .name = "suddendeath",       .times1000 = false, .engineCommand = "e$sd_turns",    .maxMeansInfinity = true,  .min = 0,  .max = 50,   .def = 15  },
+	{ .name = "caseprobability",   .times1000 = false, .engineCommand = "e$casefreq",    .maxMeansInfinity = false, .min = 0,  .max = 9,    .def = 5   },
+	{ .name = "minestime",         .times1000 = true,  .engineCommand = "e$minestime",   .maxMeansInfinity = false, .min = -1, .max = 5,    .def = 3   },
+	{ .name = "minesnum",          .times1000 = false, .engineCommand = "e$minesnum",    .maxMeansInfinity = false, .min = 0,  .max = 80,   .def = 4   },
+	{ .name = "minedudpct",        .times1000 = false, .engineCommand = "e$minedudpct",  .maxMeansInfinity = false, .min = 0,  .max = 100,  .def = 0   },
+	{ .name = "explosives",        .times1000 = false, .engineCommand = "e$explosives",  .maxMeansInfinity = false, .min = 0,  .max = 40,   .def = 2   },
+	{ .name = "healthprobability", .times1000 = false, .engineCommand = "e$healthprob",  .maxMeansInfinity = false, .min = 0,  .max = 100,  .def = 35  },
+	{ .name = "healthcaseamount",  .times1000 = false, .engineCommand = "e$hcaseamount", .maxMeansInfinity = false, .min = 0,  .max = 200,  .def = 25  },
+	{ .name = "waterrise",         .times1000 = false, .engineCommand = "e$waterrise",   .maxMeansInfinity = false, .min = 0,  .max = 100,  .def = 47  },
+	{ .name = "healthdecrease",    .times1000 = false, .engineCommand = "e$healthdec",   .maxMeansInfinity = false, .min = 0,  .max = 100,  .def = 5   },
+	{ .name = "ropepct",           .times1000 = false, .engineCommand = "e$ropepct",     .maxMeansInfinity = false, .min = 25, .max = 999,  .def = 100 },
+	{ .name = "getawaytime",       .times1000 = false, .engineCommand = "e$getawaytime", .maxMeansInfinity = false, .min = 0,  .max = 999,  .def = 100 }
+};
+
+static const flib_metascheme_mod metaSchemeMods[] = {
+	{ .name = "fortsmode",          .bitmaskIndex = 12 },
+	{ .name = "divteams",           .bitmaskIndex = 4  },
+	{ .name = "solidland",          .bitmaskIndex = 2  },
+	{ .name = "border",             .bitmaskIndex = 3  },
+	{ .name = "lowgrav",            .bitmaskIndex = 5  },
+	{ .name = "laser",              .bitmaskIndex = 6  },
+	{ .name = "invulnerability",    .bitmaskIndex = 7  },
+	{ .name = "resethealth",        .bitmaskIndex = 8  },
+	{ .name = "vampiric",           .bitmaskIndex = 9  },
+	{ .name = "karma",              .bitmaskIndex = 10 },
+	{ .name = "artillery",          .bitmaskIndex = 11 },
+	{ .name = "randomorder",        .bitmaskIndex = 13 },
+	{ .name = "king",               .bitmaskIndex = 14 },
+	{ .name = "placehog",           .bitmaskIndex = 15 },
+	{ .name = "sharedammo",         .bitmaskIndex = 16 },
+	{ .name = "disablegirders",     .bitmaskIndex = 17 },
+	{ .name = "disablelandobjects", .bitmaskIndex = 18 },
+	{ .name = "aisurvival",         .bitmaskIndex = 19 },
+	{ .name = "infattack",          .bitmaskIndex = 20 },
+	{ .name = "resetweps",          .bitmaskIndex = 21 },
+	{ .name = "perhogammo",         .bitmaskIndex = 22 },
+	{ .name = "disablewind",        .bitmaskIndex = 23 },
+	{ .name = "morewind",           .bitmaskIndex = 24 },
+	{ .name = "tagteam",            .bitmaskIndex = 25 },
+	{ .name = "bottomborder",       .bitmaskIndex = 26 }
+};
+
+const flib_metascheme flib_meta = {
+	.settingCount = sizeof(metaSchemeSettings)/sizeof(flib_metascheme_setting),
+	.modCount = sizeof(metaSchemeMods)/sizeof(flib_metascheme_mod),
+	.settings = metaSchemeSettings,
+	.mods = metaSchemeMods
+};
+
+uint32_t flib_get_teamcolor(int colorIndex) {
+	if(colorIndex>=0 && colorIndex < flib_teamcolor_count) {
+		return flib_teamcolors[colorIndex];
+	} else {
+		return 0;
+	}
+}
+
+int flib_get_teamcolor_count() {
+	return flib_teamcolor_count;
+}
+
+int flib_get_hedgehogs_per_team() {
+	return HEDGEHOGS_PER_TEAM;
+}
+
+int flib_get_weapons_count() {
+	return WEAPONS_COUNT;
+}
+
+const flib_metascheme *flib_get_metascheme() {
+	return &flib_meta;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/hwconsts.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,118 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2012 Simeon Maxein <smaxein@googlemail.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
+ */
+
+/**
+ * This file contains important constants which might need to be changed to adapt to
+ * changes in the engine or protocols.
+ *
+ * It also contains getter functions for some constants (in particular for constants
+ * that are important for the layout of data structures), so that client code can
+ * query the constants that the library was built with.
+ */
+
+#ifndef HWCONSTS_H_
+#define HWCONSTS_H_
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#define HEDGEHOGS_PER_TEAM 8
+#define DEFAULT_HEDGEHOG_COUNT 4
+#define DEFAULT_COLOR_INDEX 0
+
+#define NETGAME_DEFAULT_PORT 46631
+#define PROTOCOL_VERSION 42
+#define MIN_SERVER_VERSION 1
+
+// Used for sending scripts to the engine
+#define MULTIPLAYER_SCRIPT_PATH "Scripts/Multiplayer/"
+
+#define WEAPONS_COUNT 55
+
+// TODO allow frontend to override these?
+/* A merge of mikade/bugq colours w/ a bit of channel feedback */
+#define HW_TEAMCOLOR_ARRAY  { UINT32_C(0xffff0204), /* red    */ \
+                              UINT32_C(0xff4980c1), /* blue   */ \
+                              UINT32_C(0xff1de6ba), /* teal   */ \
+                              UINT32_C(0xffb541ef), /* purple */ \
+                              UINT32_C(0xffe55bb0), /* pink   */ \
+                              UINT32_C(0xff20bf00), /* green  */ \
+                              UINT32_C(0xfffe8b0e), /* orange */ \
+                              UINT32_C(0xff5f3605), /* brown  */ \
+                              UINT32_C(0xffffff01), /* yellow */ \
+                              /* add new colors here */ \
+                              0 } /* Keep this 0 at the end */
+
+extern const size_t flib_teamcolor_count;
+extern const uint32_t flib_teamcolors[];
+
+/**
+ * Returns the team color (ARGB) corresponding to the color index (0 if index out of bounds)
+ */
+uint32_t flib_get_teamcolor(int colorIndex);
+
+/**
+ * Returns the number of team colors (i.e. the length of the flib_teamcolors array)
+ */
+int flib_get_teamcolor_count();
+
+/**
+ * Returns the HEDGEHOGS_PER_TEAM constant
+ */
+int flib_get_hedgehogs_per_team();
+
+/**
+ * Returns the WEAPONS_COUNT constant
+ */
+int flib_get_weapons_count();
+
+/*
+ * These structs define the meaning of values in the flib_scheme struct, i.e. their correspondence to
+ * ini settings, engine commands and positions in the network protocol (the last is encoded in the
+ * order of settings/mods).
+ */
+typedef struct {
+    const char *name;				// A name identifying this setting (used as key in the schemes file)
+    const char *engineCommand;		// The command needed to send the setting to the engine. May be null if the setting is not sent to the engine (for the "health" setting)
+    const bool maxMeansInfinity;	// If true, send a very high number to the engine if the setting is equal to its maximum
+    const bool times1000;			// If true (for time-based settings), multiply the setting by 1000 before sending it to the engine.
+    const int min;					// The smallest allowed value
+    const int max;					// The highest allowed value
+    const int def;					// The default value
+} flib_metascheme_setting;
+
+typedef struct {
+    const char *name;				// A name identifying this mod (used as key in the schemes file)
+    const int bitmaskIndex;			// Mods are sent to the engine in a single integer, this field describes which bit of that integer is used
+    								// for this particular mod.
+} flib_metascheme_mod;
+
+typedef struct {
+	const int settingCount;
+	const int modCount;
+	const flib_metascheme_setting *settings;
+	const flib_metascheme_mod *mods;
+} flib_metascheme;
+
+extern const flib_metascheme flib_meta;
+
+const flib_metascheme *flib_get_metascheme();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/iniparser/LICENSE	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,23 @@
+Copyright (c) 2000-2012 by Nicolas Devillard.
+MIT License
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/iniparser/VERSION	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,2 @@
+This is version 3.1 of the iniparser library developed by N. Devillard.
+See http://ndevilla.free.fr/iniparser/ for details and new versions.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/iniparser/dictionary.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,398 @@
+/*-------------------------------------------------------------------------*/
+/**
+   @file    dictionary.c
+   @author  N. Devillard
+   @brief   Implements a dictionary for string variables.
+
+   This module implements a simple dictionary object, i.e. a list
+   of string/string associations. This object is useful to store e.g.
+   informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+                                Includes
+ ---------------------------------------------------------------------------*/
+#include "dictionary.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/** Maximum value size for integers and doubles. */
+#define MAXVALSZ    1024
+
+/** Minimal allocated number of entries in a dictionary */
+#define DICTMINSZ   128
+
+/** Invalid key token */
+#define DICT_INVALID_KEY    ((char*)-1)
+
+/*---------------------------------------------------------------------------
+                            Private functions
+ ---------------------------------------------------------------------------*/
+
+/* Doubles the allocated size associated to a pointer */
+/* 'size' is the current allocated size. */
+static void * mem_double(void * ptr, int size)
+{
+    void * newptr ;
+ 
+    newptr = calloc(2*size, 1);
+    if (newptr==NULL) {
+        return NULL ;
+    }
+    memcpy(newptr, ptr, size);
+    free(ptr);
+    return newptr ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Duplicate a string
+  @param    s String to duplicate
+  @return   Pointer to a newly allocated string, to be freed with free()
+
+  This is a replacement for strdup(). This implementation is provided
+  for systems that do not have it.
+ */
+/*--------------------------------------------------------------------------*/
+static char * xstrdup(const char * s)
+{
+    char * t ;
+    if (!s)
+        return NULL ;
+    t = (char*)malloc(strlen(s)+1) ;
+    if (t) {
+        strcpy(t,s);
+    }
+    return t ;
+}
+
+/*---------------------------------------------------------------------------
+                            Function codes
+ ---------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Compute the hash key for a string.
+  @param    key     Character string to use for key.
+  @return   1 unsigned int on at least 32 bits.
+
+  This hash function has been taken from an Article in Dr Dobbs Journal.
+  This is normally a collision-free function, distributing keys evenly.
+  The key is stored anyway in the struct so that collision can be avoided
+  by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(const char * key)
+{
+    int         len ;
+    unsigned    hash ;
+    int         i ;
+
+    len = strlen(key);
+    for (hash=0, i=0 ; i<len ; i++) {
+        hash += (unsigned)key[i] ;
+        hash += (hash<<10);
+        hash ^= (hash>>6) ;
+    }
+    hash += (hash <<3);
+    hash ^= (hash >>11);
+    hash += (hash <<15);
+    return hash ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Create a new dictionary object.
+  @param    size    Optional initial size of the dictionary.
+  @return   1 newly allocated dictionary objet.
+
+  This function allocates a new dictionary object of given size and returns
+  it. If you do not know in advance (roughly) the number of entries in the
+  dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size)
+{
+    dictionary  *   d ;
+
+    /* If no size was specified, allocate space for DICTMINSZ */
+    if (size<DICTMINSZ) size=DICTMINSZ ;
+
+    if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
+        return NULL;
+    }
+    d->size = size ;
+    d->val  = (char **)calloc(size, sizeof(char*));
+    d->key  = (char **)calloc(size, sizeof(char*));
+    d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
+    return d ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a dictionary object
+  @param    d   dictionary object to deallocate.
+  @return   void
+
+  Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * d)
+{
+    int     i ;
+
+    if (d==NULL) return ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]!=NULL)
+            free(d->key[i]);
+        if (d->val[i]!=NULL)
+            free(d->val[i]);
+    }
+    free(d->val);
+    free(d->key);
+    free(d->hash);
+    free(d);
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get a value from a dictionary.
+  @param    d       dictionary object to search.
+  @param    key     Key to look for in the dictionary.
+  @param    def     Default value to return if key not found.
+  @return   1 pointer to internally allocated character string.
+
+  This function locates a key in a dictionary and returns a pointer to its
+  value, or the passed 'def' pointer if no such key can be found in
+  dictionary. The returned character pointer points to data internal to the
+  dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, const char * key, char * def)
+{
+    unsigned    hash ;
+    int         i ;
+
+    hash = dictionary_hash(key);
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        /* Compare hash */
+        if (hash==d->hash[i]) {
+            /* Compare string, to avoid hash collisions */
+            if (!strcmp(key, d->key[i])) {
+                return d->val[i] ;
+            }
+        }
+    }
+    return def ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set a value in a dictionary.
+  @param    d       dictionary object to modify.
+  @param    key     Key to modify or add.
+  @param    val     Value to add.
+  @return   int     0 if Ok, anything else otherwise
+
+  If the given key is found in the dictionary, the associated value is
+  replaced by the provided one. If the key cannot be found in the
+  dictionary, it is added to it.
+
+  It is Ok to provide a NULL value for val, but NULL values for the dictionary
+  or the key are considered as errors: the function will return immediately
+  in such a case.
+
+  Notice that if you dictionary_set a variable to NULL, a call to
+  dictionary_get will return a NULL value: the variable will be found, and
+  its value (NULL) is returned. In other words, setting the variable
+  content to NULL is equivalent to deleting the variable from the
+  dictionary. It is not possible (in this implementation) to have a key in
+  the dictionary without value.
+
+  This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * d, const char * key, const char * val)
+{
+    int         i ;
+    unsigned    hash ;
+
+    if (d==NULL || key==NULL) return -1 ;
+    
+    /* Compute hash for this key */
+    hash = dictionary_hash(key) ;
+    /* Find if value is already in dictionary */
+    if (d->n>0) {
+        for (i=0 ; i<d->size ; i++) {
+            if (d->key[i]==NULL)
+                continue ;
+            if (hash==d->hash[i]) { /* Same hash value */
+                if (!strcmp(key, d->key[i])) {   /* Same key */
+                    /* Found a value: modify and return */
+                    if (d->val[i]!=NULL)
+                        free(d->val[i]);
+                    d->val[i] = val ? xstrdup(val) : NULL ;
+                    /* Value has been modified: return */
+                    return 0 ;
+                }
+            }
+        }
+    }
+    /* Add a new value */
+    /* See if dictionary needs to grow */
+    if (d->n==d->size) {
+
+        /* Reached maximum size: reallocate dictionary */
+        d->val  = (char **)mem_double(d->val,  d->size * sizeof(char*)) ;
+        d->key  = (char **)mem_double(d->key,  d->size * sizeof(char*)) ;
+        d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
+        if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
+            /* Cannot grow dictionary */
+            return -1 ;
+        }
+        /* Double size */
+        d->size *= 2 ;
+    }
+
+    /* Insert key in the first empty slot. Start at d->n and wrap at
+       d->size. Because d->n < d->size this will necessarily
+       terminate. */
+    for (i=d->n ; d->key[i] ; ) {
+        if(++i == d->size) i = 0;
+    }
+    /* Copy key */
+    d->key[i]  = xstrdup(key);
+    d->val[i]  = val ? xstrdup(val) : NULL ;
+    d->hash[i] = hash;
+    d->n ++ ;
+    return 0 ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a key in a dictionary
+  @param    d       dictionary object to modify.
+  @param    key     Key to remove.
+  @return   void
+
+  This function deletes a key in a dictionary. Nothing is done if the
+  key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, const char * key)
+{
+    unsigned    hash ;
+    int         i ;
+
+    if (key == NULL) {
+        return;
+    }
+
+    hash = dictionary_hash(key);
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        /* Compare hash */
+        if (hash==d->hash[i]) {
+            /* Compare string, to avoid hash collisions */
+            if (!strcmp(key, d->key[i])) {
+                /* Found key */
+                break ;
+            }
+        }
+    }
+    if (i>=d->size)
+        /* Key not found */
+        return ;
+
+    free(d->key[i]);
+    d->key[i] = NULL ;
+    if (d->val[i]!=NULL) {
+        free(d->val[i]);
+        d->val[i] = NULL ;
+    }
+    d->hash[i] = 0 ;
+    d->n -- ;
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer.
+  @return   void
+
+  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+  output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out)
+{
+    int     i ;
+
+    if (d==NULL || out==NULL) return ;
+    if (d->n<1) {
+        fprintf(out, "empty dictionary\n");
+        return ;
+    }
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]) {
+            fprintf(out, "%20s\t[%s]\n",
+                    d->key[i],
+                    d->val[i] ? d->val[i] : "UNDEF");
+        }
+    }
+    return ;
+}
+
+
+/* Test code */
+#ifdef TESTDIC
+#define NVALS 20000
+int main(int argc, char *argv[])
+{
+    dictionary  *   d ;
+    char    *   val ;
+    int         i ;
+    char        cval[90] ;
+
+    /* Allocate dictionary */
+    printf("allocating...\n");
+    d = dictionary_new(0);
+    
+    /* Set values in dictionary */
+    printf("setting %d values...\n", NVALS);
+    for (i=0 ; i<NVALS ; i++) {
+        sprintf(cval, "%04d", i);
+        dictionary_set(d, cval, "salut");
+    }
+    printf("getting %d values...\n", NVALS);
+    for (i=0 ; i<NVALS ; i++) {
+        sprintf(cval, "%04d", i);
+        val = dictionary_get(d, cval, DICT_INVALID_KEY);
+        if (val==DICT_INVALID_KEY) {
+            printf("cannot get value for key [%s]\n", cval);
+        }
+    }
+    printf("unsetting %d values...\n", NVALS);
+    for (i=0 ; i<NVALS ; i++) {
+        sprintf(cval, "%04d", i);
+        dictionary_unset(d, cval);
+    }
+    if (d->n != 0) {
+        printf("error deleting values\n");
+    }
+    printf("deallocating...\n");
+    dictionary_del(d);
+    return 0 ;
+}
+#endif
+/* vim: set ts=4 et sw=4 tw=75 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/iniparser/dictionary.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,165 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    dictionary.h
+   @author  N. Devillard
+   @brief   Implements a dictionary for string variables.
+
+   This module implements a simple dictionary object, i.e. a list
+   of string/string associations. This object is useful to store e.g.
+   informations retrieved from a configuration file (ini files).
+*/
+/*--------------------------------------------------------------------------*/
+
+#ifndef _DICTIONARY_H_
+#define _DICTIONARY_H_
+
+/*---------------------------------------------------------------------------
+                                Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*---------------------------------------------------------------------------
+                                New types
+ ---------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dictionary object
+
+  This object contains a list of string/string associations. Each
+  association is identified by a unique string key. Looking up values
+  in the dictionary is speeded up by the use of a (hopefully collision-free)
+  hash function.
+ */
+/*-------------------------------------------------------------------------*/
+typedef struct _dictionary_ {
+    int             n ;     /** Number of entries in dictionary */
+    int             size ;  /** Storage size */
+    char        **  val ;   /** List of string values */
+    char        **  key ;   /** List of string keys */
+    unsigned     *  hash ;  /** List of hash values for keys */
+} dictionary ;
+
+
+/*---------------------------------------------------------------------------
+                            Function prototypes
+ ---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Compute the hash key for a string.
+  @param    key     Character string to use for key.
+  @return   1 unsigned int on at least 32 bits.
+
+  This hash function has been taken from an Article in Dr Dobbs Journal.
+  This is normally a collision-free function, distributing keys evenly.
+  The key is stored anyway in the struct so that collision can be avoided
+  by comparing the key itself in last resort.
+ */
+/*--------------------------------------------------------------------------*/
+unsigned dictionary_hash(const char * key);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Create a new dictionary object.
+  @param    size    Optional initial size of the dictionary.
+  @return   1 newly allocated dictionary objet.
+
+  This function allocates a new dictionary object of given size and returns
+  it. If you do not know in advance (roughly) the number of entries in the
+  dictionary, give size=0.
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * dictionary_new(int size);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a dictionary object
+  @param    d   dictionary object to deallocate.
+  @return   void
+
+  Deallocate a dictionary object and all memory associated to it.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_del(dictionary * vd);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get a value from a dictionary.
+  @param    d       dictionary object to search.
+  @param    key     Key to look for in the dictionary.
+  @param    def     Default value to return if key not found.
+  @return   1 pointer to internally allocated character string.
+
+  This function locates a key in a dictionary and returns a pointer to its
+  value, or the passed 'def' pointer if no such key can be found in
+  dictionary. The returned character pointer points to data internal to the
+  dictionary object, you should not try to free it or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * dictionary_get(dictionary * d, const char * key, char * def);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set a value in a dictionary.
+  @param    d       dictionary object to modify.
+  @param    key     Key to modify or add.
+  @param    val     Value to add.
+  @return   int     0 if Ok, anything else otherwise
+
+  If the given key is found in the dictionary, the associated value is
+  replaced by the provided one. If the key cannot be found in the
+  dictionary, it is added to it.
+
+  It is Ok to provide a NULL value for val, but NULL values for the dictionary
+  or the key are considered as errors: the function will return immediately
+  in such a case.
+
+  Notice that if you dictionary_set a variable to NULL, a call to
+  dictionary_get will return a NULL value: the variable will be found, and
+  its value (NULL) is returned. In other words, setting the variable
+  content to NULL is equivalent to deleting the variable from the
+  dictionary. It is not possible (in this implementation) to have a key in
+  the dictionary without value.
+
+  This function returns non-zero in case of failure.
+ */
+/*--------------------------------------------------------------------------*/
+int dictionary_set(dictionary * vd, const char * key, const char * val);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete a key in a dictionary
+  @param    d       dictionary object to modify.
+  @param    key     Key to remove.
+  @return   void
+
+  This function deletes a key in a dictionary. Nothing is done if the
+  key cannot be found.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_unset(dictionary * d, const char * key);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer.
+  @return   void
+
+  Dumps a dictionary onto an opened file pointer. Key pairs are printed out
+  as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
+  output file pointers.
+ */
+/*--------------------------------------------------------------------------*/
+void dictionary_dump(dictionary * d, FILE * out);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/iniparser/iniparser.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,748 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    iniparser.c
+   @author  N. Devillard
+   @brief   Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+/*---------------------------- Includes ------------------------------------*/
+#include <ctype.h>
+#include "iniparser.h"
+
+/*---------------------------- Defines -------------------------------------*/
+#define ASCIILINESZ         (1024)
+#define INI_INVALID_KEY     ((char*)-1)
+
+/*---------------------------------------------------------------------------
+                        Private to this module
+ ---------------------------------------------------------------------------*/
+/**
+ * This enum stores the status for each parsed line (internal use only).
+ */
+typedef enum _line_status_ {
+    LINE_UNPROCESSED,
+    LINE_ERROR,
+    LINE_EMPTY,
+    LINE_COMMENT,
+    LINE_SECTION,
+    LINE_VALUE
+} line_status ;
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Convert a string to lowercase.
+  @param    s   String to convert.
+  @return   ptr to statically allocated string.
+
+  This function returns a pointer to a statically allocated string
+  containing a lowercased version of the input string. Do not free
+  or modify the returned string! Since the returned string is statically
+  allocated, it will be modified at each function call (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strlwc(const char * s)
+{
+    static char l[ASCIILINESZ+1];
+    int i ;
+
+    if (s==NULL) return NULL ;
+    memset(l, 0, ASCIILINESZ+1);
+    i=0 ;
+    while (s[i] && i<ASCIILINESZ) {
+        l[i] = (char)tolower((int)s[i]);
+        i++ ;
+    }
+    l[ASCIILINESZ]=(char)0;
+    return l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Remove blanks at the beginning and the end of a string.
+  @param    s   String to parse.
+  @return   ptr to statically allocated string.
+
+  This function returns a pointer to a statically allocated string,
+  which is identical to the input string, except that all blank
+  characters at the end and the beg. of the string have been removed.
+  Do not free or modify the returned string! Since the returned string
+  is statically allocated, it will be modified at each function call
+  (not re-entrant).
+ */
+/*--------------------------------------------------------------------------*/
+static char * strstrip(const char * s)
+{
+    static char l[ASCIILINESZ+1];
+    char * last ;
+    
+    if (s==NULL) return NULL ;
+    
+    while (isspace((int)*s) && *s) s++;
+    memset(l, 0, ASCIILINESZ+1);
+    strcpy(l, s);
+    last = l + strlen(l);
+    while (last > l) {
+        if (!isspace((int)*(last-1)))
+            break ;
+        last -- ;
+    }
+    *last = (char)0;
+    return (char*)l ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get number of sections in a dictionary
+  @param    d   Dictionary to examine
+  @return   int Number of sections found in dictionary
+
+  This function returns the number of sections found in a dictionary.
+  The test to recognize sections is done on the string stored in the
+  dictionary: a section name is given as "section" whereas a key is
+  stored as "section:key", thus the test looks for entries that do not
+  contain a colon.
+
+  This clearly fails in the case a section name contains a colon, but
+  this should simply be avoided.
+
+  This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getnsec(dictionary * d)
+{
+    int i ;
+    int nsec ;
+
+    if (d==NULL) return -1 ;
+    nsec=0 ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        if (strchr(d->key[i], ':')==NULL) {
+            nsec ++ ;
+        }
+    }
+    return nsec ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get name for section n in a dictionary.
+  @param    d   Dictionary to examine
+  @param    n   Section number (from 0 to nsec-1).
+  @return   Pointer to char string
+
+  This function locates the n-th section in a dictionary and returns
+  its name as a pointer to a string statically allocated inside the
+  dictionary. Do not free or modify the returned string!
+
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getsecname(dictionary * d, int n)
+{
+    int i ;
+    int foundsec ;
+
+    if (d==NULL || n<0) return NULL ;
+    foundsec=0 ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        if (strchr(d->key[i], ':')==NULL) {
+            foundsec++ ;
+            if (foundsec>n)
+                break ;
+        }
+    }
+    if (foundsec<=n) {
+        return NULL ;
+    }
+    return d->key[i] ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump.
+  @param    f   Opened file pointer to dump to.
+  @return   void
+
+  This function prints out the contents of a dictionary, one element by
+  line, onto the provided file pointer. It is OK to specify @c stderr
+  or @c stdout as output files. This function is meant for debugging
+  purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f)
+{
+    int     i ;
+
+    if (d==NULL || f==NULL) return ;
+    for (i=0 ; i<d->size ; i++) {
+        if (d->key[i]==NULL)
+            continue ;
+        if (d->val[i]!=NULL) {
+            fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
+        } else {
+            fprintf(f, "[%s]=UNDEF\n", d->key[i]);
+        }
+    }
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given dictionary into a loadable ini file.
+  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump_ini(dictionary * d, FILE * f)
+{
+    int     i ;
+    int     nsec ;
+    char *  secname ;
+
+    if (d==NULL || f==NULL) return ;
+
+    nsec = iniparser_getnsec(d);
+    if (nsec<1) {
+        /* No section in file: dump all keys as they are */
+        for (i=0 ; i<d->size ; i++) {
+            if (d->key[i]==NULL)
+                continue ;
+            fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
+        }
+        return ;
+    }
+    for (i=0 ; i<nsec ; i++) {
+        secname = iniparser_getsecname(d, i) ;
+        iniparser_dumpsection_ini(d, secname, f) ;
+    }
+    fprintf(f, "\n");
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary section to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    s   Section name of dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given section of a given dictionary into a loadable ini
+  file.  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f)
+{
+    int     j ;
+    char    keym[ASCIILINESZ+1];
+    int     seclen ;
+
+    if (d==NULL || f==NULL) return ;
+    if (! iniparser_find_entry(d, s)) return ;
+
+    seclen  = (int)strlen(s);
+    fprintf(f, "\n[%s]\n", s);
+    sprintf(keym, "%s:", s);
+    for (j=0 ; j<d->size ; j++) {
+        if (d->key[j]==NULL)
+            continue ;
+        if (!strncmp(d->key[j], keym, seclen+1)) {
+            fprintf(f,
+                    "%-30s = %s\n",
+                    d->key[j]+seclen+1,
+                    d->val[j] ? d->val[j] : "");
+        }
+    }
+    fprintf(f, "\n");
+    return ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the number of keys in a section of a dictionary.
+  @param    d   Dictionary to examine
+  @param    s   Section name of dictionary to examine
+  @return   Number of keys in section
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getsecnkeys(dictionary * d, char * s)
+{
+    int     seclen, nkeys ;
+    char    keym[ASCIILINESZ+1];
+    int j ;
+
+    nkeys = 0;
+
+    if (d==NULL) return nkeys;
+    if (! iniparser_find_entry(d, s)) return nkeys;
+
+    seclen  = (int)strlen(s);
+    sprintf(keym, "%s:", s);
+
+    for (j=0 ; j<d->size ; j++) {
+        if (d->key[j]==NULL)
+            continue ;
+        if (!strncmp(d->key[j], keym, seclen+1)) 
+            nkeys++;
+    }
+
+    return nkeys;
+
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the number of keys in a section of a dictionary.
+  @param    d   Dictionary to examine
+  @param    s   Section name of dictionary to examine
+  @return   pointer to statically allocated character strings
+
+  This function queries a dictionary and finds all keys in a given section.
+  Each pointer in the returned char pointer-to-pointer is pointing to
+  a string allocated in the dictionary; do not free or modify them.
+  
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char ** iniparser_getseckeys(dictionary * d, char * s)
+{
+
+    char **keys;
+
+    int i, j ;
+    char    keym[ASCIILINESZ+1];
+    int     seclen, nkeys ;
+
+    keys = NULL;
+
+    if (d==NULL) return keys;
+    if (! iniparser_find_entry(d, s)) return keys;
+
+    nkeys = iniparser_getsecnkeys(d, s);
+
+    keys = (char**) malloc(nkeys*sizeof(char*));
+
+    seclen  = (int)strlen(s);
+    sprintf(keym, "%s:", s);
+    
+    i = 0;
+
+    for (j=0 ; j<d->size ; j++) {
+        if (d->key[j]==NULL)
+            continue ;
+        if (!strncmp(d->key[j], keym, seclen+1)) {
+            keys[i] = d->key[j];
+            i++;
+        }
+    }
+
+    return keys;
+
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key
+  @param    d       Dictionary to search
+  @param    key     Key string to look for
+  @param    def     Default value to return if key not found.
+  @return   pointer to statically allocated character string
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the pointer passed as 'def' is returned.
+  The returned char pointer is pointing to a string allocated in
+  the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def)
+{
+    char * lc_key ;
+    char * sval ;
+
+    if (d==NULL || key==NULL)
+        return def ;
+
+    lc_key = strlwc(key);
+    sval = dictionary_get(d, lc_key, def);
+    return sval ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to an int
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  Supported values for integers include the usual C notation
+  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+  are supported. Examples:
+
+  "42"      ->  42
+  "042"     ->  34 (octal -> decimal)
+  "0x42"    ->  66 (hexa  -> decimal)
+
+  Warning: the conversion may overflow in various ways. Conversion is
+  totally outsourced to strtol(), see the associated man page for overflow
+  handling.
+
+  Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound)
+{
+    char    *   str ;
+
+    str = iniparser_getstring(d, key, INI_INVALID_KEY);
+    if (str==INI_INVALID_KEY) return notfound ;
+    return (int)strtol(str, NULL, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a double
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   double
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, const char * key, double notfound)
+{
+    char    *   str ;
+
+    str = iniparser_getstring(d, key, INI_INVALID_KEY);
+    if (str==INI_INVALID_KEY) return notfound ;
+    return atof(str);
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a boolean
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  A true boolean is found if one of the following is matched:
+
+  - A string starting with 'y'
+  - A string starting with 'Y'
+  - A string starting with 't'
+  - A string starting with 'T'
+  - A string starting with '1'
+
+  A false boolean is found if one of the following is matched:
+
+  - A string starting with 'n'
+  - A string starting with 'N'
+  - A string starting with 'f'
+  - A string starting with 'F'
+  - A string starting with '0'
+
+  The notfound value returned if no boolean is identified, does not
+  necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound)
+{
+    char    *   c ;
+    int         ret ;
+
+    c = iniparser_getstring(d, key, INI_INVALID_KEY);
+    if (c==INI_INVALID_KEY) return notfound ;
+    if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
+        ret = 1 ;
+    } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
+        ret = 0 ;
+    } else {
+        ret = notfound ;
+    }
+    return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Finds out if a given entry exists in a dictionary
+  @param    ini     Dictionary to search
+  @param    entry   Name of the entry to look for
+  @return   integer 1 if entry exists, 0 otherwise
+
+  Finds out if a given entry exists in the dictionary. Since sections
+  are stored as keys with NULL associated values, this is the only way
+  of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(
+    dictionary  *   ini,
+    const char  *   entry
+)
+{
+    int found=0 ;
+    if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
+        found = 1 ;
+    }
+    return found ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set an entry in a dictionary.
+  @param    ini     Dictionary to modify.
+  @param    entry   Entry to modify (entry name)
+  @param    val     New value to associate to the entry.
+  @return   int 0 if Ok, -1 otherwise.
+
+  If the given entry can be found in the dictionary, it is modified to
+  contain the provided value. If it cannot be found, -1 is returned.
+  It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_set(dictionary * ini, const char * entry, const char * val)
+{
+    return dictionary_set(ini, strlwc(entry), val) ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete an entry in a dictionary
+  @param    ini     Dictionary to modify
+  @param    entry   Entry to delete (entry name)
+  @return   void
+
+  If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, const char * entry)
+{
+    dictionary_unset(ini, strlwc(entry));
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Load a single line from an INI file
+  @param    input_line  Input line, may be concatenated multi-line input
+  @param    section     Output space to store section
+  @param    key         Output space to store key
+  @param    value       Output space to store value
+  @return   line_status value
+ */
+/*--------------------------------------------------------------------------*/
+static line_status iniparser_line(
+    const char * input_line,
+    char * section,
+    char * key,
+    char * value)
+{   
+    line_status sta ;
+    char        line[ASCIILINESZ+1];
+    int         len ;
+
+    strcpy(line, strstrip(input_line));
+    len = (int)strlen(line);
+
+    sta = LINE_UNPROCESSED ;
+    if (len<1) {
+        /* Empty line */
+        sta = LINE_EMPTY ;
+    } else if (line[0]=='#' || line[0]==';') {
+        /* Comment line */
+        sta = LINE_COMMENT ; 
+    } else if (line[0]=='[' && line[len-1]==']') {
+        /* Section name */
+        sscanf(line, "[%[^]]", section);
+        strcpy(section, strstrip(section));
+        strcpy(section, strlwc(section));
+        sta = LINE_SECTION ;
+    } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
+           ||  sscanf (line, "%[^=] = '%[^\']'",   key, value) == 2
+           ||  sscanf (line, "%[^=] = %[^;#]",     key, value) == 2) {
+        /* Usual key=value, with or without comments */
+        strcpy(key, strstrip(key));
+        strcpy(key, strlwc(key));
+        strcpy(value, strstrip(value));
+        /*
+         * sscanf cannot handle '' or "" as empty values
+         * this is done here
+         */
+        if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
+            value[0]=0 ;
+        }
+        sta = LINE_VALUE ;
+    } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
+           ||  sscanf(line, "%[^=] %[=]", key, value) == 2) {
+        /*
+         * Special cases:
+         * key=
+         * key=;
+         * key=#
+         */
+        strcpy(key, strstrip(key));
+        strcpy(key, strlwc(key));
+        value[0]=0 ;
+        sta = LINE_VALUE ;
+    } else {
+        /* Generate syntax error */
+        sta = LINE_ERROR ;
+    }
+    return sta ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Parse an ini file and return an allocated dictionary object
+  @param    ininame Name of the ini file to read.
+  @return   Pointer to newly allocated dictionary
+
+  This is the parser for ini files. This function is called, providing
+  the name of the file to be read. It returns a dictionary object that
+  should not be accessed directly, but through accessor functions
+  instead.
+
+  The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame)
+{
+    FILE * in ;
+
+    char line    [ASCIILINESZ+1] ;
+    char section [ASCIILINESZ+1] ;
+    char key     [ASCIILINESZ+1] ;
+    char tmp     [ASCIILINESZ+1] ;
+    char val     [ASCIILINESZ+1] ;
+
+    int  last=0 ;
+    int  len ;
+    int  lineno=0 ;
+    int  errs=0;
+
+    dictionary * dict ;
+
+    if ((in=fopen(ininame, "r"))==NULL) {
+        fprintf(stderr, "iniparser: cannot open %s\n", ininame);
+        return NULL ;
+    }
+
+    dict = dictionary_new(0) ;
+    if (!dict) {
+        fclose(in);
+        return NULL ;
+    }
+
+    memset(line,    0, ASCIILINESZ);
+    memset(section, 0, ASCIILINESZ);
+    memset(key,     0, ASCIILINESZ);
+    memset(val,     0, ASCIILINESZ);
+    last=0 ;
+
+    while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
+        lineno++ ;
+        len = (int)strlen(line)-1;
+        if (len==0)
+            continue;
+        /* Safety check against buffer overflows */
+        if (line[len]!='\n') {
+            fprintf(stderr,
+                    "iniparser: input line too long in %s (%d)\n",
+                    ininame,
+                    lineno);
+            dictionary_del(dict);
+            fclose(in);
+            return NULL ;
+        }
+        /* Get rid of \n and spaces at end of line */
+        while ((len>=0) &&
+                ((line[len]=='\n') || (isspace(line[len])))) {
+            line[len]=0 ;
+            len-- ;
+        }
+        /* Detect multi-line */
+        if (line[len]=='\\') {
+            /* Multi-line value */
+            last=len ;
+            continue ;
+        } else {
+            last=0 ;
+        }
+        switch (iniparser_line(line, section, key, val)) {
+            case LINE_EMPTY:
+            case LINE_COMMENT:
+            break ;
+
+            case LINE_SECTION:
+            errs = dictionary_set(dict, section, NULL);
+            break ;
+
+            case LINE_VALUE:
+            sprintf(tmp, "%s:%s", section, key);
+            errs = dictionary_set(dict, tmp, val) ;
+            break ;
+
+            case LINE_ERROR:
+            fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
+                    ininame,
+                    lineno);
+            fprintf(stderr, "-> %s\n", line);
+            errs++ ;
+            break;
+
+            default:
+            break ;
+        }
+        memset(line, 0, ASCIILINESZ);
+        last=0;
+        if (errs<0) {
+            fprintf(stderr, "iniparser: memory allocation failure\n");
+            break ;
+        }
+    }
+    if (errs) {
+        dictionary_del(dict);
+        dict = NULL ;
+    }
+    fclose(in);
+    return dict ;
+}
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Free all memory associated to an ini dictionary
+  @param    d Dictionary to free
+  @return   void
+
+  Free all memory associated to an ini dictionary.
+  It is mandatory to call this function before the dictionary object
+  gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d)
+{
+    dictionary_del(d);
+}
+
+/* vim: set ts=4 et sw=4 tw=75 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/iniparser/iniparser.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,307 @@
+
+/*-------------------------------------------------------------------------*/
+/**
+   @file    iniparser.h
+   @author  N. Devillard
+   @brief   Parser for ini files.
+*/
+/*--------------------------------------------------------------------------*/
+
+#ifndef _INIPARSER_H_
+#define _INIPARSER_H_
+
+/*---------------------------------------------------------------------------
+                                Includes
+ ---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * The following #include is necessary on many Unixes but not Linux.
+ * It is not needed for Windows platforms.
+ * Uncomment it if needed.
+ */
+/* #include <unistd.h> */
+
+#include "dictionary.h"
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get number of sections in a dictionary
+  @param    d   Dictionary to examine
+  @return   int Number of sections found in dictionary
+
+  This function returns the number of sections found in a dictionary.
+  The test to recognize sections is done on the string stored in the
+  dictionary: a section name is given as "section" whereas a key is
+  stored as "section:key", thus the test looks for entries that do not
+  contain a colon.
+
+  This clearly fails in the case a section name contains a colon, but
+  this should simply be avoided.
+
+  This function returns -1 in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+int iniparser_getnsec(dictionary * d);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get name for section n in a dictionary.
+  @param    d   Dictionary to examine
+  @param    n   Section number (from 0 to nsec-1).
+  @return   Pointer to char string
+
+  This function locates the n-th section in a dictionary and returns
+  its name as a pointer to a string statically allocated inside the
+  dictionary. Do not free or modify the returned string!
+
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+
+char * iniparser_getsecname(dictionary * d, int n);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given dictionary into a loadable ini file.
+  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dump_ini(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Save a dictionary section to a loadable ini file
+  @param    d   Dictionary to dump
+  @param    s   Section name of dictionary to dump
+  @param    f   Opened file pointer to dump to
+  @return   void
+
+  This function dumps a given section of a given dictionary into a loadable ini
+  file.  It is Ok to specify @c stderr or @c stdout as output files.
+ */
+/*--------------------------------------------------------------------------*/
+
+void iniparser_dumpsection_ini(dictionary * d, char * s, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Dump a dictionary to an opened file pointer.
+  @param    d   Dictionary to dump.
+  @param    f   Opened file pointer to dump to.
+  @return   void
+
+  This function prints out the contents of a dictionary, one element by
+  line, onto the provided file pointer. It is OK to specify @c stderr
+  or @c stdout as output files. This function is meant for debugging
+  purposes mostly.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_dump(dictionary * d, FILE * f);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the number of keys in a section of a dictionary.
+  @param    d   Dictionary to examine
+  @param    s   Section name of dictionary to examine
+  @return   Number of keys in section
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getsecnkeys(dictionary * d, char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the number of keys in a section of a dictionary.
+  @param    d   Dictionary to examine
+  @param    s   Section name of dictionary to examine
+  @return   pointer to statically allocated character strings
+
+  This function queries a dictionary and finds all keys in a given section.
+  Each pointer in the returned char pointer-to-pointer is pointing to
+  a string allocated in the dictionary; do not free or modify them.
+
+  This function returns NULL in case of error.
+ */
+/*--------------------------------------------------------------------------*/
+char ** iniparser_getseckeys(dictionary * d, char * s);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key
+  @param    d       Dictionary to search
+  @param    key     Key string to look for
+  @param    def     Default value to return if key not found.
+  @return   pointer to statically allocated character string
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the pointer passed as 'def' is returned.
+  The returned char pointer is pointing to a string allocated in
+  the dictionary, do not free or modify it.
+ */
+/*--------------------------------------------------------------------------*/
+char * iniparser_getstring(dictionary * d, const char * key, char * def);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to an int
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  Supported values for integers include the usual C notation
+  so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
+  are supported. Examples:
+
+  - "42"      ->  42
+  - "042"     ->  34 (octal -> decimal)
+  - "0x42"    ->  66 (hexa  -> decimal)
+
+  Warning: the conversion may overflow in various ways. Conversion is
+  totally outsourced to strtol(), see the associated man page for overflow
+  handling.
+
+  Credits: Thanks to A. Becker for suggesting strtol()
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getint(dictionary * d, const char * key, int notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a double
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   double
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+ */
+/*--------------------------------------------------------------------------*/
+double iniparser_getdouble(dictionary * d, const char * key, double notfound);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Get the string associated to a key, convert to a boolean
+  @param    d Dictionary to search
+  @param    key Key string to look for
+  @param    notfound Value to return in case of error
+  @return   integer
+
+  This function queries a dictionary for a key. A key as read from an
+  ini file is given as "section:key". If the key cannot be found,
+  the notfound value is returned.
+
+  A true boolean is found if one of the following is matched:
+
+  - A string starting with 'y'
+  - A string starting with 'Y'
+  - A string starting with 't'
+  - A string starting with 'T'
+  - A string starting with '1'
+
+  A false boolean is found if one of the following is matched:
+
+  - A string starting with 'n'
+  - A string starting with 'N'
+  - A string starting with 'f'
+  - A string starting with 'F'
+  - A string starting with '0'
+
+  The notfound value returned if no boolean is identified, does not
+  necessarily have to be 0 or 1.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_getboolean(dictionary * d, const char * key, int notfound);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Set an entry in a dictionary.
+  @param    ini     Dictionary to modify.
+  @param    entry   Entry to modify (entry name)
+  @param    val     New value to associate to the entry.
+  @return   int 0 if Ok, -1 otherwise.
+
+  If the given entry can be found in the dictionary, it is modified to
+  contain the provided value. If it cannot be found, -1 is returned.
+  It is Ok to set val to NULL.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_set(dictionary * ini, const char * entry, const char * val);
+
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Delete an entry in a dictionary
+  @param    ini     Dictionary to modify
+  @param    entry   Entry to delete (entry name)
+  @return   void
+
+  If the given entry can be found, it is deleted from the dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_unset(dictionary * ini, const char * entry);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Finds out if a given entry exists in a dictionary
+  @param    ini     Dictionary to search
+  @param    entry   Name of the entry to look for
+  @return   integer 1 if entry exists, 0 otherwise
+
+  Finds out if a given entry exists in the dictionary. Since sections
+  are stored as keys with NULL associated values, this is the only way
+  of querying for the presence of sections in a dictionary.
+ */
+/*--------------------------------------------------------------------------*/
+int iniparser_find_entry(dictionary * ini, const char * entry) ;
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Parse an ini file and return an allocated dictionary object
+  @param    ininame Name of the ini file to read.
+  @return   Pointer to newly allocated dictionary
+
+  This is the parser for ini files. This function is called, providing
+  the name of the file to be read. It returns a dictionary object that
+  should not be accessed directly, but through accessor functions
+  instead.
+
+  The returned dictionary must be freed using iniparser_freedict().
+ */
+/*--------------------------------------------------------------------------*/
+dictionary * iniparser_load(const char * ininame);
+
+/*-------------------------------------------------------------------------*/
+/**
+  @brief    Free all memory associated to an ini dictionary
+  @param    d Dictionary to free
+  @return   void
+
+  Free all memory associated to an ini dictionary.
+  It is mandatory to call this function before the dictionary object
+  gets out of the current context.
+ */
+/*--------------------------------------------------------------------------*/
+void iniparser_freedict(dictionary * d);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/gameconn.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,452 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "gameconn.h"
+#include "ipcbase.h"
+#include "ipcprotocol.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../hwconsts.h"
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef enum {
+	AWAIT_CONNECTION,
+	CONNECTED,
+	FINISHED
+} gameconn_state;
+
+struct _flib_gameconn {
+	flib_ipcbase *ipcBase;
+	flib_vector *configBuffer;
+	flib_vector *demoBuffer;
+	char *playerName;
+
+	gameconn_state state;
+	bool netgame;
+	int disconnectReason;
+
+	void (*onConnectCb)(void* context);
+	void *onConnectCtx;
+
+	void (*onDisconnectCb)(void* context, int reason);
+	void *onDisconnectCtx;
+
+	void (*onErrorMessageCb)(void* context, const char *msg);
+	void *onErrorMessageCtx;
+
+	void (*onChatCb)(void* context, const char *msg, bool teamchat);
+	void *onChatCtx;
+
+	void (*onGameRecordedCb)(void *context, const uint8_t *record, size_t size, bool isSavegame);
+	void *onGameRecordedCtx;
+
+	void (*onEngineMessageCb)(void *context, const uint8_t *em, size_t size);
+	void *onEngineMessageCtx;
+
+	bool running;
+	bool destroyRequested;
+};
+
+static void defaultCallback_onErrorMessage(void* context, const char *msg) {
+	flib_log_w("Error from engine (no callback set): %s", msg);
+}
+
+static void clearCallbacks(flib_gameconn *conn) {
+	flib_gameconn_onConnect(conn, NULL, NULL);
+	flib_gameconn_onDisconnect(conn, NULL, NULL);
+	flib_gameconn_onErrorMessage(conn, NULL, NULL);
+	flib_gameconn_onChat(conn, NULL, NULL);
+	flib_gameconn_onGameRecorded(conn, NULL, NULL);
+	flib_gameconn_onEngineMessage(conn, NULL, NULL);
+}
+
+static flib_gameconn *flib_gameconn_create_partial(bool record, const char *playerName, bool netGame) {
+	flib_gameconn *result = NULL;
+	flib_gameconn *tempConn = flib_calloc(1, sizeof(flib_gameconn));
+	if(tempConn) {
+		tempConn->ipcBase = flib_ipcbase_create();
+		tempConn->configBuffer = flib_vector_create();
+		tempConn->playerName = flib_strdupnull(playerName);
+		if(tempConn->ipcBase && tempConn->configBuffer && tempConn->playerName) {
+			if(record) {
+				tempConn->demoBuffer = flib_vector_create();
+			}
+			tempConn->state = AWAIT_CONNECTION;
+			tempConn->netgame = netGame;
+			tempConn->disconnectReason = GAME_END_ERROR;
+			clearCallbacks(tempConn);
+			result = tempConn;
+			tempConn = NULL;
+		}
+	}
+	flib_gameconn_destroy(tempConn);
+	return result;
+}
+
+flib_gameconn *flib_gameconn_create(const char *playerName, const flib_gamesetup *setup, bool netgame) {
+	if(log_badargs_if2(playerName==NULL, setup==NULL)) {
+		return NULL;
+	}
+	flib_gameconn *result = NULL;
+	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, netgame);
+	if(tempConn) {
+		if(flib_ipc_append_fullconfig(tempConn->configBuffer, setup, netgame)) {
+			flib_log_e("Error generating full game configuration for the engine.");
+		} else {
+			result = tempConn;
+			tempConn = NULL;
+		}
+	}
+	flib_gameconn_destroy(tempConn);
+	return result;
+}
+
+flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demoFileContent, size_t size) {
+	if(log_badargs_if(demoFileContent==NULL && size>0)) {
+		return NULL;
+	}
+	flib_gameconn *result = NULL;
+	flib_gameconn *tempConn = flib_gameconn_create_partial(false, "Player", false);
+	if(tempConn) {
+		if(!flib_vector_append(tempConn->configBuffer, demoFileContent, size)) {
+			result = tempConn;
+			tempConn = NULL;
+		}
+	}
+	flib_gameconn_destroy(tempConn);
+	return result;
+}
+
+flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *saveFileContent, size_t size) {
+	if(log_badargs_if(saveFileContent==NULL && size>0)) {
+		return NULL;
+	}
+	flib_gameconn *result = NULL;
+	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false);
+	if(tempConn) {
+		if(!flib_vector_append(tempConn->configBuffer, saveFileContent, size)) {
+			result = tempConn;
+			tempConn = NULL;
+		}
+	}
+	flib_gameconn_destroy(tempConn);
+	return result;
+}
+
+flib_gameconn *flib_gameconn_create_campaign(const char *playerName, const char *seed, const char *script) {
+	if(log_badargs_if3(playerName==NULL, seed==NULL, script==NULL)) {
+		return NULL;
+	}
+	flib_gameconn *result = NULL;
+	flib_gameconn *tempConn = flib_gameconn_create_partial(true, playerName, false);
+	if(tempConn) {
+		if(!flib_ipc_append_message(tempConn->configBuffer, "TL")
+				&& !flib_ipc_append_seed(tempConn->configBuffer, seed)
+				&& !flib_ipc_append_script(tempConn->configBuffer, script)
+				&& !flib_ipc_append_message(tempConn->configBuffer, "!")) {
+			result = tempConn;
+			tempConn = NULL;
+		}
+	}
+	flib_gameconn_destroy(tempConn);
+	return result;
+}
+
+void flib_gameconn_destroy(flib_gameconn *conn) {
+	if(conn) {
+		if(conn->running) {
+			/*
+			 * The function was called from a callback, so the tick function is still running
+			 * and we delay the actual destruction. We ensure no further callbacks will be
+			 * sent to prevent surprises.
+			 */
+			clearCallbacks(conn);
+			conn->destroyRequested = true;
+		} else {
+			flib_ipcbase_destroy(conn->ipcBase);
+			flib_vector_destroy(conn->configBuffer);
+			flib_vector_destroy(conn->demoBuffer);
+			free(conn->playerName);
+			free(conn);
+		}
+	}
+}
+
+int flib_gameconn_getport(flib_gameconn *conn) {
+	if(log_badargs_if(conn==NULL)) {
+		return 0;
+	}
+	return flib_ipcbase_port(conn->ipcBase);
+}
+
+static void demo_append(flib_gameconn *conn, const void *data, size_t len) {
+	if(conn->demoBuffer) {
+		if(flib_vector_append(conn->demoBuffer, data, len)) {
+			flib_log_e("Error recording demo: Out of memory.");
+			flib_vector_destroy(conn->demoBuffer);
+			conn->demoBuffer = NULL;
+		}
+	}
+}
+
+static int format_chatmessage(uint8_t buffer[257], const char *playerName, const char *message) {
+	size_t msglen = strlen(message);
+
+	// If the message starts with /me, it will be displayed differently.
+	bool meMessage = msglen >= 4 && !memcmp(message, "/me ", 4);
+	const char *template = meMessage ? "s\x02* %s %s  " : "s\x01%s: %s  ";
+	int size = snprintf((char*)buffer+1, 256, template, playerName, meMessage ? message+4 : message);
+	if(log_e_if(size<=0, "printf error")) {
+		return -1;
+	} else {
+		buffer[0] = size>255 ? 255 : size;
+		return 0;
+	}
+}
+
+static void demo_append_chatmessage(flib_gameconn *conn, const char *message) {
+	// Chat messages are reformatted to make them look as if they were received, not sent.
+	uint8_t converted[257];
+	if(!format_chatmessage(converted, conn->playerName, message)) {
+		demo_append(conn, converted, converted[0]+1);
+	}
+}
+
+static void demo_replace_gamemode(flib_buffer buf, char gamemode) {
+	size_t msgStart = 0;
+	uint8_t *data = (uint8_t*)buf.data;
+	while(msgStart+2 < buf.size) {
+		if(!memcmp(data+msgStart, "\x02T", 2)) {
+			data[msgStart+2] = gamemode;
+		}
+		msgStart += (uint8_t)data[msgStart]+1;
+	}
+}
+
+int flib_gameconn_send_enginemsg(flib_gameconn *conn, const uint8_t *data, size_t len) {
+	if(log_badargs_if2(conn==NULL, data==NULL && len>0)) {
+		return -1;
+	}
+	int result = flib_ipcbase_send_raw(conn->ipcBase, data, len);
+	if(!result) {
+		demo_append(conn, data, len);
+	}
+	return result;
+}
+
+int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg) {
+	if(log_badargs_if2(conn==NULL, msg==NULL)) {
+		return -1;
+	}
+	int result = -1;
+	uint8_t converted[257];
+	int size = snprintf((char*)converted+1, 256, "s%c%s", (char)msgtype, msg);
+	if(size>0) {
+		converted[0] = size>255 ? 255 : size;
+		if(!flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
+			demo_append(conn, converted, converted[0]+1);
+			result = 0;
+		}
+	}
+	return result;
+}
+
+int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg) {
+	if(log_badargs_if3(conn==NULL, playername==NULL, msg==NULL)) {
+		return -1;
+	}
+	uint8_t converted[257];
+	if(!format_chatmessage(converted, playername, msg)
+			&& !flib_ipcbase_send_raw(conn->ipcBase, converted, converted[0]+1)) {
+		demo_append(conn, converted, converted[0]+1);
+		return 0;
+	}
+	return -1;
+}
+
+int flib_gameconn_send_quit(flib_gameconn *conn) {
+	return flib_gameconn_send_cmd(conn, "efinish");
+}
+
+int flib_gameconn_send_cmd(flib_gameconn *conn, const char *cmdString) {
+	if(log_badargs_if2(conn==NULL, cmdString==NULL)) {
+		return -1;
+	}
+	int result = -1;
+	uint8_t converted[256];
+	size_t msglen = strlen(cmdString);
+	if(!log_e_if(msglen>255, "Message too long: %s", cmdString)) {
+		strcpy((char*)converted+1, cmdString);
+		converted[0] = msglen;
+		if(!flib_ipcbase_send_raw(conn->ipcBase, converted, msglen+1)) {
+			demo_append(conn, converted, msglen+1);
+			result = 0;
+		}
+	}
+	return result;
+}
+
+/**
+ * This macro generates a callback setter function. It uses the name of the callback to
+ * automatically generate the function name and the fields to set, so a consistent naming
+ * convention needs to be enforced (not that that is a bad thing). If null is passed as
+ * callback to the generated function, the defaultCb will be set instead (with conn
+ * as the context).
+ */
+#define GENERATE_CB_SETTER(cbName, cbParameterTypes, defaultCb) \
+	void flib_gameconn_##cbName(flib_gameconn *conn, void (*callback)cbParameterTypes, void *context) { \
+		if(!log_badargs_if(conn==NULL)) { \
+			conn->cbName##Cb = callback ? callback : &defaultCb; \
+			conn->cbName##Ctx = callback ? context : conn; \
+		} \
+	}
+
+/**
+ * Generate a callback setter function like GENERATE_CB_SETTER, and automatically generate a
+ * no-op callback function as well that is used as default.
+ */
+#define GENERATE_CB_SETTER_AND_DEFAULT(cbName, cbParameterTypes) \
+	static void _noop_callback_##cbName cbParameterTypes {} \
+	GENERATE_CB_SETTER(cbName, cbParameterTypes, _noop_callback_##cbName)
+
+GENERATE_CB_SETTER_AND_DEFAULT(onConnect, (void *context));
+GENERATE_CB_SETTER_AND_DEFAULT(onDisconnect, (void* context, int reason));
+GENERATE_CB_SETTER(onErrorMessage, (void* context, const char *msg), defaultCallback_onErrorMessage);
+GENERATE_CB_SETTER_AND_DEFAULT(onChat, (void* context, const char *msg, bool teamchat));
+GENERATE_CB_SETTER_AND_DEFAULT(onGameRecorded, (void *context, const uint8_t *record, size_t size, bool isSavegame));
+GENERATE_CB_SETTER_AND_DEFAULT(onEngineMessage, (void *context, const uint8_t *em, size_t size));
+
+#undef GENERATE_CB_SETTER_AND_DEFAULT
+#undef GENERATE_CB_SETTER
+
+static void flib_gameconn_wrappedtick(flib_gameconn *conn) {
+	if(conn->state == AWAIT_CONNECTION) {
+		flib_ipcbase_accept(conn->ipcBase);
+		switch(flib_ipcbase_state(conn->ipcBase)) {
+		case IPC_CONNECTED:
+			{
+				flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer);
+				if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) {
+					conn->state = FINISHED;
+					conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
+					return;
+				} else {
+					demo_append(conn, configBuffer.data, configBuffer.size);
+					conn->state = CONNECTED;
+					conn->onConnectCb(conn->onConnectCtx);
+					if(conn->destroyRequested) {
+						return;
+					}
+				}
+			}
+			break;
+		case IPC_NOT_CONNECTED:
+			conn->state = FINISHED;
+			conn->onDisconnectCb(conn->onDisconnectCtx, GAME_END_ERROR);
+			return;
+		default:
+			break;
+		}
+	}
+
+	if(conn->state == CONNECTED) {
+		uint8_t msgbuffer[257];
+		int len;
+		while(!conn->destroyRequested && (len = flib_ipcbase_recv_message(conn->ipcBase, msgbuffer))>=0) {
+			if(len<2) {
+				flib_log_w("Received short message from IPC (<2 bytes)");
+				continue;
+			}
+			switch(msgbuffer[1]) {
+			case '?':	// Ping
+				// The pong is already part of the config message
+				break;
+			case 'C':	// Config query
+				// And we already send the config message on connecting.
+				break;
+			case 'E':	// Error message
+				if(len>=3) {
+					msgbuffer[len-2] = 0;
+					conn->onErrorMessageCb(conn->onErrorMessageCtx, (char*)msgbuffer+2);
+				}
+				break;
+			case 'i':	// Statistics
+				// TODO stats
+				break;
+			case 'Q':	// Game interrupted
+			case 'H':	// Game halted
+			case 'q':	// game finished
+				{
+					int reason = msgbuffer[1]=='Q' ? GAME_END_INTERRUPTED : msgbuffer[1]=='H' ? GAME_END_HALTED : GAME_END_FINISHED;
+					conn->disconnectReason = reason;
+					bool savegame = (reason != GAME_END_FINISHED) && !conn->netgame;
+					if(conn->demoBuffer) {
+						flib_buffer demoBuffer = flib_vector_as_buffer(conn->demoBuffer);
+						demo_replace_gamemode(demoBuffer, savegame ? 'S' : 'D');
+						conn->onGameRecordedCb(conn->onGameRecordedCtx, demoBuffer.data, demoBuffer.size, savegame);
+						if(conn->destroyRequested) {
+							return;
+						}
+					}
+					return;
+				}
+			case 's':	// Chat message
+				if(len>=3) {
+					msgbuffer[len-2] = 0;
+					demo_append_chatmessage(conn, (char*)msgbuffer+2);
+
+					conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, false);
+				}
+				break;
+			case 'b':	// Teamchat message
+				if(len>=3) {
+					msgbuffer[len-2] = 0;
+					conn->onChatCb(conn->onChatCtx, (char*)msgbuffer+2, true);
+				}
+				break;
+			default:	// Engine message
+				demo_append(conn, msgbuffer, len);
+
+				conn->onEngineMessageCb(conn->onEngineMessageCtx, msgbuffer, len);
+				break;
+			}
+		}
+	}
+
+	if(flib_ipcbase_state(conn->ipcBase) == IPC_NOT_CONNECTED) {
+		conn->state = FINISHED;
+		conn->onDisconnectCb(conn->onDisconnectCtx, conn->disconnectReason);
+	}
+}
+
+void flib_gameconn_tick(flib_gameconn *conn) {
+	if(!log_badargs_if(conn == NULL)
+			&& !log_w_if(conn->running, "Call to flib_gameconn_tick from a callback")
+			&& !log_w_if(conn->state == FINISHED, "We are already done.")) {
+		conn->running = true;
+		flib_gameconn_wrappedtick(conn);
+		conn->running = false;
+
+		if(conn->destroyRequested) {
+			flib_gameconn_destroy(conn);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/gameconn.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,179 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * This file contains functions for starting and interacting with a game run by the engine.
+ * The general usage is to first create a gameconn object by calling one of the flib_gameconn_create
+ * functions. That will cause the frontlib to listen on a random port which can be queried using
+ * flib_gameconn_getport(). You should also register your callback functions right at the start
+ * to ensure you don't miss any callbacks.
+ *
+ * Next, start the engine (that part is up to you) with the appropriate command line arguments
+ * for starting a game.
+ *
+ * In order to allow the gameconn to run, you should regularly call flib_gameconn_tick(), which
+ * performs network I/O and calls your callbacks on interesting events.
+ *
+ * Once the engine connects, the gameconn will send it the required commands for starting the
+ * game you requested in your flib_gameconn_create call.
+ *
+ * When the game is finished (or the connection is lost), you will receive the onDisconnect
+ * message. This is the signal to destroy the gameconn and stop calling tick().
+ */
+
+#ifndef GAMECONN_H_
+#define GAMECONN_H_
+
+#include "../model/gamesetup.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/*
+ * Different reasons for a disconnect. Only GAME_END_FINISHED signals a correctly completed game.
+ */
+#define GAME_END_FINISHED 0
+#define GAME_END_INTERRUPTED 1
+#define GAME_END_HALTED 2
+#define GAME_END_ERROR 3
+
+typedef struct _flib_gameconn flib_gameconn;
+
+/**
+ * Create a gameconn that will start a local or network game with the indicated configuration.
+ */
+flib_gameconn *flib_gameconn_create(const char *playerName, const flib_gamesetup *setup, bool netgame);
+
+/**
+ * Create a gameconn that will play back a demo.
+ */
+flib_gameconn *flib_gameconn_create_playdemo(const uint8_t *demoFileContent, size_t size);
+
+/**
+ * Create a gameconn that will continue from a saved game.
+ */
+flib_gameconn *flib_gameconn_create_loadgame(const char *playerName, const uint8_t *saveFileContent, size_t size);
+
+/**
+ * Create a gameconn that will start a campaign or training mission with the indicated script.
+ * seed is the random seed to use as entropy source (any string).
+ * script is the path and filename of a Campaign or Training script, relative to the Data directory
+ * (e.g. "Missions/Training/Basic_Training_-_Bazooka.lua")
+ */
+flib_gameconn *flib_gameconn_create_campaign(const char *playerName, const char *seed, const char *script);
+
+/**
+ * Release all resources of this gameconn, including the network connection, and free its memory.
+ * It is safe to call this function from a callback.
+ */
+void flib_gameconn_destroy(flib_gameconn *conn);
+
+/**
+ * Returns the port on which the gameconn is listening. Only fails if you
+ * pass NULL (not allowed), in that case 0 is returned.
+ */
+int flib_gameconn_getport(flib_gameconn *conn);
+
+/**
+ * Perform I/O operations and call callbacks if something interesting happens.
+ * Should be called regularly.
+ */
+void flib_gameconn_tick(flib_gameconn *conn);
+
+/**
+ * Send an engine message to the engine. Only needed in net games, where you receive engine
+ * messages from the server and have to pass them here.
+ */
+int flib_gameconn_send_enginemsg(flib_gameconn *conn, const uint8_t *data, size_t len);
+
+/**
+ * Send an info message to the engine that will be displayed in the game's chatlog.
+ * The msgtype determines the color of the message;  in the QTFrontend, info messages and
+ * normal chat messages use 1, emote-messages (those starting with /me) use 2, and
+ * join/leave messages use 3. You should use flib_gameconn_send_chatmsg for chat messages
+ * though because it automatically formats /me messages.
+ *
+ * Generally only needed in net games.
+ */
+int flib_gameconn_send_textmsg(flib_gameconn *conn, int msgtype, const char *msg);
+
+/**
+ * Send a chat message to be displayed in the game's chatlog. Messages starting with /me are
+ * automatically formatted correctly.
+ *
+ * Generally only needed in net games.
+ */
+int flib_gameconn_send_chatmsg(flib_gameconn *conn, const char *playername, const char *msg);
+
+/**
+ * Request the engine to stop the game (efinish).
+ * You can use this to shut down a game early without directly killing the engine process.
+ */
+int flib_gameconn_send_quit(flib_gameconn *conn);
+
+/**
+ * Send an arbitrary command to the engine, e.g. "eforcequit" to shut down the engine
+ * quickly. Commands prefixed with "e" will be processed by the engine's ProcessCommand
+ * method (with the e removed, so e.g. efinish will be parsed as finish).
+ */
+int flib_gameconn_send_cmd(flib_gameconn *conn, const char *cmdString);
+
+/**
+ * Expected callback signature: void handleConnect(void *context)
+ * The engine has successfully connected. You don't have to react to this in any way.
+ */
+void flib_gameconn_onConnect(flib_gameconn *conn, void (*callback)(void* context), void* context);
+
+/**
+ * Expected callback signature: void handleDisconnect(void *context, int reason)
+ * The connection to the engine was closed, either because the game has ended normally, or
+ * because it was interrupted/halted, or because of an error. The reason is provided as one
+ * of the GAME_END_xxx constants.
+ *
+ * You should destroy the gameconn and - in a netgame - notify the server that the game has ended.
+ */
+void flib_gameconn_onDisconnect(flib_gameconn *conn, void (*callback)(void* context, int reason), void* context);
+
+/**
+ * Expected callback signature: void handleErrorMessage(void* context, const char *msg)
+ * The engine sent an error message, you should probably display it to the user or at least log it.
+ */
+void flib_gameconn_onErrorMessage(flib_gameconn *conn, void (*callback)(void* context, const char *msg), void* context);
+
+/**
+ * Expected callback signature: void handleChat(void* context, const char *msg, bool teamchat)
+ * The player entered a chat or teamchat message. In a netgame, you should send it on to the server.
+ */
+void flib_gameconn_onChat(flib_gameconn *conn, void (*callback)(void* context, const char *msg, bool teamchat), void* context);
+
+/**
+ * Expected callback signature: void handleGameRecorded(void *context, const uint8_t *record, size_t size, bool isSavegame)
+ * The game has stopped, and a demo or savegame is available. You can store it in a file and later pass it back
+ * to the engine to either watch a replay (if it's a demo) or to continue playing (if it's a savegame).
+ */
+void flib_gameconn_onGameRecorded(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *record, size_t size, bool isSavegame), void* context);
+
+/**
+ * Expected callback signature: void handleEngineMessage(void *context, const uint8_t *em, size_t size)
+ * The engine has generated a message with player input. In a netgame, you should send it on to the server.
+ */
+void flib_gameconn_onEngineMessage(flib_gameconn *conn, void (*callback)(void *context, const uint8_t *em, size_t size), void* context);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/ipcbase.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,216 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "ipcbase.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../socket.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * The receive buffer has to be able to hold any message that might be received. Normally
+ * the messages are at most 256 bytes, but the map preview contains 4097 bytes (4096 for a
+ * bitmap, 1 for the number of hogs which fit on the map).
+ *
+ * We don't need to worry about wasting a few kb though, and I like powers of two...
+ */
+struct _flib_ipcbase {
+	uint8_t readBuffer[8192];
+	int readBufferSize;
+
+	flib_acceptor *acceptor;
+	uint16_t port;
+
+	flib_tcpsocket *sock;
+};
+
+flib_ipcbase *flib_ipcbase_create() {
+	flib_ipcbase *result = flib_calloc(1, sizeof(flib_ipcbase));
+	flib_acceptor *acceptor = flib_acceptor_create(0);
+
+	if(!result || !acceptor) {
+		free(result);
+		flib_acceptor_close(acceptor);
+		return NULL;
+	}
+
+	result->acceptor = acceptor;
+	result->sock = NULL;
+	result->readBufferSize = 0;
+	result->port = flib_acceptor_listenport(acceptor);
+
+	flib_log_i("Started listening for IPC connections on port %u", (unsigned)result->port);
+	return result;
+}
+
+uint16_t flib_ipcbase_port(flib_ipcbase *ipc) {
+	if(log_badargs_if(ipc==NULL)) {
+		return 0;
+	}
+	return ipc->port;
+}
+
+void flib_ipcbase_destroy(flib_ipcbase *ipc) {
+	if(ipc) {
+		flib_acceptor_close(ipc->acceptor);
+		flib_socket_close(ipc->sock);
+		if(ipc->sock) {
+			flib_log_d("IPC connection closed.");
+		}
+		free(ipc);
+	}
+}
+
+IpcState flib_ipcbase_state(flib_ipcbase *ipc) {
+	if(log_badargs_if(ipc==NULL)) {
+		return IPC_NOT_CONNECTED;
+	} else if(ipc->sock) {
+		return IPC_CONNECTED;
+	} else if(ipc->acceptor) {
+		return IPC_LISTENING;
+	} else {
+		return IPC_NOT_CONNECTED;
+	}
+}
+
+static void receiveToBuffer(flib_ipcbase *ipc) {
+	if(ipc->sock) {
+		int size = flib_socket_nbrecv(ipc->sock, ipc->readBuffer+ipc->readBufferSize, sizeof(ipc->readBuffer)-ipc->readBufferSize);
+		if(size>=0) {
+			ipc->readBufferSize += size;
+		} else {
+			flib_log_d("IPC connection lost.");
+			flib_socket_close(ipc->sock);
+			ipc->sock = NULL;
+		}
+	}
+}
+
+static bool isMessageReady(flib_ipcbase *ipc) {
+	return ipc->readBufferSize >= ipc->readBuffer[0]+1;
+}
+
+static void logSentMsg(const uint8_t *data, size_t len) {
+	if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+		size_t msgStart = 0;
+		while(msgStart < len) {
+			uint8_t msglen = data[msgStart];
+			if(msgStart+msglen < len) {
+				flib_log_d("[IPC OUT][%03u]%*.*s",(unsigned)msglen, (unsigned)msglen, (unsigned)msglen, data+msgStart+1);
+			} else {
+				uint8_t msglen2 = len-msgStart-1;
+				flib_log_d("[IPC OUT][%03u/%03u]%*.*s",(unsigned)msglen2, (unsigned)msglen, (unsigned)msglen2, (unsigned)msglen2, data+msgStart+1);
+			}
+			msgStart += (uint8_t)data[msgStart]+1;
+		}
+	}
+}
+
+static void logRecvMsg(const uint8_t *data) {
+	if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+		uint8_t msglen = data[0];
+		flib_log_d("[IPC IN][%03u]%*.*s",(unsigned)msglen, (unsigned)msglen, (unsigned)msglen, data+1);
+	}
+}
+
+static void popFromReadBuffer(flib_ipcbase *ipc, uint8_t *outbuf, size_t size) {
+	memcpy(outbuf, ipc->readBuffer, size);
+	memmove(ipc->readBuffer, ipc->readBuffer+size, ipc->readBufferSize-size);
+	ipc->readBufferSize -= size;
+}
+
+int flib_ipcbase_recv_message(flib_ipcbase *ipc, void *data) {
+	if(log_badargs_if2(ipc==NULL, data==NULL)) {
+		return -1;
+	}
+
+	if(!isMessageReady(ipc)) {
+		receiveToBuffer(ipc);
+	}
+
+	if(isMessageReady(ipc)) {
+		int msgsize = ipc->readBuffer[0]+1;
+		popFromReadBuffer(ipc, data, msgsize);
+		logRecvMsg(data);
+		return msgsize;
+	} else if(!ipc->sock && ipc->readBufferSize>0) {
+		flib_log_w("Last message from engine data stream is incomplete (received %u of %u bytes)", (unsigned)ipc->readBufferSize, (unsigned)(ipc->readBuffer[0])+1);
+		ipc->readBufferSize = 0;
+		return -1;
+	} else {
+		return -1;
+	}
+}
+
+int flib_ipcbase_recv_map(flib_ipcbase *ipc, void *data) {
+	if(log_badargs_if2(ipc==NULL, data==NULL)) {
+		return -1;
+	}
+
+	receiveToBuffer(ipc);
+
+	if(ipc->readBufferSize >= IPCBASE_MAPMSG_BYTES) {
+		popFromReadBuffer(ipc, data, IPCBASE_MAPMSG_BYTES);
+		return IPCBASE_MAPMSG_BYTES;
+	} else {
+		return -1;
+	}
+}
+
+int flib_ipcbase_send_raw(flib_ipcbase *ipc, const void *data, size_t len) {
+	if(log_badargs_if2(ipc==NULL, data==NULL && len>0)
+			|| log_w_if(!ipc->sock, "flib_ipcbase_send_raw: Not connected.")) {
+		return -1;
+	}
+	if(flib_socket_send(ipc->sock, data, len) == len) {
+		logSentMsg(data, len);
+		return 0;
+	} else {
+		flib_log_w("Failed or incomplete ICP write: engine connection lost.");
+		flib_socket_close(ipc->sock);
+		ipc->sock = NULL;
+		return -1;
+	}
+}
+
+int flib_ipcbase_send_message(flib_ipcbase *ipc, void *data, size_t len) {
+	if(log_badargs_if3(ipc==NULL, data==NULL && len>0, len>255)) {
+		return -1;
+	}
+
+	uint8_t sendbuf[256];
+	sendbuf[0] = len;
+	memcpy(sendbuf+1, data, len);
+	return flib_ipcbase_send_raw(ipc, sendbuf, len+1);
+}
+
+void flib_ipcbase_accept(flib_ipcbase *ipc) {
+	if(!log_badargs_if(ipc==NULL) && !ipc->sock && ipc->acceptor) {
+		ipc->sock = flib_socket_accept(ipc->acceptor, true);
+		if(ipc->sock) {
+			flib_log_d("IPC connection accepted.");
+			flib_acceptor_close(ipc->acceptor);
+			ipc->acceptor = NULL;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/ipcbase.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,105 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * Low-level protocol support for the IPC connection to the engine.
+ */
+#ifndef IPCBASE_H_
+#define IPCBASE_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#define IPCBASE_MAPMSG_BYTES 4097
+
+typedef enum {IPC_NOT_CONNECTED, IPC_LISTENING, IPC_CONNECTED} IpcState;
+
+typedef struct _flib_ipcbase flib_ipcbase;
+
+/**
+ * Start an engine connection by listening on a random port. The selected port can
+ * be queried with flib_ipcbase_port and has to be passed to the engine.
+ *
+ * Returns NULL on error. Destroy the created object with flib_ipcbase_destroy.
+ *
+ * We stop accepting new connections once a connection has been established, so you
+ * need to create a new ipcbase in order to start a new connection.
+ */
+flib_ipcbase *flib_ipcbase_create();
+
+/**
+ * Return the listening port
+ */
+uint16_t flib_ipcbase_port(flib_ipcbase *ipc);
+
+/**
+ * Free resources and close sockets. NULL safe.
+ */
+void flib_ipcbase_destroy(flib_ipcbase *ipc);
+
+/**
+ * Determine the current connection state
+ */
+IpcState flib_ipcbase_state(flib_ipcbase *ipc);
+
+/**
+ * Receive a single message (up to 256 bytes) and copy it into the data buffer.
+ * Returns the length of the received message, a negative value if no message could
+ * be read.
+ *
+ * The first byte of a message is its content length, which is one less than the returned
+ * value.
+ *
+ * Note: When a connection is closed, you probably want to call this function until
+ * no further message is returned, to ensure you see all messages that were sent
+ * before the connection closed.
+ */
+int flib_ipcbase_recv_message(flib_ipcbase *ipc, void *data);
+
+/**
+ * Try to receive 4097 bytes. This is the size of the reply the engine sends
+ * when successfully queried for map data. The first 4096 bytes are a bit-packed
+ * twocolor image of the map (256x128), the last byte is the number of hogs that
+ * fit on the map.
+ */
+int flib_ipcbase_recv_map(flib_ipcbase *ipc, void *data);
+
+/**
+ * Blocking send bytes over the socket. No message framing will be added.
+ * Returns 0 on success.
+ */
+int flib_ipcbase_send_raw(flib_ipcbase *ipc, const void *data, size_t len);
+
+/**
+ * Write a single message (up to 255 bytes) to the engine. This call blocks until the
+ * message is completely written or the connection is closed or an error occurs.
+ *
+ * Calling this function in a state other than IPC_CONNECTED will fail immediately.
+ * Returns 0 on success.
+ */
+int flib_ipcbase_send_message(flib_ipcbase *ipc, void *data, size_t len);
+
+/**
+ * Try to accept a connection. Only has an effect in state IPC_LISTENING.
+ */
+void flib_ipcbase_accept(flib_ipcbase *ipc);
+
+#endif /* IPCBASE_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/ipcprotocol.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,316 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "ipcprotocol.h"
+#include "../util/util.h"
+#include "../util/logging.h"
+#include "../md5/md5.h"
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...) {
+	int result = -1;
+	if(!log_badargs_if2(vec==NULL, fmt==NULL)) {
+		// 1 byte size prefix, 255 bytes max message length, 1 0-byte for vsnprintf
+		char msgbuffer[257];
+
+		// Format the message, leaving one byte at the start for the length
+		va_list argp;
+		va_start(argp, fmt);
+		int msgSize = vsnprintf(msgbuffer+1, 256, fmt, argp);
+		va_end(argp);
+
+		if(!log_e_if(msgSize > 255, "Message too long (%u bytes)", (unsigned)msgSize)
+				&& !log_e_if(msgSize < 0, "printf error")) {
+			// Add the length prefix
+			((uint8_t*)msgbuffer)[0] = msgSize;
+
+			// Append it to the vector
+			result = flib_vector_append(vec, msgbuffer, msgSize+1);
+		}
+	}
+	return result;
+}
+
+int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview) {
+	int result = -1;
+	flib_vector *tempvector = flib_vector_create();
+	if(!log_badargs_if2(vec==NULL, map==NULL)) {
+		bool error = false;
+
+		if(map->mapgen == MAPGEN_NAMED) {
+			error |= log_e_if(!map->name, "Missing map name")
+					|| flib_ipc_append_message(tempvector, "emap %s", map->name);
+		}
+		if(!mappreview) {
+			error |= log_e_if(!map->theme, "Missing map theme")
+					|| flib_ipc_append_message(tempvector, "etheme %s", map->theme);
+		}
+		error |= flib_ipc_append_seed(tempvector, map->seed);
+		error |= flib_ipc_append_message(tempvector, "e$template_filter %i", map->templateFilter);
+		error |= flib_ipc_append_message(tempvector, "e$mapgen %i", map->mapgen);
+
+		if(map->mapgen == MAPGEN_MAZE) {
+			error |= flib_ipc_append_message(tempvector, "e$maze_size %i", map->mazeSize);
+		}
+		if(map->mapgen == MAPGEN_DRAWN) {
+			/*
+			 * We have to split the drawn map data into several edraw messages here because
+			 * it can be longer than the maximum message size.
+			 */
+			const char *edraw = "edraw ";
+			int edrawlen = strlen(edraw);
+			for(size_t offset=0; offset<map->drawDataSize; offset+=200) {
+				size_t bytesRemaining = map->drawDataSize-offset;
+				int fragmentsize = bytesRemaining < 200 ? bytesRemaining : 200;
+				uint8_t messagesize = edrawlen + fragmentsize;
+				error |= flib_vector_append(tempvector, &messagesize, 1);
+				error |= flib_vector_append(tempvector, edraw, edrawlen);
+				error |= flib_vector_append(tempvector, map->drawData+offset, fragmentsize);
+			}
+		}
+
+		if(!log_e_if(error, "Error generating map config")) {
+			// Message created, now we can copy everything.
+			flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector);
+			if(!flib_vector_append(vec, constbuf.data, constbuf.size)) {
+				result = 0;
+			}
+		}
+	}
+	flib_vector_destroy(tempvector);
+	return result;
+}
+
+int flib_ipc_append_seed(flib_vector *vec, const char *seed) {
+	if(log_badargs_if2(vec==NULL, seed==NULL)) {
+		return -1;
+	}
+	return flib_ipc_append_message(vec, "eseed %s", seed);
+}
+
+int flib_ipc_append_script(flib_vector *vec, const char *script) {
+	int result = -1;
+	if(!log_badargs_if2(vec==NULL, script==NULL)) {
+		result = flib_ipc_append_message(vec, "escript %s", script);
+	}
+	return result;
+}
+
+int flib_ipc_append_style(flib_vector *vec, const char *style) {
+	int result = -1;
+	char *copy = flib_strdupnull(style);
+	if(!log_badargs_if(vec==NULL) && copy) {
+		if(!strcmp("Normal", copy)) {
+			// "Normal" means no gametype script
+			// TODO if an empty script called "Normal" is added to the scripts directory this can be removed
+			result = 0;
+		} else {
+			size_t len = strlen(copy);
+			for(size_t i=0; i<len; i++) {
+				if(copy[i] == ' ') {
+					copy[i] = '_';
+				}
+			}
+
+			result = flib_ipc_append_message(vec, "escript %s%s.lua", MULTIPLAYER_SCRIPT_PATH, copy);
+		}
+	}
+	free(copy);
+	return result;
+}
+
+static uint32_t buildModFlags(const flib_scheme *scheme) {
+	uint32_t result = 0;
+	for(int i=0; i<flib_meta.modCount; i++) {
+		if(scheme->mods[i]) {
+			int bitmaskIndex = flib_meta.mods[i].bitmaskIndex;
+			result |= (UINT32_C(1) << bitmaskIndex);
+		}
+	}
+	return result;
+}
+
+int flib_ipc_append_gamescheme(flib_vector *vec, const flib_scheme *scheme) {
+	int result = -1;
+	flib_vector *tempvector = flib_vector_create();
+	if(!log_badargs_if2(vec==NULL, scheme==NULL) && tempvector) {
+		bool error = false;
+		error |= flib_ipc_append_message(tempvector, "e$gmflags %"PRIu32, buildModFlags(scheme));
+		for(int i=0; i<flib_meta.settingCount; i++) {
+			if(flib_meta.settings[i].engineCommand) {
+				int value = scheme->settings[i];
+				if(flib_meta.settings[i].maxMeansInfinity) {
+					value = value>=flib_meta.settings[i].max ? 9999 : value;
+				}
+				if(flib_meta.settings[i].times1000) {
+					value *= 1000;
+				}
+				error |= flib_ipc_append_message(tempvector, "%s %i", flib_meta.settings[i].engineCommand, value);
+			}
+		}
+
+		if(!error) {
+			// Message created, now we can copy everything.
+			flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector);
+			if(!flib_vector_append(vec, constbuf.data, constbuf.size)) {
+				result = 0;
+			}
+		}
+	}
+	flib_vector_destroy(tempvector);
+	return result;
+}
+
+static int appendWeaponSet(flib_vector *vec, flib_weaponset *set) {
+	return flib_ipc_append_message(vec, "eammloadt %s", set->loadout)
+		|| flib_ipc_append_message(vec, "eammprob %s", set->crateprob)
+		|| flib_ipc_append_message(vec, "eammdelay %s", set->delay)
+		|| flib_ipc_append_message(vec, "eammreinf %s", set->crateammo);
+}
+
+static void calculateMd5Hex(const char *in, char out[33]) {
+	md5_state_t md5state;
+	uint8_t md5bytes[16];
+	md5_init(&md5state);
+	md5_append(&md5state, (unsigned char*)in, strlen(in));
+	md5_finish(&md5state, md5bytes);
+	for(int i=0;i<sizeof(md5bytes); i++) {
+		snprintf(out+i*2, 3, "%02x", (unsigned)md5bytes[i]);
+	}
+}
+
+static int flib_ipc_append_addteam(flib_vector *vec, const flib_team *team, bool perHogAmmo, bool noAmmoStore) {
+	int result = -1;
+	flib_vector *tempvector = flib_vector_create();
+	if(!log_badargs_if2(vec==NULL, team==NULL) && tempvector) {
+		bool error = false;
+
+		if(!perHogAmmo && !noAmmoStore) {
+			error = error
+					|| appendWeaponSet(tempvector, team->hogs[0].weaponset)
+					|| flib_ipc_append_message(tempvector, "eammstore");
+		}
+
+		char md5Hex[33];
+		calculateMd5Hex(team->ownerName ? team->ownerName : "", md5Hex);
+		if(team->colorIndex<0 || team->colorIndex>=flib_teamcolor_count) {
+			flib_log_e("Color index out of bounds for team %s: %i", team->name, team->colorIndex);
+			error = true;
+		} else {
+			error |= flib_ipc_append_message(tempvector, "eaddteam %s %"PRIu32" %s", md5Hex, flib_teamcolors[team->colorIndex], team->name);
+		}
+
+		if(team->remoteDriven) {
+			error |= flib_ipc_append_message(tempvector, "erdriven");
+		}
+
+		error |= flib_ipc_append_message(tempvector, "egrave %s", team->grave);
+		error |= flib_ipc_append_message(tempvector, "efort %s", team->fort);
+		error |= flib_ipc_append_message(tempvector, "evoicepack %s", team->voicepack);
+		error |= flib_ipc_append_message(tempvector, "eflag %s", team->flag);
+
+		for(int i=0; i<team->bindingCount; i++) {
+			error |= flib_ipc_append_message(tempvector, "ebind %s %s", team->bindings[i].binding, team->bindings[i].action);
+		}
+
+		for(int i=0; i<team->hogsInGame; i++) {
+			if(perHogAmmo && !noAmmoStore) {
+				error |= appendWeaponSet(tempvector, team->hogs[i].weaponset);
+			}
+			error |= flib_ipc_append_message(tempvector, "eaddhh %i %i %s", team->hogs[i].difficulty, team->hogs[i].initialHealth, team->hogs[i].name);
+			error |= flib_ipc_append_message(tempvector, "ehat %s", team->hogs[i].hat);
+		}
+
+		if(!error) {
+			// Message created, now we can copy everything.
+			flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector);
+			if(!flib_vector_append(vec, constbuf.data, constbuf.size)) {
+				result = 0;
+			}
+		}
+	}
+	flib_vector_destroy(tempvector);
+	return result;
+}
+
+int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame) {
+	int result = -1;
+	flib_vector *tempvector = flib_vector_create();
+	if(!log_badargs_if2(vec==NULL, setup==NULL) && tempvector) {
+		bool error = false;
+		bool perHogAmmo = false;
+		bool sharedAmmo = false;
+
+		error |= flib_ipc_append_message(vec, netgame ? "TN" : "TL");
+		if(setup->map) {
+			error |= flib_ipc_append_mapconf(tempvector, setup->map, false);
+		}
+		if(setup->style) {
+			error |= flib_ipc_append_style(tempvector, setup->style);
+		}
+		if(setup->gamescheme) {
+			error |= flib_ipc_append_gamescheme(tempvector, setup->gamescheme);
+			sharedAmmo = flib_scheme_get_mod(setup->gamescheme, "sharedammo");
+			// Shared ammo has priority over per-hog ammo
+			perHogAmmo = !sharedAmmo && flib_scheme_get_mod(setup->gamescheme, "perhogammo");
+		}
+		if(setup->teamlist->teams && setup->teamlist->teamCount>0) {
+			int *clanColors = flib_calloc(setup->teamlist->teamCount, sizeof(int));
+			if(!clanColors) {
+				error = true;
+			} else {
+				int clanCount = 0;
+				for(int i=0; !error && i<setup->teamlist->teamCount; i++) {
+					flib_team *team = setup->teamlist->teams[i];
+					// Find the clan index of this team (clans are identified by color).
+					bool newClan = false;
+					int clan = 0;
+					while(clan<clanCount && clanColors[clan] != team->colorIndex) {
+						clan++;
+					}
+					if(clan==clanCount) {
+						newClan = true;
+						clanCount++;
+						clanColors[clan] = team->colorIndex;
+					}
+
+					// If shared ammo is active, only add an ammo store for the first team in each clan.
+					bool noAmmoStore = sharedAmmo&&!newClan;
+					error |= flib_ipc_append_addteam(tempvector, setup->teamlist->teams[i], perHogAmmo, noAmmoStore);
+				}
+			}
+			free(clanColors);
+		}
+		error |= flib_ipc_append_message(tempvector, "!");
+
+		if(!error) {
+			// Message created, now we can copy everything.
+			flib_constbuffer constbuf = flib_vector_as_constbuffer(tempvector);
+			if(!flib_vector_append(vec, constbuf.data, constbuf.size)) {
+				result = 0;
+			}
+		}
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/ipcprotocol.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,93 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef IPCPROTOCOL_H_
+#define IPCPROTOCOL_H_
+
+#include "../util/buffer.h"
+#include "../model/map.h"
+#include "../model/team.h"
+#include "../model/scheme.h"
+#include "../model/gamesetup.h"
+
+#include <stdbool.h>
+
+/**
+ * Create a message in the IPC protocol format and add it to
+ * the vector. Use a format string and extra parameters as with printf.
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_message(flib_vector *vec, const char *fmt, ...);
+
+/**
+ * Append IPC messages to the buffer that configure the engine for
+ * this map.
+ *
+ * Unfortunately the engine needs a slightly different configuration
+ * for generating a map preview.
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_mapconf(flib_vector *vec, const flib_map *map, bool mappreview);
+
+/**
+ * Append a seed message to the buffer.
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_seed(flib_vector *vec, const char *seed);
+
+/**
+ * Append a script to the buffer (e.g. "Missions/Training/Basic_Training_-_Bazooka.lua")
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_script(flib_vector *vec, const char *script);
+
+/**
+ * Append a game style to the buffer. (e.g. "Capture the Flag")
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_style(flib_vector *vec, const char *style);
+
+/**
+ * Append the game scheme to the buffer.
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_gamescheme(flib_vector *vec, const flib_scheme *scheme);
+
+/**
+ * Append the entire game config to the buffer (including the final "!" that marks the
+ * end of configuration data for the engine)
+ *
+ * Returns nonzero if something goes wrong. In that case the buffer
+ * contents are unaffected.
+ */
+int flib_ipc_append_fullconfig(flib_vector *vec, const flib_gamesetup *setup, bool netgame);
+
+#endif /* IPCPROTOCOL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/mapconn.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,196 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "mapconn.h"
+#include "ipcbase.h"
+#include "ipcprotocol.h"
+
+#include "../util/logging.h"
+#include "../util/buffer.h"
+#include "../util/util.h"
+
+#include <stdlib.h>
+
+typedef enum {
+	AWAIT_CONNECTION,
+	AWAIT_REPLY,
+	AWAIT_CLOSE,
+	FINISHED
+} mapconn_state;
+
+struct _flib_mapconn {
+	uint8_t mapBuffer[IPCBASE_MAPMSG_BYTES];
+	flib_ipcbase *ipcBase;
+	flib_vector *configBuffer;
+
+	mapconn_state progress;
+
+	void (*onSuccessCb)(void*, const uint8_t*, int);
+	void *onSuccessCtx;
+
+	void (*onFailureCb)(void*, const char*);
+	void *onFailureCtx;
+
+	bool running;
+	bool destroyRequested;
+};
+
+static void noop_handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {}
+static void noop_handleFailure(void *context, const char *errormessage) {}
+
+static void clearCallbacks(flib_mapconn *conn) {
+	conn->onSuccessCb = &noop_handleSuccess;
+	conn->onFailureCb = &noop_handleFailure;
+}
+
+static flib_vector *createConfigBuffer(const flib_map *mapdesc) {
+	flib_vector *result = NULL;
+	flib_vector *tempbuffer = flib_vector_create();
+	if(tempbuffer) {
+		bool error = false;
+		error |= flib_ipc_append_mapconf(tempbuffer, mapdesc, true);
+		error |= flib_ipc_append_message(tempbuffer, "!");
+		if(!error) {
+			result = tempbuffer;
+			tempbuffer = NULL;
+		}
+	}
+	flib_vector_destroy(tempbuffer);
+	return result;
+}
+
+flib_mapconn *flib_mapconn_create(const flib_map *mapdesc) {
+	if(log_badargs_if(mapdesc==NULL)) {
+		return NULL;
+	}
+	flib_mapconn *result = NULL;
+	flib_mapconn *tempConn = flib_calloc(1, sizeof(flib_mapconn));
+	if(tempConn) {
+		tempConn->ipcBase = flib_ipcbase_create();
+		tempConn->configBuffer = createConfigBuffer(mapdesc);
+		if(tempConn->ipcBase && tempConn->configBuffer) {
+			tempConn->progress = AWAIT_CONNECTION;
+			clearCallbacks(tempConn);
+			result = tempConn;
+			tempConn = NULL;
+		}
+	}
+	flib_mapconn_destroy(tempConn);
+	return result;
+}
+
+void flib_mapconn_destroy(flib_mapconn *conn) {
+	if(conn) {
+		if(conn->running) {
+			/*
+			 * The function was called from a callback, so the tick function is still running
+			 * and we delay the actual destruction. We ensure no further callbacks will be
+			 * sent to prevent surprises.
+			 */
+			clearCallbacks(conn);
+			conn->destroyRequested = true;
+		} else {
+			flib_ipcbase_destroy(conn->ipcBase);
+			flib_vector_destroy(conn->configBuffer);
+			free(conn);
+		}
+	}
+}
+
+int flib_mapconn_getport(flib_mapconn *conn) {
+	if(log_badargs_if(conn==NULL)) {
+		return 0;
+	}
+	return flib_ipcbase_port(conn->ipcBase);
+}
+
+void flib_mapconn_onSuccess(flib_mapconn *conn, void (*callback)(void* context, const uint8_t *bitmap, int numHedgehogs), void *context) {
+	if(!log_badargs_if(conn==NULL)) {
+		conn->onSuccessCb = callback ? callback : &noop_handleSuccess;
+		conn->onSuccessCtx = context;
+	}
+}
+
+void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context) {
+	if(!log_badargs_if(conn==NULL)) {
+		conn->onFailureCb = callback ? callback : &noop_handleFailure;
+		conn->onFailureCtx = context;
+	}
+}
+
+static void flib_mapconn_wrappedtick(flib_mapconn *conn) {
+	if(conn->progress == AWAIT_CONNECTION) {
+		flib_ipcbase_accept(conn->ipcBase);
+		switch(flib_ipcbase_state(conn->ipcBase)) {
+		case IPC_CONNECTED:
+			{
+				flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer);
+				if(flib_ipcbase_send_raw(conn->ipcBase, configBuffer.data, configBuffer.size)) {
+					conn->progress = FINISHED;
+					conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine.");
+					return;
+				} else {
+					conn->progress = AWAIT_REPLY;
+				}
+			}
+			break;
+		case IPC_NOT_CONNECTED:
+			conn->progress = FINISHED;
+			conn->onFailureCb(conn->onFailureCtx, "Engine connection closed unexpectedly.");
+			return;
+		default:
+			break;
+		}
+	}
+
+	if(conn->progress == AWAIT_REPLY) {
+		if(flib_ipcbase_recv_map(conn->ipcBase, conn->mapBuffer) >= 0) {
+			conn->progress = AWAIT_CLOSE;
+		} else if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) {
+			conn->progress = FINISHED;
+			conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly.");
+			return;
+		}
+	}
+
+	if(conn->progress == AWAIT_CLOSE) {
+		// Just do throwaway reads so we find out when the engine disconnects
+		uint8_t buf[256];
+		flib_ipcbase_recv_message(conn->ipcBase, buf);
+		if(flib_ipcbase_state(conn->ipcBase) != IPC_CONNECTED) {
+			conn->progress = FINISHED;
+			conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCBASE_MAPMSG_BYTES-1]);
+			return;
+		}
+	}
+}
+
+void flib_mapconn_tick(flib_mapconn *conn) {
+	if(!log_badargs_if(conn==NULL)
+			&& !log_w_if(conn->running, "Call to flib_mapconn_tick from a callback")
+			&& !log_w_if(conn->progress == FINISHED, "We are already done.")) {
+		conn->running = true;
+		flib_mapconn_wrappedtick(conn);
+		conn->running = false;
+
+		if(conn->destroyRequested) {
+			flib_mapconn_destroy(conn);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/ipc/mapconn.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,116 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Functions for querying a map preview from the engine, which includes both a two-color image
+ * and the number of hogs this map is suitable for.
+ *
+ * The general usage is to first create a mapconn object by calling flib_mapconn_create.
+ * That will cause the frontlib to listen on a random port which can be queried using
+ * flib_mapconn_getport(). You should also register your callback functions right at the start
+ * to ensure you don't miss any callbacks.
+ *
+ * Next, start the engine (that part is up to you) with the appropriate command line arguments
+ * for a map preview request.
+ *
+ * In order to allow the mapconn to run, you should regularly call flib_mapconn_tick(), which
+ * performs network I/O and calls your callbacks if the map has been generated or an error
+ * has occurred. Once either the onSuccess or onFailure callback is called, you should destroy
+ * the mapconn and stop calling tick().
+ */
+
+#ifndef IPC_MAPCONN_H_
+#define IPC_MAPCONN_H_
+
+#include "../model/map.h"
+
+#include <stdint.h>
+
+#define MAPIMAGE_WIDTH 256
+#define MAPIMAGE_HEIGHT 128
+#define MAPIMAGE_BYTES (MAPIMAGE_WIDTH/8*MAPIMAGE_HEIGHT)
+
+typedef struct _flib_mapconn flib_mapconn;
+
+/**
+ * Start a new map rendering connection (mapconn). This means a listening socket
+ * will be started on a random unused port, waiting for a connection from the
+ * engine process. Once this connection is established, the required information
+ * will be sent to the engine, and the reply is read.
+ *
+ * The map must be a regular, maze or drawn map - for a preview of a named map,
+ * use the preview images in the map's directory, and for the hog count read the
+ * map information (e.g. using flib_mapcfg_read).
+ *
+ * No NULL parameters allowed, returns NULL on failure.
+ * Use flib_mapconn_destroy to free the returned object.
+ */
+flib_mapconn *flib_mapconn_create(const flib_map *mapdesc);
+
+/**
+ * Destroy the mapconn object. Passing NULL is allowed and does nothing.
+ * flib_mapconn_destroy may be called from inside a callback function.
+ */
+void flib_mapconn_destroy(flib_mapconn *conn);
+
+/**
+ * Returns the port on which the mapconn is listening. Only fails if you
+ * pass NULL (not allowed), in that case 0 is returned.
+ */
+int flib_mapconn_getport(flib_mapconn *conn);
+
+/**
+ * Set a callback which will receive the rendered map if the rendering succeeds.
+ *
+ * Expected callback signature:
+ * void handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs)
+ *
+ * The context passed to the callback is the same pointer you provided when
+ * registering the callback. bitmap is a pointer to a buffer of size MAPIMAGE_BYTES
+ * containing a bit-packed image of size MAPIMAGE_WIDTH * MAPIMAGE_HEIGHT.
+ * numHedgehogs is the number of hogs that fit on this map.
+ *
+ * The bitmap pointer passed to the callback belongs to the caller,
+ * so it should not be stored elsewhere. Note that it remains valid
+ * inside the callback method even if flib_mapconn_destroy is called.
+ */
+void flib_mapconn_onSuccess(flib_mapconn *conn, void (*callback)(void* context, const uint8_t *bitmap, int numHedgehogs), void *context);
+
+/**
+ * Set a callback which will receive an error message if rendering fails.
+ *
+ * Expected callback signature:
+ * void handleFailure(void *context, const char *errormessage)
+ *
+ * The context passed to the callback is the same pointer you provided when
+ * registering the callback.
+ *
+ * The error message passed to the callback belongs to the caller,
+ * so it should not be stored elsewhere. Note that it remains valid
+ * inside the callback method even if flib_mapconn_destroy is called.
+ */
+void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context);
+
+/**
+ * Perform I/O operations and call callbacks if something interesting happens.
+ * Should be called regularly.
+ */
+void flib_mapconn_tick(flib_mapconn *conn);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/md5/md5.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,381 @@
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+	either statically or dynamically; added missing #include <string.h>
+	in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+	type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+	unsigned in ANSI C, signed in traditional"; made test program
+	self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+	a = pms->abcd[0], b = pms->abcd[1],
+	c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+	/*
+	 * Determine dynamically whether this is a big-endian or
+	 * little-endian machine, since we can use a more efficient
+	 * algorithm on the latter.
+	 */
+	static const int w = 1;
+
+	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0		/* little-endian */
+	{
+	    /*
+	     * On little-endian machines, we can process properly aligned
+	     * data without copying it.
+	     */
+	    if (!((data - (const md5_byte_t *)0) & 3)) {
+		/* data are properly aligned */
+		X = (const md5_word_t *)data;
+	    } else {
+		/* not aligned */
+		memcpy(xbuf, data, 64);
+		X = xbuf;
+	    }
+	}
+#endif
+#if BYTE_ORDER == 0
+	else			/* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0		/* big-endian */
+	{
+	    /*
+	     * On big-endian machines, we must arrange the bytes in the
+	     * right order.
+	     */
+	    const md5_byte_t *xp = data;
+	    int i;
+
+#  if BYTE_ORDER == 0
+	    X = xbuf;		/* (dynamic only) */
+#  else
+#    define xbuf X		/* (static only) */
+#  endif
+	    for (i = 0; i < 16; ++i, xp += 4)
+		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+	}
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+	return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+	pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+	memcpy(pms->buf + offset, p, copy);
+	if (offset + copy < 64)
+	    return;
+	p += copy;
+	left -= copy;
+	md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+	md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+	memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/md5/md5.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+	references to Ghostscript; clarified derivation from RFC 1321;
+	now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+	added conditionalization for C++ compilation from Martin
+	Purschke <purschke@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];	/* message length in bits, lsw first */
+    md5_word_t abcd[4];		/* digest buffer */
+    md5_byte_t buf[64];		/* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/gamesetup.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,55 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "gamesetup.h"
+#include "../util/util.h"
+
+#include <stdlib.h>
+
+void flib_gamesetup_destroy(flib_gamesetup *gamesetup) {
+	if(gamesetup) {
+		free(gamesetup->style);
+		flib_scheme_destroy(gamesetup->gamescheme);
+		flib_map_destroy(gamesetup->map);
+		flib_teamlist_destroy(gamesetup->teamlist);
+		free(gamesetup);
+	}
+}
+
+flib_gamesetup *flib_gamesetup_copy(const flib_gamesetup *setup) {
+	if(!setup) {
+		return NULL;
+	}
+
+	flib_gamesetup *result = flib_calloc(1, sizeof(flib_gamesetup));
+	if(result) {
+		result->style = flib_strdupnull(setup->style);
+		result->gamescheme = flib_scheme_copy(setup->gamescheme);
+		result->map = flib_map_copy(setup->map);
+		result->teamlist = flib_teamlist_copy(setup->teamlist);
+		if((setup->style && !result->style)
+				|| (setup->gamescheme && !result->gamescheme)
+				|| (setup->map && !result->map)
+				|| (setup->teamlist && !result->teamlist)) {
+			flib_gamesetup_destroy(result);
+			result = NULL;
+		}
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/gamesetup.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,47 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * A complete game configuration that contains all settings the engine needs to start a
+ * local or networked game.
+ */
+
+#ifndef MODEL_GAMESETUP_H_
+#define MODEL_GAMESETUP_H_
+
+#include "scheme.h"
+#include "weapon.h"
+#include "map.h"
+#include "teamlist.h"
+
+typedef struct {
+    char *style;				// e.g. "Capture the Flag"
+    flib_scheme *gamescheme;
+    flib_map *map;
+	flib_teamlist *teamlist;
+} flib_gamesetup;
+
+void flib_gamesetup_destroy(flib_gamesetup *gamesetup);
+
+/**
+ * Deep-copy of the flib_gamesetup.
+ */
+flib_gamesetup *flib_gamesetup_copy(const flib_gamesetup *gamesetup);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/map.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,110 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "map.h"
+
+#include "../util/inihelper.h"
+#include "../util/util.h"
+#include "../util/logging.h"
+
+#include <stdlib.h>
+
+flib_map *flib_map_create_regular(const char *seed, const char *theme, int templateFilter) {
+	if(log_badargs_if2(seed==NULL, theme==NULL)) {
+		return NULL;
+	}
+	flib_map newmap = {0};
+	newmap.mapgen = MAPGEN_REGULAR;
+	newmap.name = "+rnd+";
+	newmap.seed = (char*)seed;
+	newmap.theme = (char*)theme;
+	newmap.templateFilter = templateFilter;
+	return flib_map_copy(&newmap);
+}
+
+flib_map *flib_map_create_maze(const char *seed, const char *theme, int mazeSize) {
+	if(log_badargs_if2(seed==NULL, theme==NULL)) {
+		return NULL;
+	}
+	flib_map newmap = {0};
+	newmap.mapgen = MAPGEN_MAZE;
+	newmap.name = "+maze+";
+	newmap.seed = (char*)seed;
+	newmap.theme = (char*)theme;
+	newmap.mazeSize = mazeSize;
+	return flib_map_copy(&newmap);
+}
+
+flib_map *flib_map_create_named(const char *seed, const char *name) {
+	if(log_badargs_if2(seed==NULL, name==NULL)) {
+		return NULL;
+	}
+	flib_map newmap = {0};
+	newmap.mapgen = MAPGEN_NAMED;
+	newmap.name = (char*)name;
+	newmap.seed = (char*)seed;
+	return flib_map_copy(&newmap);
+}
+
+flib_map *flib_map_create_drawn(const char *seed, const char *theme, const uint8_t *drawData, size_t drawDataSize) {
+	if(log_badargs_if3(seed==NULL, theme==NULL, drawData==NULL)) {
+		return NULL;
+	}
+	flib_map newmap = {0};
+	newmap.mapgen = MAPGEN_DRAWN;
+	newmap.name = "+drawn+";
+	newmap.seed = (char*)seed;
+	newmap.theme = (char*)theme;
+	newmap.drawData = (uint8_t*) drawData;
+	newmap.drawDataSize = drawDataSize;
+	return flib_map_copy(&newmap);
+}
+
+flib_map *flib_map_copy(const flib_map *map) {
+	flib_map *result = NULL;
+	if(map) {
+		flib_map *newmap = flib_calloc(1, sizeof(flib_map));
+		if(newmap) {
+			newmap->mapgen = map->mapgen;
+			newmap->drawDataSize = map->drawDataSize;
+			newmap->drawData = flib_bufdupnull(map->drawData, map->drawDataSize);
+			newmap->mazeSize = map->mazeSize;
+			newmap->name = flib_strdupnull(map->name);
+			newmap->seed = flib_strdupnull(map->seed);
+			newmap->templateFilter = map->templateFilter;
+			newmap->theme = flib_strdupnull(map->theme);
+			if((newmap->drawData || !map->drawData) && (newmap->name || !map->name) && (newmap->seed || !map->seed) && (newmap->theme || !map->theme)) {
+				result = newmap;
+				newmap = NULL;
+			}
+		}
+		flib_map_destroy(newmap);
+	}
+	return result;
+}
+
+void flib_map_destroy(flib_map *map) {
+	if(map) {
+		free(map->seed);
+		free(map->drawData);
+		free(map->name);
+		free(map->theme);
+		free(map);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/map.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,114 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef MODEL_MAP_H_
+#define MODEL_MAP_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define MAPGEN_REGULAR 0
+#define MAPGEN_MAZE 1
+#define MAPGEN_DRAWN 2
+#define MAPGEN_NAMED 3
+
+#define TEMPLATEFILTER_ALL 0
+#define TEMPLATEFILTER_SMALL 1
+#define TEMPLATEFILTER_MEDIUM 2
+#define TEMPLATEFILTER_LARGE 3
+#define TEMPLATEFILTER_CAVERN 4
+#define TEMPLATEFILTER_WACKY 5
+
+#define MAZE_SIZE_SMALL_TUNNELS 0
+#define MAZE_SIZE_MEDIUM_TUNNELS 1
+#define MAZE_SIZE_LARGE_TUNNELS 2
+#define MAZE_SIZE_SMALL_ISLANDS 3
+#define MAZE_SIZE_MEDIUM_ISLANDS 4
+#define MAZE_SIZE_LARGE_ISLANDS 5
+
+/**
+ * Data structure for defining a map. This contains the whole recipe to
+ * exactly recreate a particular map.
+ *
+ * The required fields depend on the map generator, see the comments
+ * at the struct for details.
+ */
+typedef struct {
+	int mapgen;				// Always one of the MAPGEN_ constants
+	char *name;				// The name of the map for MAPGEN_NAMED (e.g. "Cogs"), otherwise one of "+rnd+", "+maze+" or "+drawn+".
+	char *seed;				// Used for all maps. This is a random seed for all (non-AI) entropy in the round. Typically a random UUID, but can be any string.
+	char *theme;			// Used for all maps. This is the name of a directory in Data/Themes (e.g. "Beach")
+	uint8_t *drawData;		// Used for MAPGEN_DRAWN
+	size_t drawDataSize;	// Used for MAPGEN_DRAWN
+	int templateFilter;		// Used for MAPGEN_REGULAR. One of the TEMPLATEFILTER_xxx constants.
+	int mazeSize;			// Used for MAPGEN_MAZE. One of the MAZE_SIZE_xxx constants.
+} flib_map;
+
+/**
+ * Create a generated map. theme should be the name of a
+ * directory in "Themes" and templateFilter should be one of the
+ * TEMPLATEFILTER_* constants, but this is not checked before
+ * passing it to the engine.
+ *
+ * Use flib_map_destroy to free the returned object.
+ * No NULL parameters allowed, returns NULL on failure.
+ */
+flib_map *flib_map_create_regular(const char *seed, const char *theme, int templateFilter);
+
+/**
+ * Create a generated maze-type map. theme should be the name of a
+ * directory in "Themes" and mazeSize should be one of the
+ * MAZE_SIZE_* constants, but this is not checked before
+ * passing it to the engine.
+ *
+ * Use flib_map_destroy to free the returned object.
+ * No NULL parameters allowed, returns NULL on failure.
+ */
+flib_map *flib_map_create_maze(const char *seed, const char *theme, int mazeSize);
+
+/**
+ * Create a map from the Maps-Directory. name should be the name of a
+ * directory in "Maps", but this is not checked before
+ * passing it to the engine. If this is a mission, the corresponding
+ * script is used automatically.
+ *
+ * Use flib_map_destroy to free the returned object.
+ * No NULL parameters allowed, returns NULL on failure.
+ */
+flib_map *flib_map_create_named(const char *seed, const char *name);
+
+/**
+ * Create a hand-drawn map. Use flib_map_destroy to free the returned object.
+ * No NULL parameters allowed, returns NULL on failure.
+ */
+flib_map *flib_map_create_drawn(const char *seed, const char *theme, const uint8_t *drawData, size_t drawDataSize);
+
+/**
+ * Create a deep copy of the map. Returns NULL on failure or if NULL was passed.
+ */
+flib_map *flib_map_copy(const flib_map *map);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
+ */
+void flib_map_destroy(flib_map *map);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/mapcfg.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,64 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "mapcfg.h"
+
+#include "../util/util.h"
+#include "../util/logging.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+void removeNewline(char *str) {
+	for(;*str;str++) {
+		if(*str=='\n' || *str=='\r') {
+			*str = 0;
+			return;
+		}
+	}
+}
+
+int flib_mapcfg_read(const char *dataDirPath, const char *mapname, flib_mapcfg *out) {
+	int result = -1;
+	if(!log_badargs_if4(dataDirPath==NULL, mapname==NULL, out==NULL, flib_contains_dir_separator(mapname))) {
+		char *path = flib_asprintf("%sMaps/%s/map.cfg", dataDirPath, mapname);
+		if(path) {
+			FILE *file = fopen(path, "rb");
+			if(!log_e_if(!file, "Unable to open map config file %s", path)) {
+				if(!log_e_if(!fgets(out->theme, sizeof(out->theme), file), "Error reading theme from %s", path)) {
+					removeNewline(out->theme);
+					char buf[64];
+					if(fgets(buf, sizeof(buf), file)) {
+						removeNewline(buf);
+						errno = 0;
+						out->hogLimit = strtol(buf, NULL, 10);
+						result = !log_e_if(errno, "Invalid hoglimit in %s: %i", path, buf);
+					} else {
+						result = 0;
+					}
+				}
+				fclose(file);
+			}
+		}
+		free(path);
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/mapcfg.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,38 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * Data structure and functions for accessing the map.cfg of named maps.
+ */
+
+#ifndef MAPCFG_H_
+#define MAPCFG_H_
+
+typedef struct {
+	char theme[256];
+	int hogLimit;
+} flib_mapcfg;
+
+/**
+ * Read the map configuration for the map with this name.
+ * The dataDirPath must end in a path separator.
+ */
+int flib_mapcfg_read(const char *dataDirPath, const char *mapname, flib_mapcfg *out);
+
+#endif /* MAPCFG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/room.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,34 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "room.h"
+#include "../util/logging.h"
+
+#include <stdlib.h>
+
+void flib_room_destroy(flib_room *room) {
+	if(room) {
+		free(room->map);
+		free(room->name);
+		free(room->owner);
+		free(room->scheme);
+		free(room->weapons);
+		free(room);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/room.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,42 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Models the room information for the lobby roomlist.
+ */
+
+#ifndef ROOM_H_
+#define ROOM_H_
+
+#include <stdbool.h>
+
+typedef struct {
+    bool inProgress;	// true if the game is running
+    char *name;
+    int playerCount;
+    int teamCount;
+    char *owner;
+    char *map;			// This is either a map name, or one of +rnd+, +maze+ or +drawn+.
+    char *scheme;
+    char *weapons;
+} flib_room;
+
+void flib_room_destroy();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/scheme.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,95 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "scheme.h"
+
+#include "../util/inihelper.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+flib_scheme *flib_scheme_create(const char *schemeName) {
+	flib_scheme *result = flib_calloc(1, sizeof(flib_scheme));
+	if(log_badargs_if(schemeName==NULL) || result==NULL) {
+		return NULL;
+	}
+
+	result->name = flib_strdupnull(schemeName);
+	result->mods = flib_calloc(flib_meta.modCount, sizeof(*result->mods));
+	result->settings = flib_calloc(flib_meta.settingCount, sizeof(*result->settings));
+
+	if(!result->mods || !result->settings || !result->name) {
+		flib_scheme_destroy(result);
+		return NULL;
+	}
+
+	for(int i=0; i<flib_meta.settingCount; i++) {
+		result->settings[i] = flib_meta.settings[i].def;
+	}
+	return result;
+}
+
+flib_scheme *flib_scheme_copy(const flib_scheme *scheme) {
+	flib_scheme *result = NULL;
+	if(scheme) {
+		result = flib_scheme_create(scheme->name);
+		if(result) {
+			memcpy(result->mods, scheme->mods, flib_meta.modCount * sizeof(*scheme->mods));
+			memcpy(result->settings, scheme->settings, flib_meta.settingCount * sizeof(*scheme->settings));
+		}
+	}
+	return result;
+}
+
+void flib_scheme_destroy(flib_scheme* scheme) {
+	if(scheme) {
+		free(scheme->mods);
+		free(scheme->settings);
+		free(scheme->name);
+		free(scheme);
+	}
+}
+
+bool flib_scheme_get_mod(const flib_scheme *scheme, const char *name) {
+	if(!log_badargs_if2(scheme==NULL, name==NULL)) {
+		for(int i=0; i<flib_meta.modCount; i++) {
+			if(!strcmp(flib_meta.mods[i].name, name)) {
+				return scheme->mods[i];
+			}
+		}
+		flib_log_e("Unable to find game mod %s", name);
+	}
+	return false;
+}
+
+int flib_scheme_get_setting(const flib_scheme *scheme, const char *name, int def) {
+	if(!log_badargs_if2(scheme==NULL, name==NULL)) {
+		for(int i=0; i<flib_meta.settingCount; i++) {
+			if(!strcmp(flib_meta.settings[i].name, name)) {
+				return scheme->settings[i];
+			}
+		}
+		flib_log_e("Unable to find game setting %s", name);
+	}
+	return def;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/scheme.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,72 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Data structures for game scheme information.
+ *
+ * The scheme consists of settings (integers) and mods (booleans). These are not fixed, but
+ * described in a "metascheme", which describes how each setting and mod is sent to the
+ * engine, and in which order they appear in the network protocol. The metascheme is defined
+ * in hwconsts.h
+ */
+
+#ifndef SCHEME_H_
+#define SCHEME_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "../hwconsts.h"
+
+/**
+ * The settings and mods arrays have the same number and order of elements
+ * as the corresponding arrays in the metascheme.
+ */
+typedef struct {
+    char *name;
+    int *settings;
+    bool *mods;
+} flib_scheme;
+
+/**
+ * Create a new configuration with everything set to default or false
+ * Returns NULL on error.
+ */
+flib_scheme *flib_scheme_create(const char *schemeName);
+
+/**
+ * Create a copy of the scheme. Returns NULL on error or if NULL was passed.
+ */
+flib_scheme *flib_scheme_copy(const flib_scheme *scheme);
+
+/**
+ * Decrease the reference count of the object and free it if this was the last reference.
+ */
+void flib_scheme_destroy(flib_scheme* scheme);
+
+/**
+ * Retrieve a mod setting by its name. If the mod is not found, logs an error and returns false.
+ */
+bool flib_scheme_get_mod(const flib_scheme *scheme, const char *name);
+
+/**
+ * Retrieve a game setting by its name. If the setting is not found, logs an error and returns def.
+ */
+int flib_scheme_get_setting(const flib_scheme *scheme, const char *name, int def);
+
+#endif /* SCHEME_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/schemelist.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,216 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "schemelist.h"
+
+#include "../util/inihelper.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../util/list.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+static char *makePrefixedName(int schemeIndex, const char *settingName) {
+	return flib_asprintf("%i\\%s", schemeIndex, settingName);
+}
+
+static int readSettingsFromIni(flib_ini *ini, flib_scheme *scheme, int index) {
+	bool error = false;
+	for(int i=0; i<flib_meta.settingCount && !error; i++) {
+		char *key = makePrefixedName(index, flib_meta.settings[i].name);
+		if(!key) {
+			error = true;
+		} else if(flib_ini_get_int_opt(ini, &scheme->settings[i], key, flib_meta.settings[i].def)) {
+			flib_log_e("Error reading setting %s in schemes file.", key);
+			error = true;
+		}
+		free(key);
+	}
+	return error;
+}
+
+static int readModsFromIni(flib_ini *ini, flib_scheme *scheme, int index) {
+	bool error = false;
+	for(int i=0; i<flib_meta.modCount && !error; i++) {
+		char *key = makePrefixedName(index, flib_meta.mods[i].name);
+		if(!key) {
+			error = true;
+		} else if(flib_ini_get_bool_opt(ini, &scheme->mods[i], key, false)) {
+			flib_log_e("Error reading mod %s in schemes file.", key);
+			error = true;
+		}
+		free(key);
+	}
+	return error;
+}
+
+static flib_scheme *readSchemeFromIni(flib_ini *ini, int index) {
+	flib_scheme *result = NULL;
+	char *schemeNameKey = makePrefixedName(index+1, "name");
+	if(schemeNameKey) {
+		char *schemeName = NULL;
+		if(!flib_ini_get_str_opt(ini, &schemeName, schemeNameKey, "Unnamed")) {
+			flib_scheme *tmpScheme = flib_scheme_create(schemeName);
+			if(tmpScheme) {
+				if(!readSettingsFromIni(ini, tmpScheme, index) && !readModsFromIni(ini, tmpScheme, index)) {
+					result = tmpScheme;
+					tmpScheme = NULL;
+				}
+			}
+			flib_scheme_destroy(tmpScheme);
+		}
+		free(schemeName);
+	}
+	free(schemeNameKey);
+	return result;
+}
+
+static flib_schemelist *fromIniHandleError(flib_schemelist *result, flib_ini *ini) {
+	flib_ini_destroy(ini);
+	flib_schemelist_destroy(result);
+	return NULL;
+}
+
+flib_schemelist *flib_schemelist_from_ini(const char *filename) {
+	if(log_badargs_if(filename==NULL)) {
+		return NULL;
+	}
+
+	flib_schemelist *list = NULL;
+	flib_ini *ini = flib_ini_load(filename);
+	if(!ini || flib_ini_enter_section(ini, "schemes")) {
+		flib_log_e("Missing file or missing section \"schemes\" in file %s.", filename);
+		return fromIniHandleError(list, ini);
+	}
+
+	list = flib_schemelist_create();
+	if(!list) {
+		return fromIniHandleError(list, ini);
+	}
+
+	int schemeCount = 0;
+	if(flib_ini_get_int(ini, &schemeCount, "size")) {
+		flib_log_e("Missing or malformed scheme count in config file %s.", filename);
+		return fromIniHandleError(list, ini);
+	}
+
+	for(int i=0; i<schemeCount; i++) {
+		flib_scheme *scheme = readSchemeFromIni(ini, i);
+		if(!scheme || flib_schemelist_insert(list, scheme, i)) {
+			flib_scheme_destroy(scheme);
+			flib_log_e("Error reading scheme %i from config file %s.", i, filename);
+			return fromIniHandleError(list, ini);
+		}
+	}
+
+
+	flib_ini_destroy(ini);
+	return list;
+}
+
+static int writeSchemeToIni(const flib_scheme *scheme, flib_ini *ini, int index) {
+	bool error = false;
+
+	char *key = makePrefixedName(index+1, "name");
+	error |= !key || flib_ini_set_str(ini, key, scheme->name);
+	free(key);
+
+	for(int i=0; i<flib_meta.modCount && !error; i++) {
+		char *key = makePrefixedName(index+1, flib_meta.mods[i].name);
+		error |= !key || flib_ini_set_bool(ini, key, scheme->mods[i]);
+		free(key);
+	}
+
+	for(int i=0; i<flib_meta.settingCount && !error; i++) {
+		char *key = makePrefixedName(index+1, flib_meta.settings[i].name);
+		error |= !key || flib_ini_set_int(ini, key, scheme->settings[i]);
+		free(key);
+	}
+	return error;
+}
+
+int flib_schemelist_to_ini(const char *filename, const flib_schemelist *schemes) {
+	int result = -1;
+	if(!log_badargs_if2(filename==NULL, schemes==NULL)) {
+		flib_ini *ini = flib_ini_create(NULL);
+		if(ini && !flib_ini_create_section(ini, "schemes")) {
+			bool error = false;
+			error |= flib_ini_set_int(ini, "size", schemes->schemeCount);
+			for(int i=0; i<schemes->schemeCount && !error; i++) {
+				error |= writeSchemeToIni(schemes->schemes[i], ini, i);
+			}
+
+			if(!error) {
+				result = flib_ini_save(ini, filename);
+			}
+		}
+		flib_ini_destroy(ini);
+	}
+	return result;
+}
+
+flib_schemelist *flib_schemelist_create() {
+	return flib_calloc(1, sizeof(flib_schemelist));
+}
+
+void flib_schemelist_destroy(flib_schemelist *list) {
+	if(list) {
+		for(int i=0; i<list->schemeCount; i++) {
+			flib_scheme_destroy(list->schemes[i]);
+		}
+		free(list->schemes);
+		free(list);
+	}
+}
+
+flib_scheme *flib_schemelist_find(flib_schemelist *list, const char *name) {
+	if(!log_badargs_if2(list==NULL, name==NULL)) {
+		for(int i=0; i<list->schemeCount; i++) {
+			if(!strcmp(name, list->schemes[i]->name)) {
+				return list->schemes[i];
+			}
+		}
+	}
+	return NULL;
+}
+
+GENERATE_STATIC_LIST_INSERT(insertScheme, flib_scheme*)
+GENERATE_STATIC_LIST_DELETE(deleteScheme, flib_scheme*)
+
+int flib_schemelist_insert(flib_schemelist *list, flib_scheme *cfg, int pos) {
+	if(!log_badargs_if2(list==NULL, cfg==NULL)
+			&& !insertScheme(&list->schemes, &list->schemeCount, cfg, pos)) {
+		return 0;
+	}
+	return -1;
+}
+
+int flib_schemelist_delete(flib_schemelist *list, int pos) {
+	if(!log_badargs_if(list==NULL)) {
+		flib_scheme *elem = list->schemes[pos];
+		if(!deleteScheme(&list->schemes, &list->schemeCount, pos)) {
+			flib_scheme_destroy(elem);
+			return 0;
+		}
+	}
+	return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/schemelist.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,79 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Functions for managing a list of schemes.
+ * This is in here because the scheme config file of the QtFrontend (which we are staying compatible with) contains
+ * all the schemes at once, so we need functions to work with a list like that.
+ */
+
+#ifndef SCHEMELIST_H_
+#define SCHEMELIST_H_
+
+#include "scheme.h"
+
+typedef struct {
+	int schemeCount;
+	flib_scheme **schemes;
+} flib_schemelist;
+
+/**
+ * Load a list of configurations from the ini file.
+ * Returns NULL on error.
+ */
+flib_schemelist *flib_schemelist_from_ini(const char *filename);
+
+/**
+ * Store the list of configurations to an ini file.
+ * Returns NULL on error.
+ */
+int flib_schemelist_to_ini(const char *filename, const flib_schemelist *config);
+
+/**
+ * Create an empty scheme list. Returns NULL on error.
+ */
+flib_schemelist *flib_schemelist_create();
+
+/**
+ * Insert a new scheme into the list at position pos, moving all higher schemes to make place.
+ * pos must be at least 0 (insert at the start) and at most list->schemeCount (insert at the end).
+ * Ownership of the scheme is transferred to the list.
+ * Returns 0 on success.
+ */
+int flib_schemelist_insert(flib_schemelist *list, flib_scheme *cfg, int pos);
+
+/**
+ * Delete a scheme from the list at position pos, moving down all higher schemes.
+ * The scheme is destroyed.
+ * Returns 0 on success.
+ */
+int flib_schemelist_delete(flib_schemelist *list, int pos);
+
+/**
+ * Find the scheme with a specific name
+ */
+flib_scheme *flib_schemelist_find(flib_schemelist *list, const char *name);
+
+/**
+ * Free this schemelist and all contained schemes
+ */
+void flib_schemelist_destroy(flib_schemelist *list);
+
+
+#endif /* SCHEMELIST_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/team.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,323 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "team.h"
+
+#include "../util/inihelper.h"
+#include "../util/util.h"
+#include "../util/logging.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+static flib_team *from_ini_handleError(flib_team *result, flib_ini *settingfile) {
+	flib_ini_destroy(settingfile);
+	flib_team_destroy(result);
+	return NULL;
+}
+
+flib_team *flib_team_from_ini(const char *filename) {
+	if(log_badargs_if(filename==NULL)) {
+		return NULL;
+	}
+
+	flib_team *result = flib_calloc(1, sizeof(flib_team));
+	flib_ini *ini = NULL;
+
+	if(!result) {
+		return from_ini_handleError(result, ini);
+	}
+
+	ini = flib_ini_load(filename);
+	if(!ini) {
+		flib_log_e("Error loading team file %s", filename);
+		return from_ini_handleError(result, ini);
+	}
+
+	if(flib_ini_enter_section(ini, "team")) {
+		flib_log_e("Missing section \"Team\" in team file %s", filename);
+		return from_ini_handleError(result, ini);
+	}
+	bool error = false;
+	error |= flib_ini_get_str(ini, &result->name, "name");
+	error |= flib_ini_get_str(ini, &result->grave, "grave");
+	error |= flib_ini_get_str(ini, &result->fort, "fort");
+	error |= flib_ini_get_str(ini, &result->voicepack, "voicepack");
+	error |= flib_ini_get_str(ini, &result->flag, "flag");
+	error |= flib_ini_get_int(ini, &result->rounds, "rounds");
+	error |= flib_ini_get_int(ini, &result->wins, "wins");
+	error |= flib_ini_get_int(ini, &result->campaignProgress, "campaignprogress");
+
+	int difficulty = 0;
+	error |= flib_ini_get_int(ini, &difficulty, "difficulty");
+
+	if(error) {
+		flib_log_e("Missing or malformed entry in section \"Team\" in file %s", filename);
+		return from_ini_handleError(result, ini);
+	}
+
+	for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+		char sectionName[32];
+		if(snprintf(sectionName, sizeof(sectionName), "hedgehog%i", i) <= 0) {
+			return from_ini_handleError(result, ini);
+		}
+		if(flib_ini_enter_section(ini, sectionName)) {
+			flib_log_e("Missing section \"%s\" in team file %s", sectionName, filename);
+			return from_ini_handleError(result, ini);
+		}
+		flib_hog *hog = &result->hogs[i];
+		error |= flib_ini_get_str(ini, &hog->name, "name");
+		error |= flib_ini_get_str(ini, &hog->hat, "hat");
+		error |= flib_ini_get_int(ini, &hog->rounds, "rounds");
+		error |= flib_ini_get_int(ini, &hog->kills, "kills");
+		error |= flib_ini_get_int(ini, &hog->deaths, "deaths");
+		error |= flib_ini_get_int(ini, &hog->suicides, "suicides");
+		result->hogs[i].difficulty = difficulty;
+		result->hogs[i].initialHealth = TEAM_DEFAULT_HEALTH;
+
+		if(error) {
+			flib_log_e("Missing or malformed entry in section \"%s\" in file %s", sectionName, filename);
+			return from_ini_handleError(result, ini);
+		}
+	}
+
+	if(!flib_ini_enter_section(ini, "binds")) {
+		result->bindingCount = flib_ini_get_keycount(ini);
+		if(result->bindingCount<0) {
+			flib_log_e("Error reading bindings from file %s", filename);
+			result->bindingCount = 0;
+		}
+		result->bindings = flib_calloc(result->bindingCount, sizeof(flib_binding));
+		if(!result->bindings) {
+			return from_ini_handleError(result, ini);
+		}
+		for(int i=0; i<result->bindingCount; i++) {
+			char *keyname = flib_ini_get_keyname(ini, i);
+			if(!keyname) {
+				error = true;
+			} else {
+				result->bindings[i].action = flib_urldecode(keyname);
+				error |= !result->bindings[i].action;
+				error |= flib_ini_get_str(ini, &result->bindings[i].binding, keyname);
+			}
+			free(keyname);
+		}
+	}
+
+	if(error) {
+		flib_log_e("Error reading team file %s", filename);
+		return from_ini_handleError(result, ini);
+	}
+
+	flib_ini_destroy(ini);
+	return result;
+}
+
+void flib_team_destroy(flib_team *team) {
+	if(team) {
+		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+			free(team->hogs[i].name);
+			free(team->hogs[i].hat);
+			flib_weaponset_destroy(team->hogs[i].weaponset);
+		}
+		free(team->name);
+		free(team->grave);
+		free(team->fort);
+		free(team->voicepack);
+		free(team->flag);
+		if(team->bindings) {
+			for(int i=0; i<team->bindingCount; i++) {
+				free(team->bindings[i].action);
+				free(team->bindings[i].binding);
+			}
+		}
+		free(team->bindings);
+		free(team->ownerName);
+		free(team);
+	}
+}
+
+static int writeTeamSection(const flib_team *team, flib_ini *ini) {
+	if(flib_ini_create_section(ini, "team")) {
+		return -1;
+	}
+	bool error = false;
+	error |= flib_ini_set_str(ini, "name",  team->name);
+	error |= flib_ini_set_str(ini, "grave", team->grave);
+	error |= flib_ini_set_str(ini, "fort", team->fort);
+	error |= flib_ini_set_str(ini, "voicepack", team->voicepack);
+	error |= flib_ini_set_str(ini, "flag", team->flag);
+	error |= flib_ini_set_int(ini, "rounds", team->rounds);
+	error |= flib_ini_set_int(ini, "wins", team->wins);
+	error |= flib_ini_set_int(ini, "campaignprogress", team->campaignProgress);
+	error |= flib_ini_set_int(ini, "difficulty", team->hogs[0].difficulty);
+	return error;
+}
+
+static int writeHogSections(const flib_team *team, flib_ini *ini) {
+	for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+		const flib_hog *hog = &team->hogs[i];
+		char sectionName[32];
+		if(snprintf(sectionName, sizeof(sectionName), "hedgehog%i", i) <= 0) {
+			return -1;
+		}
+		if(flib_ini_create_section(ini, sectionName)) {
+			return -1;
+		}
+		bool error = false;
+		error |= flib_ini_set_str(ini, "name", hog->name);
+		error |= flib_ini_set_str(ini, "hat", hog->hat);
+		error |= flib_ini_set_int(ini, "rounds", hog->rounds);
+		error |= flib_ini_set_int(ini, "kills", hog->kills);
+		error |= flib_ini_set_int(ini, "deaths", hog->deaths);
+		error |= flib_ini_set_int(ini, "suicides", hog->suicides);
+		if(error) {
+			return error;
+		}
+	}
+	return 0;
+}
+
+static int writeBindingSection(const flib_team *team, flib_ini *ini) {
+	if(team->bindingCount == 0) {
+		return 0;
+	}
+	if(flib_ini_create_section(ini, "binds")) {
+		return -1;
+	}
+	for(int i=0; i<team->bindingCount; i++) {
+		bool error = false;
+		char *action = flib_urlencode(team->bindings[i].action);
+		if(action) {
+			error |= flib_ini_set_str(ini, action, team->bindings[i].binding);
+			free(action);
+		} else {
+			error = true;
+		}
+		if(error) {
+			return error;
+		}
+	}
+	return 0;
+}
+
+int flib_team_to_ini(const char *filename, const flib_team *team) {
+	int result = -1;
+	if(!log_badargs_if2(filename==NULL, team==NULL)) {
+		flib_ini *ini = flib_ini_create(filename);
+		bool error = false;
+		error |= writeTeamSection(team, ini);
+		error |= writeHogSections(team, ini);
+		error |= writeBindingSection(team, ini);
+		if(!error) {
+			result = flib_ini_save(ini, filename);
+		}
+		flib_ini_destroy(ini);
+	}
+	return result;
+}
+
+int flib_team_set_weaponset(flib_team *team, const flib_weaponset *set) {
+	if(team) {
+		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+			flib_weaponset_destroy(team->hogs[i].weaponset);
+			team->hogs[i].weaponset = flib_weaponset_copy(set);
+			if(set && !team->hogs[i].weaponset) {
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+void flib_team_set_health(flib_team *team, int health) {
+	if(team) {
+		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+			team->hogs[i].initialHealth = health;
+		}
+	}
+}
+
+static char *strdupWithError(const char *in, bool *error) {
+	char *out = flib_strdupnull(in);
+	if(in && !out) {
+		*error = true;
+	}
+	return out;
+}
+
+flib_team *flib_team_copy(const flib_team *team) {
+	flib_team *result = NULL;
+	if(team) {
+		flib_team *tmpTeam = flib_calloc(1, sizeof(flib_team));
+		if(tmpTeam) {
+			bool error = false;
+
+			for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+				tmpTeam->hogs[i].name = strdupWithError(team->hogs[i].name, &error);
+				tmpTeam->hogs[i].hat = strdupWithError(team->hogs[i].hat, &error);
+				tmpTeam->hogs[i].rounds = team->hogs[i].rounds;
+				tmpTeam->hogs[i].kills = team->hogs[i].kills;
+				tmpTeam->hogs[i].deaths = team->hogs[i].deaths;
+				tmpTeam->hogs[i].suicides = team->hogs[i].suicides;
+				tmpTeam->hogs[i].difficulty = team->hogs[i].difficulty;
+				tmpTeam->hogs[i].initialHealth = team->hogs[i].initialHealth;
+				tmpTeam->hogs[i].weaponset = flib_weaponset_copy(team->hogs[i].weaponset);
+				if(team->hogs[i].weaponset && !tmpTeam->hogs[i].weaponset) {
+					error = true;
+				}
+			}
+
+			tmpTeam->name = strdupWithError(team->name, &error);
+			tmpTeam->grave = strdupWithError(team->grave, &error);
+			tmpTeam->fort = strdupWithError(team->fort, &error);
+			tmpTeam->voicepack = strdupWithError(team->voicepack, &error);
+			tmpTeam->flag = strdupWithError(team->flag, &error);
+			tmpTeam->ownerName = strdupWithError(team->ownerName, &error);
+
+			tmpTeam->bindingCount = team->bindingCount;
+			if(team->bindings) {
+				tmpTeam->bindings = flib_calloc(team->bindingCount, sizeof(flib_binding));
+				if(tmpTeam->bindings) {
+					for(int i=0; i<tmpTeam->bindingCount; i++) {
+						tmpTeam->bindings[i].action = strdupWithError(team->bindings[i].action, &error);
+						tmpTeam->bindings[i].binding = strdupWithError(team->bindings[i].binding, &error);
+					}
+				} else {
+					error = true;
+				}
+			}
+
+			tmpTeam->rounds = team->rounds;
+			tmpTeam->wins = team->wins;
+			tmpTeam->campaignProgress = team->campaignProgress;
+
+			tmpTeam->colorIndex = team->colorIndex;
+			tmpTeam->hogsInGame = team->hogsInGame;
+			tmpTeam->remoteDriven = team->remoteDriven;
+
+			if(!error) {
+				result = tmpTeam;
+				tmpTeam = 0;
+			}
+		}
+		flib_team_destroy(tmpTeam);
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/team.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,130 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * This file defines a data structure for a hedgewars team.
+ *
+ * Teams are used in several different contexts in Hedgewars, and some of these require
+ * extra information about teams. For example, the weaponset is important
+ * to the engine, but not for ini reading/writing, and with the team statistics it is the
+ * other way around. To keep things simple, the data structure can hold all information
+ * used in any context. On the downside, that means we can't use static typing to ensure
+ * that team information is "complete" for a particular purpose.
+ */
+#ifndef TEAM_H_
+#define TEAM_H_
+
+
+#include "weapon.h"
+#include "../hwconsts.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define TEAM_DEFAULT_HEALTH 100
+
+/**
+ * Struct representing a single keybinding.
+ */
+typedef struct {
+	char *action;
+	char *binding;
+} flib_binding;
+
+typedef struct {
+	char *name;
+	char *hat;			// e.g. hair_yellow; References a .png file in Data/Graphics/Hats
+
+	// Statistics. They are irrelevant for the engine or server,
+	// but provided for ini reading/writing by the frontend.
+	int rounds;
+	int kills;
+	int deaths;
+	int suicides;
+
+	int difficulty;		// 0 = human, 1 = most difficult bot ... 5 = least difficult bot (somewhat counterintuitive)
+
+	// Transient setting used in game setup
+	int initialHealth;
+	flib_weaponset *weaponset;
+} flib_hog;
+
+typedef struct {
+	flib_hog hogs[HEDGEHOGS_PER_TEAM];
+	char *name;
+	char *grave;		// e.g. "Bone"; References a .png file in Data/Graphics/Graves
+	char *fort;			// e.g. "Castle"; References a series of files in Data/Forts
+	char *voicepack;	// e.g. "Classic"; References a directory in Data/Sounds/voices
+	char *flag;			// e.g. "hedgewars"; References a .png file in Data/Graphics/Flags
+
+	flib_binding *bindings;
+	int bindingCount;
+
+	// Statistics. They are irrelevant for the engine or server,
+	// but provided for ini reading/writing by the frontend.
+	int rounds;
+	int wins;
+	int campaignProgress;
+
+	// Transient settings used in game setup
+	int colorIndex;		// Index into a color table
+	int hogsInGame;		// The number of hogs that will actually play
+	bool remoteDriven;	// true for non-local teams in a network game
+	char *ownerName;	// Username of the owner of a team in a network game
+} flib_team;
+
+/**
+ * Free all memory associated with the team
+ */
+void flib_team_destroy(flib_team *team);
+
+/**
+ * Loads a team, returns NULL on error. Destroy this team using flib_team_destroy.
+ * This will not fill in the fields marked as "transient" in the structs above.
+ */
+flib_team *flib_team_from_ini(const char *filename);
+
+/**
+ * Write the team to an ini file. Attempts to retain extra ini settings
+ * that were already present. Note that not all fields of a team struct
+ * are stored in the ini, some are only used intermittently to store
+ * information about a team in the context of a game.
+ *
+ * The flib_team can handle "difficulty" on a per-hog basis, but it
+ * is only written per-team in the team file. The difficulty of the
+ * first hog is used for the entire team when writing.
+ */
+int flib_team_to_ini(const char *filename, const flib_team *team);
+
+/**
+ * Set the same weaponset for every hog in the team
+ */
+int flib_team_set_weaponset(flib_team *team, const flib_weaponset *set);
+
+/**
+ * Set the same initial health for every hog.
+ */
+void flib_team_set_health(flib_team *team, int health);
+
+/**
+ * Create a deep copy of a team. Returns NULL on failure.
+ */
+flib_team *flib_team_copy(const flib_team *team);
+
+#endif /* TEAM_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/teamlist.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,120 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "teamlist.h"
+
+#include "../util/util.h"
+#include "../util/list.h"
+#include "../util/logging.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+flib_teamlist *flib_teamlist_create() {
+	return flib_calloc(1, sizeof(flib_teamlist));
+}
+
+void flib_teamlist_destroy(flib_teamlist *list) {
+	if(list) {
+		for(int i=0; i<list->teamCount; i++) {
+			flib_team_destroy(list->teams[i]);
+		}
+		free(list->teams);
+		free(list);
+	}
+}
+
+GENERATE_STATIC_LIST_INSERT(insertTeam, flib_team*)
+GENERATE_STATIC_LIST_DELETE(deleteTeam, flib_team*)
+
+static int findTeam(const flib_teamlist *list, const char *name) {
+	for(int i=0; i<list->teamCount; i++) {
+		if(!strcmp(name, list->teams[i]->name)) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+int flib_teamlist_insert(flib_teamlist *list, flib_team *team, int pos) {
+	if(!log_badargs_if2(list==NULL, team==NULL)
+			&& !insertTeam(&list->teams, &list->teamCount, team, pos)) {
+		return 0;
+	}
+	return -1;
+}
+
+int flib_teamlist_delete(flib_teamlist *list, const char *name) {
+	int result = -1;
+	if(!log_badargs_if2(list==NULL, name==NULL)) {
+		int itemid = findTeam(list, name);
+		if(itemid>=0) {
+			flib_team *team = list->teams[itemid];
+			if(!deleteTeam(&list->teams, &list->teamCount, itemid)) {
+				flib_team_destroy(team);
+				result = 0;
+			}
+		}
+	}
+	return result;
+}
+
+flib_team *flib_teamlist_find(const flib_teamlist *list, const char *name) {
+	flib_team *result = NULL;
+	if(!log_badargs_if2(list==NULL, name==NULL)) {
+		int itemid = findTeam(list, name);
+		if(itemid>=0) {
+			result = list->teams[itemid];
+		}
+	}
+	return result;
+}
+
+void flib_teamlist_clear(flib_teamlist *list) {
+	if(!log_badargs_if(list==NULL)) {
+		for(int i=0; i<list->teamCount; i++) {
+			flib_team_destroy(list->teams[i]);
+		}
+		free(list->teams);
+		list->teams = NULL;
+		list->teamCount = 0;
+	}
+}
+
+flib_teamlist *flib_teamlist_copy(flib_teamlist *list) {
+	if(!list) {
+		return NULL;
+	}
+	flib_teamlist *result = flib_teamlist_create();
+	if(result) {
+		bool error = false;
+		for(int i=0; !error && i<list->teamCount; i++) {
+			flib_team *teamcopy = flib_team_copy(list->teams[i]);
+			if(!teamcopy || flib_teamlist_insert(result, teamcopy, i)) {
+				flib_team_destroy(teamcopy);
+				error = true;
+			}
+		}
+		if(error) {
+			flib_teamlist_destroy(result);
+			result = NULL;
+		}
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/teamlist.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,61 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef TEAMLIST_H_
+#define TEAMLIST_H_
+
+#include "team.h"
+
+typedef struct {
+	int teamCount;
+	flib_team **teams;
+} flib_teamlist;
+
+flib_teamlist *flib_teamlist_create();
+
+void flib_teamlist_destroy(flib_teamlist *list);
+
+/**
+ * Insert a team into the list. The list takes ownership of the team. Returns 0 on success.
+ */
+int flib_teamlist_insert(flib_teamlist *list, flib_team *team, int pos);
+
+/**
+ * Delete the team with the name [name] from the list and destroys it.
+ * Returns 0 on success.
+ */
+int flib_teamlist_delete(flib_teamlist *list, const char *name);
+
+/**
+ * Returns the team with the name [name] from the list if it exists, NULL otherwise
+ */
+flib_team *flib_teamlist_find(const flib_teamlist *list, const char *name);
+
+/**
+ * Removes all items from the list and destroys them.
+ */
+void flib_teamlist_clear(flib_teamlist *list);
+
+/**
+ * Create a copy of the list and all the teams it contains. Weaponsets are not copied, but
+ * kept as references
+ */
+flib_teamlist *flib_teamlist_copy(flib_teamlist *list);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/weapon.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,234 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "weapon.h"
+
+#include "../util/inihelper.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../util/list.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+static void setField(char field[WEAPONS_COUNT+1], const char *line, int lineLen, bool no9) {
+	if(lineLen>WEAPONS_COUNT) {
+		lineLen = WEAPONS_COUNT;
+	}
+
+	char min = '0';
+	char max = no9 ? '8' : '9';
+	for(int i=0; i<lineLen; i++) {
+		if(line[i] >= min && line[i] <= max) {
+			field[i] = line[i];
+		} else {
+			flib_log_w("Invalid character in weapon config string \"%.*s\", position %i", lineLen, line, i);
+			field[i] = '0';
+		}
+	}
+	for(int i=lineLen; i<WEAPONS_COUNT; i++) {
+		field[i] = '0';
+	}
+	field[WEAPONS_COUNT] = 0;
+}
+
+flib_weaponset *flib_weaponset_create(const char *name) {
+	flib_weaponset *result = NULL;
+	if(!log_badargs_if(name==NULL)) {
+		flib_weaponset *newSet = flib_calloc(1, sizeof(flib_weaponset));
+		if(newSet) {
+			newSet->name = flib_strdupnull(name);
+			if(newSet->name) {
+				setField(newSet->loadout, "", 0, false);
+				setField(newSet->crateprob, "", 0, false);
+				setField(newSet->crateammo, "", 0, false);
+				setField(newSet->delay, "", 0, false);
+				result = newSet;
+				newSet = NULL;
+			}
+		}
+		flib_weaponset_destroy(newSet);
+	}
+	return result;
+}
+
+void flib_weaponset_destroy(flib_weaponset *cfg) {
+	if(cfg) {
+		free(cfg->name);
+		free(cfg);
+	}
+}
+
+flib_weaponset *flib_weaponset_copy(const flib_weaponset *weaponset) {
+	if(!weaponset) {
+		return NULL;
+	}
+
+	flib_weaponset *result = flib_weaponset_create(weaponset->name);
+	if(result) {
+		memcpy(result->loadout, weaponset->loadout, WEAPONS_COUNT+1);
+		memcpy(result->crateprob, weaponset->crateprob, WEAPONS_COUNT+1);
+		memcpy(result->delay, weaponset->delay, WEAPONS_COUNT+1);
+		memcpy(result->crateammo, weaponset->crateammo, WEAPONS_COUNT+1);
+	}
+
+	return result;
+}
+
+void flib_weaponsetlist_destroy(flib_weaponsetlist *list) {
+	if(list) {
+		for(int i=0; i<list->weaponsetCount; i++) {
+			flib_weaponset_destroy(list->weaponsets[i]);
+		}
+		free(list->weaponsets);
+		free(list);
+	}
+}
+
+flib_weaponset *flib_weaponset_from_ammostring(const char *name, const char *ammostring) {
+	flib_weaponset *result = NULL;
+	if(!log_badargs_if2(name==NULL, ammostring==NULL)) {
+		result = flib_weaponset_create(name);
+		if(result) {
+			int fieldlen = strlen(ammostring)/4;
+			setField(result->loadout, ammostring, fieldlen, false);
+			setField(result->crateprob, ammostring + fieldlen, fieldlen, true);
+			setField(result->delay, ammostring + 2*fieldlen, fieldlen, true);
+			setField(result->crateammo, ammostring + 3*fieldlen, fieldlen, true);
+		}
+	}
+	return result;
+}
+
+static int fillWeaponsetFromIni(flib_weaponsetlist *list, flib_ini *ini, int index) {
+	int result = -1;
+	char *keyname = flib_ini_get_keyname(ini, index);
+	char *decodedKeyname = flib_urldecode(keyname);
+	char *ammostring = NULL;
+	if(decodedKeyname && !flib_ini_get_str(ini, &ammostring, keyname)) {
+		flib_weaponset *set = flib_weaponset_from_ammostring(decodedKeyname, ammostring);
+		if(set) {
+			result = flib_weaponsetlist_insert(list, set, list->weaponsetCount);
+			if(result) {
+				flib_weaponset_destroy(set);
+			}
+		}
+	}
+	free(ammostring);
+	free(decodedKeyname);
+	free(keyname);
+	return result;
+}
+
+static int fillWeaponsetsFromIni(flib_weaponsetlist *list, flib_ini *ini) {
+	bool error = false;
+	int weaponsets = flib_ini_get_keycount(ini);
+
+	for(int i=0; i<weaponsets && !error; i++) {
+		error |= fillWeaponsetFromIni(list, ini, i);
+	}
+	return error;
+}
+
+flib_weaponsetlist *flib_weaponsetlist_from_ini(const char *filename) {
+	flib_weaponsetlist *result = NULL;
+	if(!log_badargs_if(filename==NULL)) {
+		flib_ini *ini = flib_ini_load(filename);
+		if(!ini) {
+			flib_log_e("Missing file %s.", filename);
+		} else if(flib_ini_enter_section(ini, "General")) {
+			flib_log_e("Missing section \"General\" in file %s.", filename);
+		} else {
+			flib_weaponsetlist *tmpList = flib_weaponsetlist_create();
+			if(tmpList && !fillWeaponsetsFromIni(tmpList, ini)) {
+				result = tmpList;
+				tmpList = NULL;
+			}
+			flib_weaponsetlist_destroy(tmpList);
+		}
+		flib_ini_destroy(ini);
+	}
+	return result;
+}
+
+static bool needsEscape(char c) {
+	return !((c>='0' && c<='9') || (c>='a' && c <='z'));
+}
+
+static int writeWeaponsetToIni(flib_ini *ini, flib_weaponset *set) {
+	int result = -1;
+	char weaponstring[WEAPONS_COUNT*4+1];
+	strcpy(weaponstring, set->loadout);
+	strcat(weaponstring, set->crateprob);
+	strcat(weaponstring, set->delay);
+	strcat(weaponstring, set->crateammo);
+
+	char *escapedname = flib_urlencode_pred(set->name, needsEscape);
+	if(escapedname) {
+		result = flib_ini_set_str(ini, escapedname, weaponstring);
+	}
+	free(escapedname);
+	return result;
+}
+
+int flib_weaponsetlist_to_ini(const char *filename, const flib_weaponsetlist *list) {
+	int result = -1;
+	if(!log_badargs_if2(filename==NULL, list==NULL)) {
+		flib_ini *ini = flib_ini_create(NULL);
+		if(ini && !flib_ini_create_section(ini, "General")) {
+			bool error = false;
+			for(int i=0; i<list->weaponsetCount && !error; i++) {
+				error |= writeWeaponsetToIni(ini, list->weaponsets[i]);
+			}
+
+			if(!error) {
+				result = flib_ini_save(ini, filename);
+			}
+		}
+		flib_ini_destroy(ini);
+	}
+	return result;
+}
+
+flib_weaponsetlist *flib_weaponsetlist_create() {
+	return flib_calloc(1, sizeof(flib_weaponsetlist));
+}
+
+GENERATE_STATIC_LIST_INSERT(insertWeaponset, flib_weaponset*)
+GENERATE_STATIC_LIST_DELETE(deleteWeaponset, flib_weaponset*)
+
+int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *set, int pos) {
+	if(!log_badargs_if2(list==NULL, set==NULL)
+			&& !insertWeaponset(&list->weaponsets, &list->weaponsetCount, set, pos)) {
+		return 0;
+	}
+	return -1;
+}
+
+int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos) {
+	if(!log_badargs_if(list==NULL)) {
+		flib_weaponset *elem = list->weaponsets[pos];
+		if(!deleteWeaponset(&list->weaponsets, &list->weaponsetCount, pos)) {
+			flib_weaponset_destroy(elem);
+			return 0;
+		}
+	}
+	return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/model/weapon.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,104 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef MODEL_WEAPON_H_
+#define MODEL_WEAPON_H_
+
+#include "../hwconsts.h"
+
+/**
+ * These values are all ASCII characters in the range '0'..'9'
+ * The fields are zero-terminated so they can easily be used as strings.
+ *
+ * For loadout, 9 means inifinite ammo.
+ * For the other setting, 9 is invalid.
+ */
+typedef struct {
+	char loadout[WEAPONS_COUNT+1];
+	char crateprob[WEAPONS_COUNT+1];
+	char crateammo[WEAPONS_COUNT+1];
+	char delay[WEAPONS_COUNT+1];
+	char *name;
+} flib_weaponset;
+
+typedef struct {
+	int weaponsetCount;
+	flib_weaponset **weaponsets;
+} flib_weaponsetlist;
+
+/**
+ * Returns a new weapon set, or NULL on error.
+ * name must not be NULL.
+ *
+ * The new weapon set is pre-filled with default
+ * settings (see hwconsts.h)
+ */
+flib_weaponset *flib_weaponset_create(const char *name);
+
+/**
+ * Free the memory used by this weaponset
+ */
+void flib_weaponset_destroy(flib_weaponset *weaponset);
+
+flib_weaponset *flib_weaponset_copy(const flib_weaponset *weaponset);
+
+/**
+ * Create a weaponset from an ammostring. This format is used both in the ini files
+ * and in the net protocol.
+ */
+flib_weaponset *flib_weaponset_from_ammostring(const char *name, const char *ammostring);
+
+/**
+ * Load a list of weaponsets from the ini file.
+ * Returns NULL on error.
+ */
+flib_weaponsetlist *flib_weaponsetlist_from_ini(const char *filename);
+
+/**
+ * Store the list of weaponsets to an ini file.
+ * Returns NULL on error.
+ */
+int flib_weaponsetlist_to_ini(const char *filename, const flib_weaponsetlist *weaponsets);
+
+/**
+ * Create an empty weaponset list. Returns NULL on error.
+ */
+flib_weaponsetlist *flib_weaponsetlist_create();
+
+/**
+ * Release all memory associated with the weaponsetlist and release all contained weaponsets
+ */
+void flib_weaponsetlist_destroy(flib_weaponsetlist *list);
+
+/**
+ * Insert a new weaponset into the list at position pos, moving all higher weaponsets to make place.
+ * pos must be at least 0 (insert at the start) and at most list->weaponsetCount (insert at the end).
+ * Ownership of the weaponset is transferred to the list.
+ * Returns 0 on success.
+ */
+int flib_weaponsetlist_insert(flib_weaponsetlist *list, flib_weaponset *weaponset, int pos);
+
+/**
+ * Delete a weaponset from the list at position pos, moving down all higher weaponsets.
+ * The weaponset is destroyed.
+ * Returns 0 on success.
+ */
+int flib_weaponsetlist_delete(flib_weaponsetlist *list, int pos);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netbase.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,259 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "netbase.h"
+#include "../util/buffer.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../socket.h"
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NET_READBUFFER_LIMIT (1024*1024)
+
+struct _flib_netbase {
+	flib_vector *readBuffer;
+	flib_tcpsocket *sock;
+};
+
+flib_netbase *flib_netbase_create(const char *server, uint16_t port) {
+	if(log_badargs_if2(server==NULL, port==0)) {
+		return NULL;
+	}
+
+	flib_netbase *result = NULL;
+	flib_netbase *newNet =  flib_calloc(1, sizeof(flib_netbase));
+
+	if(newNet) {
+		newNet->readBuffer = flib_vector_create();
+		newNet->sock = flib_socket_connect(server, port);
+		if(newNet->readBuffer && newNet->sock) {
+			flib_log_i("Connected to server %s:%u", server, (unsigned)port);
+			result = newNet;
+			newNet = NULL;
+		}
+	}
+	flib_netbase_destroy(newNet);
+
+	return result;
+}
+
+void flib_netbase_destroy(flib_netbase *net) {
+	if(net) {
+		flib_socket_close(net->sock);
+		flib_vector_destroy(net->readBuffer);
+		free(net);
+	}
+}
+
+bool flib_netbase_connected(flib_netbase *net) {
+	if(!log_badargs_if(net==NULL) && net->sock) {
+		return true;
+	}
+	return false;
+}
+
+/**
+ * Parses and returns a message, and removes it from the vector.
+ */
+static flib_netmsg *parseMessage(flib_vector *vec) {
+	const uint8_t *partStart = flib_vector_data(vec);
+	const uint8_t *end = partStart+flib_vector_size(vec);
+	flib_netmsg *result = flib_netmsg_create();
+	if(!result) {
+		return NULL;
+	}
+
+	while(1) {
+		const uint8_t *partEnd = memchr(partStart, '\n', end-partStart);
+		if(!partEnd) {
+			// message incomplete
+			flib_netmsg_destroy(result);
+			return NULL;
+		} else if(partEnd-partStart == 0) {
+			// Zero-length part, message end marker. Remove the message from the vector.
+			uint8_t *vectorStart = flib_vector_data(vec);
+			size_t msgLen = partEnd+1-vectorStart;
+			memmove(vectorStart, partEnd+1, flib_vector_size(vec)-msgLen);
+			flib_vector_resize(vec, flib_vector_size(vec)-msgLen);
+			return result;
+		} else {
+			if(flib_netmsg_append_part(result, partStart, partEnd-partStart)) {
+				flib_netmsg_destroy(result);
+				return NULL;
+			}
+			partStart = partEnd+1; // Skip the '\n'
+		}
+	}
+	return NULL; // Never reached
+}
+
+/**
+ * Receive some bytes and add them to the buffer.
+ * Returns the number of bytes received.
+ * Automatically closes the socket if an error occurs
+ * and sets sock=NULL.
+ */
+static int receiveToBuffer(flib_netbase *net) {
+	uint8_t buffer[256];
+	if(!net->sock) {
+		return 0;
+	} else if(flib_vector_size(net->readBuffer) > NET_READBUFFER_LIMIT) {
+		flib_log_e("Net connection closed: Net message too big");
+		flib_socket_close(net->sock);
+		net->sock = NULL;
+		return 0;
+	} else {
+		int size = flib_socket_nbrecv(net->sock, buffer, sizeof(buffer));
+		if(size>=0 && !flib_vector_append(net->readBuffer, buffer, size)) {
+			return size;
+		} else {
+			flib_socket_close(net->sock);
+			net->sock = NULL;
+			return 0;
+		}
+	}
+}
+
+flib_netmsg *flib_netbase_recv_message(flib_netbase *net) {
+	if(log_badargs_if(net==NULL)) {
+		return NULL;
+	}
+
+	flib_netmsg *msg;
+	while(!(msg=parseMessage(net->readBuffer))
+			&& receiveToBuffer(net)) {}
+
+	if(msg) {
+		return msg;
+	} else if(!net->sock && flib_vector_size(net->readBuffer)>0) {
+		// Connection is down and we didn't get a complete message, just flush the rest.
+		flib_vector_resize(net->readBuffer, 0);
+	}
+	return NULL;
+}
+
+static void logSentMsg(const uint8_t *data, size_t len) {
+	if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+		flib_log_d("[NET OUT][%03u]%*.*s",(unsigned)len, (unsigned)len, (unsigned)len, data);
+	}
+}
+
+int flib_netbase_send_raw(flib_netbase *net, const void *data, size_t len) {
+	if(log_badargs_if2(net==NULL, data==NULL && len>0)) {
+		return -1;
+	}
+	if(!net->sock) {
+		flib_log_w("flib_netbase_send_raw: Not connected.");
+		return -1;
+	}
+
+	if(flib_socket_send(net->sock, data, len) == len) {
+		logSentMsg(data, len);
+		return 0;
+	} else {
+		flib_log_w("Failed or incomplete write: net connection lost.");
+		flib_socket_close(net->sock);
+		net->sock = NULL;
+		return -1;
+	}
+}
+
+int flib_netbase_send_message(flib_netbase *net, const flib_netmsg *msg) {
+	if(log_badargs_if2(net==NULL, msg==NULL)) {
+		return -1;
+	}
+
+	size_t totalSize = 0;
+	for(int i=0; i<msg->partCount; i++) {
+		totalSize += strlen(msg->parts[i]) + 1;
+	}
+	totalSize++; // Last part ends in two '\n' instead of one
+
+	uint8_t *buffer = flib_malloc(totalSize);
+	if(!buffer) {
+		return -1;
+	}
+	size_t pos = 0;
+	for(int i=0; i<msg->partCount; i++) {
+		size_t partsize = strlen(msg->parts[i]);
+		memcpy(buffer+pos, msg->parts[i], partsize);
+		pos += partsize;
+		buffer[pos++] = '\n';
+	}
+	buffer[pos++] = '\n';
+	return flib_netbase_send_raw(net, buffer, pos);
+}
+
+int flib_netbase_sendf(flib_netbase *net, const char *format, ...) {
+	int result = -1;
+	if(!log_badargs_if2(net==NULL, format==NULL)) {
+		va_list argp;
+		va_start(argp, format);
+		char *buffer = flib_vasprintf(format, argp);
+		if(buffer) {
+			result = flib_netbase_send_raw(net, buffer, strlen(buffer));
+		}
+		free(buffer);
+		va_end(argp);
+	}
+	return result;
+}
+
+flib_netmsg *flib_netmsg_create() {
+	flib_netmsg *result = flib_calloc(1, sizeof(flib_netmsg));
+	if(result) {
+		result->partCount = 0;
+		result->parts = NULL;
+		return result;
+	} else {
+		return NULL;
+	}
+}
+
+void flib_netmsg_destroy(flib_netmsg *msg) {
+	if(msg) {
+		for(int i=0; i<msg->partCount; i++) {
+			free(msg->parts[i]);
+		}
+		free(msg->parts);
+		free(msg);
+	}
+}
+
+int flib_netmsg_append_part(flib_netmsg *msg, const void *part, size_t partlen) {
+	int result = -1;
+	if(!log_badargs_if2(msg==NULL, part==NULL && partlen>0)) {
+		char **newParts = realloc(msg->parts, (msg->partCount+1)*sizeof(*msg->parts));
+		if(newParts) {
+			msg->parts = newParts;
+			msg->parts[msg->partCount] = flib_malloc(partlen+1);
+			if(msg->parts[msg->partCount]) {
+				memcpy(msg->parts[msg->partCount], part, partlen);
+				msg->parts[msg->partCount][partlen] = 0;
+				msg->partCount++;
+				result = 0;
+			}
+		}
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netbase.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,91 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * Low-level protocol support for the network connection
+ */
+
+#ifndef NETBASE_H_
+#define NETBASE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct _flib_netbase;
+typedef struct _flib_netbase flib_netbase;
+
+typedef struct {
+	int partCount;
+	char **parts;
+} flib_netmsg;
+
+/**
+ * Start a connection to the specified Hedgewars server.
+ *
+ * Returns NULL on error. Destroy the created object with flib_netconn_destroy.
+ */
+flib_netbase *flib_netbase_create(const char *server, uint16_t port);
+
+/**
+ * Free resources and close sockets.
+ */
+void flib_netbase_destroy(flib_netbase *net);
+
+/**
+ * Determine the current connection state. Starts out true, and turns to
+ * false when we are disconnected from the server.
+ */
+bool flib_netbase_connected(flib_netbase *net);
+
+/**
+ * Receive a new message and return it as a flib_netmsg. The netmsg has to be
+ * destroyed with flib_netmsg_destroy after use.
+ * Returns NULL if no message is available.
+ *
+ * Note: When a connection is closed, you probably want to call this function until
+ * no further message is returned, to ensure you see all messages that were sent
+ * before the connection closed.
+ */
+flib_netmsg *flib_netbase_recv_message(flib_netbase *net);
+
+int flib_netbase_send_raw(flib_netbase *net, const void *data, size_t len);
+
+/**
+ * Write a single message to the server. This call blocks until the
+ * message is completely written or the connection is closed or an error occurs.
+ *
+ * Returns a negative value on failure.
+ */
+int flib_netbase_send_message(flib_netbase *net, const flib_netmsg *msg);
+
+/**
+ * Send a message printf-style.
+ *
+ * flib_netbase_sendf(net, "%s\n\n", "TOGGLE_READY");
+ * flib_netbase_sendf(net, "%s\n%s\n%i\n\n", "CFG", "MAPGEN", MAPGEN_MAZE);
+ */
+int flib_netbase_sendf(flib_netbase *net, const char *format, ...);
+
+flib_netmsg *flib_netmsg_create();
+void flib_netmsg_destroy(flib_netmsg *msg);
+int flib_netmsg_append_part(flib_netmsg *msg, const void *param, size_t len);
+
+#endif /* NETBASE_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,613 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2006-2008 Igor Ulyanov <iulyanov@gmail.com>
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2012 Simeon Maxein <smaxein@googlemail.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 "netconn_internal.h"
+#include "netprotocol.h"
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../md5/md5.h"
+#include "../base64/base64.h"
+#include "../model/mapcfg.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+flib_netconn *flib_netconn_create(const char *playerName, const char *dataDirPath, const char *host, int port) {
+	flib_netconn *result = NULL;
+	if(!log_badargs_if4(playerName==NULL, host==NULL, port<1, port>65535)) {
+		flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn));
+		if(newConn) {
+			newConn->netBase = flib_netbase_create(host, port);
+			newConn->playerName = flib_strdupnull(playerName);
+			newConn->dataDirPath = flib_strdupnull(dataDirPath);
+
+			newConn->netconnState = NETCONN_STATE_CONNECTING;
+
+			newConn->isChief = false;
+			newConn->map = flib_map_create_named("", "NoSuchMap");
+			newConn->pendingTeamlist.teamCount = 0;
+			newConn->pendingTeamlist.teams = NULL;
+			newConn->teamlist.teamCount = 0;
+			newConn->teamlist.teams = NULL;
+			newConn->scheme = NULL;
+			newConn->style = NULL;
+			newConn->weaponset = NULL;
+
+			newConn->running = false;
+			newConn->destroyRequested = false;
+			netconn_clearCallbacks(newConn);
+			if(newConn->netBase && newConn->playerName && newConn->dataDirPath && newConn->map) {
+				result = newConn;
+				newConn = NULL;
+			}
+		}
+		flib_netconn_destroy(newConn);
+	}
+	return result;
+}
+
+void flib_netconn_destroy(flib_netconn *conn) {
+	if(conn) {
+		if(conn->running) {
+			/*
+			 * The function was called from a callback, so the tick function is still running
+			 * and we delay the actual destruction. We ensure no further callbacks will be
+			 * sent to prevent surprises.
+			 */
+			netconn_clearCallbacks(conn);
+			conn->destroyRequested = true;
+		} else {
+			flib_netbase_destroy(conn->netBase);
+			free(conn->playerName);
+			free(conn->dataDirPath);
+
+			flib_map_destroy(conn->map);
+			flib_teamlist_clear(&conn->pendingTeamlist);
+			flib_teamlist_clear(&conn->teamlist);
+			flib_scheme_destroy(conn->scheme);
+			free(conn->style);
+			flib_weaponset_destroy(conn->weaponset);
+
+			free(conn);
+		}
+	}
+}
+
+bool flib_netconn_is_chief(flib_netconn *conn) {
+	if(!log_badargs_if(conn==NULL) && conn->netconnState==NETCONN_STATE_ROOM) {
+		return conn->isChief;
+	}
+	return false;
+}
+
+const char *flib_netconn_get_playername(flib_netconn *conn) {
+	if(!log_badargs_if(conn==NULL)) {
+		return conn->playerName;
+	}
+	return NULL;
+}
+
+void netconn_leaveRoom(flib_netconn *conn) {
+	conn->netconnState = NETCONN_STATE_LOBBY;
+	conn->isChief = false;
+	flib_map_destroy(conn->map);
+	conn->map = flib_map_create_named("", "NoSuchMap");
+	flib_teamlist_clear(&conn->pendingTeamlist);
+	flib_teamlist_clear(&conn->teamlist);
+	flib_scheme_destroy(conn->scheme);
+	conn->scheme = NULL;
+	free(conn->style);
+	conn->style = NULL;
+	flib_weaponset_destroy(conn->weaponset);
+	conn->weaponset = NULL;
+}
+
+void netconn_setMap(flib_netconn *conn, const flib_map *map) {
+	flib_map *copy = flib_map_copy(map);
+	if(copy) {
+		flib_map_destroy(conn->map);
+		conn->map = copy;
+	}
+}
+
+void netconn_setWeaponset(flib_netconn *conn, const flib_weaponset *weaponset) {
+	flib_weaponset *copy = flib_weaponset_copy(weaponset);
+	if(copy) {
+		flib_weaponset_destroy(conn->weaponset);
+		conn->weaponset = copy;
+	}
+}
+
+void netconn_setScript(flib_netconn *conn, const char *script) {
+	char *copy = flib_strdupnull(script);
+	if(copy) {
+		free(conn->style);
+		conn->style = copy;
+	}
+}
+
+void netconn_setScheme(flib_netconn *conn, const flib_scheme *scheme) {
+	flib_scheme *copy = flib_scheme_copy(scheme);
+	if(copy) {
+		flib_scheme_destroy(conn->scheme);
+		conn->scheme = copy;
+	}
+}
+
+flib_gamesetup *flib_netconn_create_gamesetup(flib_netconn *conn) {
+	flib_gamesetup *result = NULL;
+	if(!log_badargs_if(conn==NULL)) {
+		if(conn->teamlist.teamCount==0 || !conn->scheme || !conn->weaponset) {
+			flib_log_e("Incomplete room state");
+		} else {
+			flib_gamesetup stackSetup = {0};
+			stackSetup.gamescheme = conn->scheme;
+			stackSetup.map = conn->map;
+			stackSetup.style = conn->style;
+			stackSetup.teamlist = &conn->teamlist;
+			result = flib_gamesetup_copy(&stackSetup);
+			if(result) {
+				bool error = false;
+				for(int i=0; i<result->teamlist->teamCount; i++) {
+					if(flib_team_set_weaponset(result->teamlist->teams[i], conn->weaponset)) {
+						error = true;
+					}
+					flib_team_set_health(result->teamlist->teams[i], flib_scheme_get_setting(conn->scheme, "health", 100));
+				}
+				if(result->map->mapgen == MAPGEN_NAMED && result->map->name) {
+					flib_mapcfg mapcfg;
+					if(!flib_mapcfg_read(conn->dataDirPath, result->map->name, &mapcfg)) {
+						free(result->map->theme);
+						result->map->theme = flib_strdupnull(mapcfg.theme);
+						if(!result->map->theme) {
+							error = true;
+						}
+					} else {
+						flib_log_e("Unable to read map config for map %s", result->map->name);
+					}
+				}
+				if(error) {
+					flib_gamesetup_destroy(result);
+					result = NULL;
+				}
+			}
+		}
+	}
+	return result;
+}
+
+static void flib_netconn_wrappedtick(flib_netconn *conn) {
+	flib_netmsg *netmsg;
+	flib_netbase *net = conn->netBase;
+	bool exit = false;
+
+	while(!exit && !conn->destroyRequested && (netmsg=flib_netbase_recv_message(conn->netBase))) {
+		if(netmsg->partCount==0) {
+			flib_log_w("Empty server message");
+			continue;
+		}
+
+		if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) {
+			char *buf = flib_join(netmsg->parts, netmsg->partCount, "|");
+			if(buf) {
+				flib_log_d("[Net In]%s", buf);
+			}
+			free(buf);
+		}
+
+		const char *cmd = netmsg->parts[0];
+
+	    if (!strcmp(cmd, "NICK") && netmsg->partCount>=2) {
+	    	if(netmsg->partCount<2) {
+	    		flib_log_w("Net: Malformed NICK message");
+	    	} else {
+	    		char *nick = flib_strdupnull(netmsg->parts[1]);
+	    		if(nick) {
+					free(conn->playerName);
+					conn->playerName = nick;
+	    		} else {
+					conn->netconnState = NETCONN_STATE_DISCONNECTED;
+					conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Out of memory");
+					exit = true;
+				}
+	    	}
+	    } else if (!strcmp(cmd, "PROTO")) {
+	        // The server just echoes this back apparently
+		} else if (!strcmp(cmd, "ERROR")) {
+			if (netmsg->partCount >= 2) {
+				conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_ERROR, netmsg->parts[1]);
+			} else {
+				conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_ERROR, "Unknown Error");
+			}
+		} else if(!strcmp(cmd, "WARNING")) {
+			if (netmsg->partCount >= 2) {
+				conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_WARNING, netmsg->parts[1]);
+			} else {
+				conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_WARNING, "Unknown Warning");
+			}
+	    } else if(!strcmp(cmd, "CONNECTED")) {
+			if(netmsg->partCount<3 || atol(netmsg->parts[2])<MIN_SERVER_VERSION) {
+				flib_log_w("Net: Server too old");
+				flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Server too old");
+				conn->netconnState = NETCONN_STATE_DISCONNECTED;
+				conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_SERVER_TOO_OLD, "Server too old");
+				exit = true;
+			} else {
+				flib_netbase_sendf(net, "%s\n%s\n\n", "NICK", conn->playerName);
+				flib_netbase_sendf(net, "%s\n%i\n\n", "PROTO", (int)PROTOCOL_VERSION);
+			}
+		} else if(!strcmp(cmd, "PING")) {
+	        if (netmsg->partCount > 1) {
+	        	flib_netbase_sendf(net, "%s\n%s\n\n", "PONG", netmsg->parts[1]);
+	        } else {
+	        	flib_netbase_sendf(net, "%s\n\n", "PONG");
+	        }
+	    } else if(!strcmp(cmd, "ROOMS")) {
+	        if(netmsg->partCount % 8 != 1) {
+	        	flib_log_w("Net: Malformed ROOMS message");
+	        } else {
+	        	int roomCount = netmsg->partCount/8;
+	        	flib_room **rooms = flib_room_array_from_netmsg(netmsg->parts+1, roomCount);
+	        	if(rooms) {
+	        		conn->onRoomlistCb(conn->onRoomlistCtx, (const flib_room**)rooms, roomCount);
+	        		for(int i=0; i<roomCount; i++) {
+	        			flib_room_destroy(rooms[i]);
+	        		}
+	        		free(rooms);
+	        	}
+	        }
+	    } else if (!strcmp(cmd, "SERVER_MESSAGE")) {
+	        if(netmsg->partCount < 2) {
+	        	flib_log_w("Net: Empty SERVERMESSAGE message");
+	        } else {
+	        	conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_SERVERMESSAGE, netmsg->parts[1]);
+	        }
+	    } else if (!strcmp(cmd, "CHAT")) {
+	        if(netmsg->partCount < 3) {
+	        	flib_log_w("Net: Empty CHAT message");
+	        } else {
+	        	conn->onChatCb(conn->onChatCtx, netmsg->parts[1], netmsg->parts[2]);
+	        }
+	    } else if (!strcmp(cmd, "INFO")) {
+	        if(netmsg->partCount < 5) {
+	        	flib_log_w("Net: Malformed INFO message");
+	        } else {
+	        	char *joined = flib_join(netmsg->parts+1, netmsg->partCount-1, "\n");
+	        	if(joined) {
+	        		conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_PLAYERINFO, joined);
+	        	}
+	        	free(joined);
+	        }
+	    } else if(!strcmp(cmd, "SERVER_VARS")) {
+	    	for(int offset=1; offset+2<netmsg->partCount; offset+=2) {
+	    		conn->onServerVarCb(conn->onServerVarCtx, netmsg->parts[offset], netmsg->parts[offset+1]);
+	    	}
+	    } else if (!strcmp(cmd, "CLIENT_FLAGS")) {
+	        if(netmsg->partCount < 3 || strlen(netmsg->parts[1]) < 2) {
+	        	flib_log_w("Net: Malformed CLIENT_FLAGS message");
+	        } else {
+				const char *flags = netmsg->parts[1];
+				bool setFlag = flags[0] == '+';
+
+				for(int j = 2; j < netmsg->partCount; ++j) {
+					bool isSelf = !strcmp(conn->playerName, netmsg->parts[j]);
+					if(isSelf && strchr(flags, 'h')) {
+						conn->isChief = setFlag;
+					}
+					conn->onClientFlagsCb(conn->onClientFlagsCtx, netmsg->parts[j], flags+1, setFlag);
+				}
+	        }
+	    } else if (!strcmp(cmd, "ADD_TEAM")) {
+	        if(netmsg->partCount != 24 || conn->netconnState!=NETCONN_STATE_ROOM) {
+	            flib_log_w("Net: Bad ADD_TEAM message");
+	        } else {
+	        	flib_team *team = flib_team_from_netmsg(netmsg->parts+1);
+	        	if(!team || flib_teamlist_insert(&conn->teamlist, team, conn->teamlist.teamCount)) {
+					flib_team_destroy(team);
+					conn->netconnState = NETCONN_STATE_DISCONNECTED;
+					conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error");
+					exit = true;
+	        	} else {
+	        		conn->onTeamAddCb(conn->onTeamAddCtx, team);
+	        	}
+	        }
+	    } else if (!strcmp(cmd, "REMOVE_TEAM")) {
+	        if(netmsg->partCount != 2 || conn->netconnState!=NETCONN_STATE_ROOM) {
+	            flib_log_w("Net: Bad REMOVETEAM message");
+	        } else {
+	        	flib_teamlist_delete(&conn->teamlist, netmsg->parts[1]);
+	        	conn->onTeamDeleteCb(conn->onTeamDeleteCtx, netmsg->parts[1]);
+	        }
+	    } else if(!strcmp(cmd, "ROOMABANDONED")) {
+	    	netconn_leaveRoom(conn);
+	        conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed");
+	    } else if(!strcmp(cmd, "KICKED")) {
+	    	netconn_leaveRoom(conn);
+	    	conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked");
+	    } else if(!strcmp(cmd, "JOINED")) {
+	        if(netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad JOINED message");
+	        } else {
+				for(int i = 1; i < netmsg->partCount; ++i)
+				{
+					bool isMe = !strcmp(conn->playerName, netmsg->parts[i]);
+					if (isMe) {
+						conn->netconnState = NETCONN_STATE_ROOM;
+						conn->onEnterRoomCb(conn->onEnterRoomCtx, conn->isChief);
+					}
+
+					conn->onRoomJoinCb(conn->onRoomJoinCtx, netmsg->parts[i]);
+				}
+	        }
+	    } else if(!strcmp(cmd, "LOBBY:JOINED")) {
+	        if(netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad JOINED message");
+	        } else {
+				for(int i = 1; i < netmsg->partCount; ++i)
+				{
+					bool isMe = !strcmp(conn->playerName, netmsg->parts[i]);
+					if (isMe && conn->netconnState == NETCONN_STATE_CONNECTING) {
+						conn->onConnectedCb(conn->onConnectedCtx);
+						conn->netconnState = NETCONN_STATE_LOBBY;
+					}
+					conn->onLobbyJoinCb(conn->onLobbyJoinCtx, netmsg->parts[i]);
+				}
+	        }
+	    } else if(!strcmp(cmd, "LEFT")) {
+	        if(netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad LEFT message");
+	        } else {
+	        	conn->onRoomLeaveCb(conn->onRoomLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
+	        }
+	    } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) {
+	    	const char *subcmd = netmsg->parts[1];
+	    	if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) {
+	    		flib_room *room = flib_room_from_netmsg(netmsg->parts+2);
+	    		if(room) {
+	    			conn->onRoomAddCb(conn->onRoomAddCtx, room);
+	    		}
+	    		flib_room_destroy(room);
+			} else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) {
+				flib_room *room = flib_room_from_netmsg(netmsg->parts+3);
+				if(room) {
+	    			conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], room);
+	    		}
+				flib_room_destroy(room);
+			} else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) {
+				conn->onRoomDeleteCb(conn->onRoomDeleteCtx, netmsg->parts[2]);
+			} else {
+				flib_log_w("Net: Unknown or malformed ROOM subcommand: %s", subcmd);
+			}
+	    } else if(!strcmp(cmd, "LOBBY:LEFT")) {
+	        if(netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad LOBBY:LEFT message");
+	        } else {
+	        	conn->onLobbyLeaveCb(conn->onLobbyLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL);
+	        }
+	    } else if (!strcmp(cmd, "RUN_GAME")) {
+	        conn->onRunGameCb(conn->onRunGameCtx);
+	    } else if (!strcmp(cmd, "ASKPASSWORD")) {
+	    	conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName);
+	    } else if (!strcmp(cmd, "NOTICE")) {
+	        if(netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad NOTICE message");
+	        } else {
+				errno = 0;
+				long n = strtol(netmsg->parts[1], NULL, 10);
+				if(errno) {
+					flib_log_w("Net: Bad NOTICE message");
+				} else if(n==0) {
+					conn->onNickTakenCb(conn->onNickTakenCtx, conn->playerName);
+				} else {
+					flib_log_w("Net: Unknown NOTICE message: %l", n);
+				}
+	        }
+	    } else if (!strcmp(cmd, "TEAM_ACCEPTED")) {
+	        if (netmsg->partCount != 2 || conn->netconnState!=NETCONN_STATE_ROOM) {
+	            flib_log_w("Net: Bad TEAM_ACCEPTED message");
+	        } else {
+	        	flib_team *team = flib_team_copy(flib_teamlist_find(&conn->pendingTeamlist, netmsg->parts[1]));
+	        	if(team) {
+	        		flib_teamlist_insert(&conn->teamlist, team, conn->teamlist.teamCount);
+	        		flib_teamlist_delete(&conn->pendingTeamlist, netmsg->parts[1]);
+	        	} else {
+	        		flib_log_e("Team accepted that was not requested: %s", netmsg->parts[1]);
+	        	}
+	        	conn->onTeamAcceptedCb(conn->onTeamAcceptedCtx, netmsg->parts[1]);
+	        }
+	    } else if (!strcmp(cmd, "CFG")) {
+	        if(netmsg->partCount < 3 || conn->netconnState!=NETCONN_STATE_ROOM) {
+	            flib_log_w("Net: Bad CFG message");
+	        } else {
+	        	const char *subcmd = netmsg->parts[1];
+				if(!strcmp(subcmd, "SCHEME") && netmsg->partCount == flib_meta.modCount + flib_meta.settingCount + 3) {
+					flib_scheme *cfg = flib_scheme_from_netmsg(netmsg->parts+2);
+					if(cfg) {
+						flib_scheme_destroy(conn->scheme);
+						conn->scheme = cfg;
+						conn->onSchemeChangedCb(conn->onSchemeChangedCtx, cfg);
+					} else {
+						flib_log_e("Error processing CFG SCHEME message");
+					}
+				} else if(!strcmp(subcmd, "FULLMAPCONFIG") && netmsg->partCount == 7) {
+					flib_map *map = flib_map_from_netmsg(netmsg->parts+2);
+					if(map) {
+						flib_map_destroy(conn->map);
+						conn->map = map;
+						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_FULL);
+					} else {
+						flib_log_e("Error processing CFG FULLMAPCONFIG message");
+					}
+				} else if(!strcmp(subcmd, "MAP") && netmsg->partCount == 3) {
+					char *mapname = flib_strdupnull(netmsg->parts[2]);
+					if(mapname) {
+						free(conn->map->name);
+						conn->map->name = mapname;
+						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAP);
+					} else {
+						flib_log_e("Error processing CFG MAP message");
+					}
+				} else if(!strcmp(subcmd, "THEME") && netmsg->partCount == 3) {
+					char *themename = flib_strdupnull(netmsg->parts[2]);
+					if(themename) {
+						free(conn->map->theme);
+						conn->map->theme = themename;
+						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_THEME);
+					} else {
+						flib_log_e("Error processing CFG THEME message");
+					}
+				} else if(!strcmp(subcmd, "SEED") && netmsg->partCount == 3) {
+					char *seed = flib_strdupnull(netmsg->parts[2]);
+					if(seed) {
+						free(conn->map->seed);
+						conn->map->seed = seed;
+						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_SEED);
+					} else {
+						flib_log_e("Error processing CFG SEED message");
+					}
+				} else if(!strcmp(subcmd, "TEMPLATE") && netmsg->partCount == 3) {
+					conn->map->templateFilter = atoi(netmsg->parts[2]);
+					conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_TEMPLATE);
+				} else if(!strcmp(subcmd, "MAPGEN") && netmsg->partCount == 3) {
+					conn->map->mapgen = atoi(netmsg->parts[2]);
+					conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAPGEN);
+				} else if(!strcmp(subcmd, "MAZE_SIZE") && netmsg->partCount == 3) {
+					conn->map->mazeSize = atoi(netmsg->parts[2]);
+					conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_MAZE_SIZE);
+				} else if(!strcmp(subcmd, "DRAWNMAP") && netmsg->partCount == 3) {
+					size_t drawnMapSize = 0;
+					uint8_t *drawnMapData = NULL;
+					if(!flib_drawnmapdata_from_netmsg(netmsg->parts[2], &drawnMapData, &drawnMapSize)) {
+						free(conn->map->drawData);
+						conn->map->drawData = drawnMapData;
+						conn->map->drawDataSize = drawnMapSize;
+						conn->onMapChangedCb(conn->onMapChangedCtx, conn->map, NETCONN_MAPCHANGE_DRAWNMAP);
+					} else {
+						flib_log_e("Error processing CFG DRAWNMAP message");
+					}
+				} else if(!strcmp(subcmd, "SCRIPT") && netmsg->partCount == 3) {
+					netconn_setScript(conn, netmsg->parts[2]);
+					conn->onScriptChangedCb(conn->onScriptChangedCtx, netmsg->parts[2]);
+				} else if(!strcmp(subcmd, "AMMO") && netmsg->partCount == 4) {
+					flib_weaponset *weapons = flib_weaponset_from_ammostring(netmsg->parts[2], netmsg->parts[3]);
+					if(weapons) {
+						flib_weaponset_destroy(conn->weaponset);
+						conn->weaponset = weapons;
+						conn->onWeaponsetChangedCb(conn->onWeaponsetChangedCtx, weapons);
+					} else {
+						flib_log_e("Error processing CFG AMMO message");
+					}
+				} else {
+					flib_log_w("Net: Unknown or malformed CFG subcommand: %s", subcmd);
+				}
+	        }
+	    } else if (!strcmp(cmd, "HH_NUM")) {
+	        if (netmsg->partCount != 3 || conn->netconnState!=NETCONN_STATE_ROOM) {
+	            flib_log_w("Net: Bad HH_NUM message");
+	        } else {
+	        	int hogs = atoi(netmsg->parts[2]);
+	        	if(hogs<=0 || hogs>HEDGEHOGS_PER_TEAM) {
+	        		flib_log_w("Net: Bad HH_NUM message: %s hogs", netmsg->parts[2]);
+	        	} else {
+	        		flib_team *team = flib_teamlist_find(&conn->teamlist, netmsg->parts[1]);
+	        		if(team) {
+	        			team->hogsInGame = hogs;
+	        		} else {
+	        			flib_log_e("HH_NUM message for unknown team %s", netmsg->parts[1]);
+	        		}
+	        		conn->onHogCountChangedCb(conn->onHogCountChangedCtx, netmsg->parts[1], hogs);
+	        	}
+	        }
+	    } else if (!strcmp(cmd, "TEAM_COLOR")) {
+	        if (netmsg->partCount != 3 || conn->netconnState!=NETCONN_STATE_ROOM) {
+	            flib_log_w("Net: Bad TEAM_COLOR message");
+	        } else {
+	        	long color;
+	        	if(sscanf(netmsg->parts[2], "%lu", &color) && color>=0 && color<flib_teamcolor_count) {
+	        		flib_team *team = flib_teamlist_find(&conn->teamlist, netmsg->parts[1]);
+	        		if(team) {
+	        			team->colorIndex = color;
+	        		} else {
+	        			flib_log_e("TEAM_COLOR message for unknown team %s", netmsg->parts[1]);
+	        		}
+	        		conn->onTeamColorChangedCb(conn->onTeamColorChangedCtx, netmsg->parts[1], color);
+	        	} else {
+	        		flib_log_w("Net: Bad TEAM_COLOR message: Color %s", netmsg->parts[2]);
+	        	}
+	        }
+	    } else if (!strcmp(cmd, "EM")) {
+	        if(netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad EM message");
+	        } else {
+	        	for(int i = 1; i < netmsg->partCount; ++i) {
+					char *out = NULL;
+					size_t outlen;
+					bool ok = base64_decode_alloc(netmsg->parts[i], strlen(netmsg->parts[i]), &out, &outlen);
+					if(ok && outlen) {
+						conn->onEngineMessageCb(conn->onEngineMessageCtx, (uint8_t*)out, outlen);
+					} else {
+						flib_log_e("Net: Malformed engine message: %s", netmsg->parts[i]);
+					}
+					free(out);
+	        	}
+	        }
+	    } else if (!strcmp(cmd, "BYE")) {
+	        if (netmsg->partCount < 2) {
+	            flib_log_w("Net: Bad BYE message");
+	        } else {
+				conn->netconnState = NETCONN_STATE_DISCONNECTED;
+				if (!strcmp(netmsg->parts[1], "Authentication failed")) {
+					conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_AUTH_FAILED, netmsg->parts[1]);
+				} else {
+					conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_NORMAL, netmsg->parts[1]);
+				}
+				exit = true;
+	        }
+	    } else if (!strcmp(cmd, "ADMIN_ACCESS")) {
+	    	// deprecated
+	    } else if (!strcmp(cmd, "ROOM_CONTROL_ACCESS")) {
+	    	// deprecated
+	    } else {
+	    	flib_log_w("Unknown server command: %s", cmd);
+	    }
+		flib_netmsg_destroy(netmsg);
+	}
+
+	if(!exit && !conn->destroyRequested && !flib_netbase_connected(net)) {
+		conn->netconnState = NETCONN_STATE_DISCONNECTED;
+		conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_CONNLOST, "Connection lost");
+	}
+}
+
+void flib_netconn_tick(flib_netconn *conn) {
+	if(!log_badargs_if(conn==NULL)
+			&& !log_w_if(conn->running, "Call to flib_netconn_tick from a callback")
+			&& !log_w_if(conn->netconnState == NETCONN_STATE_DISCONNECTED, "We are already done.")) {
+		conn->running = true;
+		flib_netconn_wrappedtick(conn);
+		conn->running = false;
+
+		if(conn->destroyRequested) {
+			flib_netconn_destroy(conn);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,654 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * This file contains functions for communicating with a Hedgewars server to chat, prepare and play
+ * rounds of Hedgewars.
+ *
+ * To use this, first create a netconn object by calling flib_netconn_create. This will start the
+ * connection to the game server (which might fail right away, the function returns null then). You
+ * should also register your callback functions right at the start to ensure you don't miss any
+ * callbacks.
+ *
+ * In order to allow the netconn to run, you should regularly call flib_netconn_tick(), which
+ * performs network I/O and calls your callbacks on interesting events.
+ *
+ * When the connection is closed, you will receive the onDisconnect callback. This is the signal to
+ * destroy the netconn and stop calling tick().
+ *
+ * The connection process lasts from the time you create the netconn until you receive the
+ * onConnected callback (or onDisconnected in case something goes wrong). During that time, you
+ * might receive the onNickTaken and onPasswordRequest callbacks; see their description for more
+ * information on how to handle them. You could also receive other callbacks during connecting (e.g.
+ * about the room list), but it should be safe to ignore them.
+ *
+ * Once you are connected, you are in the lobby, and you can enter rooms and leave them again. The
+ * room and lobby states have different protocols, so many commands only work in either one or the
+ * other. If you are in a room you might also be in a game, but most of the functions behave the
+ * same ingame as in a room.
+ *
+ * The state changes from lobby to room when the server tells you that you just entered one, which
+ * will also trigger the onEnterRoom callback. This usually happens in reply to either a joinRoom,
+ * createRoom or playerFollow command.
+ *
+ * The state changes back to lobby when the room is dissolved, when you are kicked from the room, or
+ * when you actively leave the room using flib_netconn_send_leaveRoom. The first two events will
+ * trigger the onLeaveRoom callback.
+ */
+
+#ifndef NETCONN_H_
+#define NETCONN_H_
+
+#include "../model/gamesetup.h"
+#include "../model/scheme.h"
+#include "../model/room.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define NETCONN_STATE_CONNECTING 0
+#define NETCONN_STATE_LOBBY 1
+#define NETCONN_STATE_ROOM 2
+#define NETCONN_STATE_DISCONNECTED 10
+
+#define NETCONN_DISCONNECT_NORMAL 0				// The connection was closed normally
+#define NETCONN_DISCONNECT_SERVER_TOO_OLD 1		// The server has a lower protocol version than we do
+#define NETCONN_DISCONNECT_AUTH_FAILED 2		// You sent a password with flib_netconn_send_password that was not accepted
+#define NETCONN_DISCONNECT_CONNLOST 3			// The network connection was lost
+#define NETCONN_DISCONNECT_INTERNAL_ERROR 100	// Something went wrong in frontlib itself
+
+#define NETCONN_ROOMLEAVE_ABANDONED 0			// The room was closed because the chief left
+#define NETCONN_ROOMLEAVE_KICKED 1				// You have been kicked from the room
+
+#define NETCONN_MSG_TYPE_PLAYERINFO 0			// A response to flib_netconn_send_playerInfo
+#define NETCONN_MSG_TYPE_SERVERMESSAGE 1		// The welcome message when connecting to the lobby
+#define NETCONN_MSG_TYPE_WARNING 2				// A general warning message
+#define NETCONN_MSG_TYPE_ERROR 3				// A general error message
+
+#define NETCONN_MAPCHANGE_FULL 0
+#define NETCONN_MAPCHANGE_MAP 1
+#define NETCONN_MAPCHANGE_MAPGEN 2
+#define NETCONN_MAPCHANGE_DRAWNMAP 3
+#define NETCONN_MAPCHANGE_MAZE_SIZE 4
+#define NETCONN_MAPCHANGE_TEMPLATE 5
+#define NETCONN_MAPCHANGE_THEME 6
+#define NETCONN_MAPCHANGE_SEED 7
+
+typedef struct _flib_netconn flib_netconn;
+
+/**
+ * Create a new netplay connection with these parameters.
+ * The path to the data directory must end with a path delimiter (e.g. C:\Games\Hedgewars\Data\)
+ */
+flib_netconn *flib_netconn_create(const char *playerName, const char *dataDirPath, const char *host, int port);
+void flib_netconn_destroy(flib_netconn *conn);
+
+/**
+ * Perform I/O operations and call callbacks if something interesting happens.
+ * Should be called regularly.
+ */
+void flib_netconn_tick(flib_netconn *conn);
+
+/**
+ * Are you currently the owner of this room? The return value only makes sense in
+ * NETCONN_STATE_ROOM and NETCONN_STATE_INGAME states.
+ */
+bool flib_netconn_is_chief(flib_netconn *conn);
+
+/**
+ * Returns the playername. This is *probably* the one provided on creation, but if that name was
+ * already taken, a different one could have been set by the onNickTaken callback or its default
+ * implementation.
+ */
+const char *flib_netconn_get_playername(flib_netconn *conn);
+
+/**
+ * Generate a game setup from the current room state.
+ * Returns NULL if the room state does not contain enough information for a complete game setup,
+ * or if an error occurs.
+ *
+ * The new gamesetup must be destroyed with flib_gamesetup_destroy().
+ */
+flib_gamesetup *flib_netconn_create_gamesetup(flib_netconn *conn);
+
+
+
+
+// Send functions needed when connecting and disconnecting
+
+	/**
+	 * Request a different nickname.
+	 * This function only makes sense in reaction to an onNickTaken callback, because the netconn
+	 * automatically requests the nickname you provide on creation, and once the server accepts the
+	 * nickname it can no longer be changed.
+	 */
+	int flib_netconn_send_nick(flib_netconn *conn, const char *nick);
+
+	/**
+	 * Send the password in reply to a password request.
+	 * If the server does not accept the password, you will be disconnected
+	 * (NETCONN_DISCONNECT_AUTH_FAILED)
+	 */
+	int flib_netconn_send_password(flib_netconn *conn, const char *passwd);
+
+	/**
+	 * Tell the server that you want to leave. If successful, the server will disconnect you.
+	 */
+	int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg);
+
+
+// Send functions that make sense both in the lobby and in rooms
+
+	/**
+	 * Send a chat message. This message is either sent to the lobby or the room, depending on
+	 * whether you are in a room at the moment. The message is not echoed back to you.
+	 */
+	int flib_netconn_send_chat(flib_netconn *conn, const char *chat);
+
+	/**
+	 * Kick a player. This has different meanings in the lobby and in a room;
+	 * In the lobby, it will kick the player from the server, and you need to be a server admin to
+	 * do it. In a room, it will kick the player from the room, and you need to be room chief.
+	 */
+	int flib_netconn_send_kick(flib_netconn *conn, const char *playerName);
+
+	/**
+	 * Request information about a player (e.g. current room, version, partial IP). If the action
+	 * succeeds, you will receive an onMessage callback with NETCONN_MSG_TYPE_PLAYERINFO containing
+	 * the requested information.
+	 */
+	int flib_netconn_send_playerInfo(flib_netconn *conn, const char *playerName);
+
+
+// Send functions that only make sense in the lobby
+
+	/**
+	 * Request an update of the room list. Only makes sense when in lobby state.
+	 * If the action succeeds, you will receive an onRoomlist callback containing the current room
+	 * data.
+	 */
+	int flib_netconn_send_request_roomlist(flib_netconn *conn);
+
+	/**
+	 * Join a room as guest (not chief). Only makes sense when in lobby state. If the action
+	 * succeeds, you will receive an onEnterRoom callback with chief=false followed by other
+	 * callbacks with current room information.
+	 */
+	int flib_netconn_send_joinRoom(flib_netconn *conn, const char *room);
+
+	/**
+	 * Follow a player. Only valid in the lobby. If the player is in a room (or in a game), this
+	 * command is analogous to calling flib_netconn_send_joinRoom with that room.
+	 */
+	int flib_netconn_send_playerFollow(flib_netconn *conn, const char *playerName);
+
+	/**
+	 * Create and join a new room. Only makes sense when in lobby state. If the action succeeds,
+	 * you will receive an onEnterRoom callback with chief=true.
+	 */
+	int flib_netconn_send_createRoom(flib_netconn *conn, const char *room);
+
+	/**
+	 * Ban a player. The scope of this ban depends on whether you are in a room or in the lobby.
+	 * In a room, you need to be the room chief, and the ban will apply to the room only. In the
+	 * lobby, you need to be server admin to ban someone, and the ban applies to the entire server.
+	 */
+	int flib_netconn_send_ban(flib_netconn *conn, const char *playerName);
+
+	/**
+	 * Does something administrator-y. At any rate you need to be an administrator and in the lobby
+	 * to use this command.
+	 */
+	int flib_netconn_send_clearAccountsCache(flib_netconn *conn);
+
+	/**
+	 * Sets a server variable to the indicated value. Only makes sense if you are server admin and
+	 * in the lobby. Known variables are MOTD_NEW, MOTD_OLD and LATEST_PROTO. MOTD_OLD is shown to
+	 * players with older protocol versions, to inform them that they might want to update.
+	 */
+	int flib_netconn_send_setServerVar(flib_netconn *conn, const char *name, const char *value);
+
+	/**
+	 * Queries all server variables. Only makes sense if you are server admin and in the lobby.
+	 * If the action succeeds, you will receive several onServerVar callbacks with the
+	 * current values of all server variables.
+	 */
+	int flib_netconn_send_getServerVars(flib_netconn *conn);
+
+
+// Send functions that only make sense in a room
+
+	/**
+	 * Leave the room for the lobby. Only makes sense in room state. msg can be NULL if you don't
+	 * want to send a message. The server always accepts a part command, so once you send it off,
+	 * you can just assume that you are back in the lobby.
+	 */
+	int flib_netconn_send_leaveRoom(flib_netconn *conn, const char *msg);
+
+	/**
+	 * Change your "ready" status in the room. Only makes sense when in room state. If the action
+	 * succeeds, you will receive an onClientFlags callback containing the change.
+	 */
+	int flib_netconn_send_toggleReady(flib_netconn *conn);
+
+	/**
+	 * Add a team to the current room. Apart from the "fixed" team information, this also includes
+	 * the color, but not the number of hogs. Only makes sense when in room state. If the action
+	 * succeeds, you will receive an onTeamAccepted callback with the name of the team.
+	 *
+	 * Notes: Technically, sending a color here is the only way for a non-chief to set the color of
+	 * her own team. The server remembers this color and even generates a separate teamColor message
+	 * to inform everyone of it. However, at the moment the frontends generally override this color
+	 * with one they choose themselves in order to deal with unfortunate behavior of the QtFrontend,
+	 * which always sends color index 0 when adding a team but thinks that the team has a random
+	 * color. The chief always sends a new color in order to bring the QtFrontend back into sync.
+	 */
+	int flib_netconn_send_addTeam(flib_netconn *conn, const flib_team *team);
+
+	/**
+	 * Remove the team with the name teamname. Only makes sense when in room state.
+	 * The server does not send a reply on success.
+	 */
+	int flib_netconn_send_removeTeam(flib_netconn *conn, const char *teamname);
+
+
+// Send functions that only make sense in a room and if you are room chief
+
+	/**
+	 * Rename the current room. Only makes sense in room state and if you are chief. If the action
+	 * succeeds, you (and everyone else on the server) will receive an onRoomUpdate message
+	 * containing the change.
+	 */
+	int flib_netconn_send_renameRoom(flib_netconn *conn, const char *roomName);
+
+	/**
+	 * Set the number of hogs for a team. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_teamHogCount(flib_netconn *conn, const char *teamname, int hogcount);
+
+	/**
+	 * Set the teamcolor of a team. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, int colorIndex);
+
+	/**
+	 * Set the weaponset for the room. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_weaponset(flib_netconn *conn, const flib_weaponset *weaponset);
+
+	/**
+	 * Set the map for the room. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_map(flib_netconn *conn, const flib_map *map);
+
+	/**
+	 * Set the mapname. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_mapName(flib_netconn *conn, const char *mapName);
+
+	/**
+	 * Set the map generator (regular, maze, drawn, named). Only makes sense in room state and if
+	 * you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_mapGen(flib_netconn *conn, int mapGen);
+
+	/**
+	 * Set the map template for regular maps. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_mapTemplate(flib_netconn *conn, int templateFilter);
+
+	/**
+	 * Set the maze template (maze size) for mazes. Only makes sense in room state and if you are
+	 * chief. The server does not send a reply.
+	 */
+	int flib_netconn_send_mapMazeSize(flib_netconn *conn, int mazeSize);
+
+	/**
+	 * Set the seed for the map. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_mapSeed(flib_netconn *conn, const char *seed);
+
+	/**
+	 * Set the theme for the map. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_mapTheme(flib_netconn *conn, const char *theme);
+
+	/**
+	 * Set the draw data for the drawn map. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_mapDrawdata(flib_netconn *conn, const uint8_t *drawData, size_t size);
+
+	/**
+	 * Set the script (game style). Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_script(flib_netconn *conn, const char *scriptName);
+
+	/**
+	 * Set the scheme. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_scheme(flib_netconn *conn, const flib_scheme *scheme);
+
+	/**
+	 * Signal that you want to start the game. Only makes sense in room state and if you are chief.
+	 * The server will check whether all players are ready and whether it believes the setup makes
+	 * sense (e.g. more than one clan). If the server is satisfied, you will receive an onRunGame
+	 * callback (all other clients in the room are notified the same way). Otherwise the server
+	 * might answer with a warning, or might not answer at all.
+	 */
+	int flib_netconn_send_startGame(flib_netconn *conn);
+
+	/**
+	 * Allow/forbid players to join the room. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_toggleRestrictJoins(flib_netconn *conn);
+
+	/**
+	 * Allow/forbid adding teams to the room. Only makes sense in room state and if you are chief.
+	 * The server does not send a reply.
+	 */
+	int flib_netconn_send_toggleRestrictTeams(flib_netconn *conn);
+
+
+// Send functions that are only needed for running a game
+
+	/**
+	 * Send a teamchat message, forwarded from the engine. Only makes sense ingame.
+	 * The server does not send a reply. In contrast to a Chat message, the server
+	 * automatically converts this into an engine message and passes it on to the other
+	 * clients.
+	 */
+	int flib_netconn_send_teamchat(flib_netconn *conn, const char *msg);
+
+	/**
+	 * Send an engine message. Only makes sense when ingame. In a networked game, you have to pass
+	 * all the engine messages from the engine here, and they will be spread to all other clients
+	 * in the game to keep the game in sync.
+	 */
+	int flib_netconn_send_engineMessage(flib_netconn *conn, const uint8_t *message, size_t size);
+
+	/**
+	 * Inform the server that the round has ended. Call this when the engine has disconnected,
+	 * passing 1 if the round ended normally, 0 otherwise.
+	 */
+	int flib_netconn_send_roundfinished(flib_netconn *conn, bool withoutError);
+
+
+
+
+
+// Callbacks that are important for connecting/disconnecting
+
+	/**
+	 * onNickTaken is called when connecting to the server, if it turns out that there is already a
+	 * player with the same nick.
+	 * In order to proceed, a new nickname needs to be sent to the server using
+	 * flib_netconn_send_nick() (or of course you can bail out and send a QUIT).
+	 * If you don't set a callback, the netconn will automatically react by generating a new name.
+	 */
+	void flib_netconn_onNickTaken(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+
+	/**
+	 * When connecting with a registered nickname, the server will ask for a password before
+	 * admitting you in. This callback is called when that happens. As a reaction, you can send the
+	 * password using flib_netconn_send_password. If you don't register a callback, the default
+	 * behavior is to just quit in a way that will cause a disconnect with
+	 * NETCONN_DISCONNECT_AUTH_FAILED.
+	 *
+	 * You can't just choose a new nickname when you receive this callback, because at that point
+	 * the server has already accepted your nick.
+	 */
+	void flib_netconn_onPasswordRequest(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+
+	/**
+	 * This is called when the server has accepted our nickname (and possibly password) and we have
+	 * entered the lobby.
+	 */
+	void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context), void* context);
+
+	/**
+	 * This is always the last callback (unless the netconn is destroyed early), and the netconn
+	 * should be destroyed when it is received. The reason for the disconnect is passed as one of
+	 * the NETCONN_DISCONNECT_ constants. Sometimes a message is included as well, but that
+	 * parameter might also be NULL.
+	 */
+	void flib_netconn_onDisconnected(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void* context);
+
+
+// Callbacks that make sense in most situations
+
+	/**
+	 * Callback for several informational messages that should be displayed to the user
+	 * (e.g. in the chat window), but do not require a reaction. If a game is running, you might
+	 * want to redirect some of these messages to the engine as well so the user will see them.
+	 */
+	void flib_netconn_onMessage(flib_netconn *conn, void (*callback)(void *context, int msgtype, const char *msg), void* context);
+
+	/**
+	 * We received a chat message. Where this message belongs depends on the current state
+	 * (lobby/room). If a game is running the message should be passed to the engine.
+	 */
+	void flib_netconn_onChat(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *msg), void* context);
+
+	/**
+	 * Callbacks for incremental room list updates. They will fire whenever these events occur,
+	 * even before you first query the actual roomlist - so be sure not to blindly reference your
+	 * room list in these callbacks. The server currently only sends updates when a room changes
+	 * its name, so in order to update other room information you need to query the roomlist again
+	 * (see send_request_roomlist / onRoomlist).
+	 */
+	void flib_netconn_onRoomAdd(flib_netconn *conn, void (*callback)(void *context, const flib_room *room), void* context);
+	void flib_netconn_onRoomDelete(flib_netconn *conn, void (*callback)(void *context, const char *name), void* context);
+	void flib_netconn_onRoomUpdate(flib_netconn *conn, void (*callback)(void *context, const char *oldName, const flib_room *room), void* context);
+
+	/**
+	 * Callbacks for players joining or leaving the lobby. In contrast to the roomlist updates, you
+	 * will get a JOIN callback for every player already on the server when you join (and there is
+	 * no direct way to query the current playerlist)
+	 *
+	 * NOTE: partMessage may be NULL.
+	 */
+	void flib_netconn_onLobbyJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+	void flib_netconn_onLobbyLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMessage), void* context);
+
+	/**
+	 * This is called when the server informs us that one or more flags associated with a
+	 * player/client have changed.
+	 *
+	 * nick is the name of the player, flags is a string containing one character for each modified
+	 * flag (see below), and newFlagState signals whether the flags should be set to true or false.
+	 *
+	 * Some of these flags are important for protocol purposes (especially if they are set for you)
+	 * while others are just informational. Also, some flags are only relevant for players who are
+	 * in the same room as you, and the server will not inform you if they change for others.
+	 *
+	 * These are the currently known/used flags:
+	 * a: Server admin. Always updated.
+	 * h: Room chief. Updated when in the same room.
+	 * r: Ready to play. Updated when in the same room.
+	 * u: Registered user. Always updated.
+	 *
+	 * The server tells us the 'a' and 'u' flags for all players when we first join the lobby, and
+	 * also tells us the 'r' and 'h' flags when we join or create a room. It assumes that all flags
+	 * are initially false, so it will typically only tell you to set certain flags to true when
+	 * transmitting the initial states. Reset the 'h' and 'r' flags to false when leaving a room,
+	 * or when entering room state, to arrive at the right state for each player.
+	 *
+	 * The room chief state of yourself is particularly important because it determines whether you
+	 * can modify settings of the current room. Generally, when you create a room you start out
+	 * being room chief, and when you join an existing room you are not. However, if the original
+	 * chief leaves a room, the server can choose a new chief, and if that happens the chief flag
+	 * will be transferred to someone else.
+	 */
+	void flib_netconn_onClientFlags(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *flags, bool newFlagState), void *context);
+
+// Callbacks that happen only in response to specific requests
+
+	/**
+	 * Response to flib_netconn_send_request_roomlist().
+	 * The rooms array contains the current state of all rooms on the server.
+	 */
+	void flib_netconn_onRoomlist(flib_netconn *conn, void (*callback)(void *context, const flib_room **rooms, int roomCount), void* context);
+
+	/**
+	 * Response to flib_netconn_send_joinRoom, flib_netconn_send_playerFollow or
+	 * flib_netconn_send_createRoom.
+	 *
+	 * You just left the lobby and entered a room.
+	 * If chief is true, you can and should send a full configuration for the room now. This
+	 * consists of ammo, scheme, script and map, where map apparently has to come last.
+	 */
+	void flib_netconn_onEnterRoom(flib_netconn *conn, void (*callback)(void *context, bool chief), void *context);
+
+	/**
+	 * Response to flib_netconn_send_addTeam.
+	 * The server might reject your team for several reasons, e.g. because it has the same name as
+	 * an existing team, or because the room chief restricted adding new teams. If the team is
+	 * accepted by the server, this callback is fired.
+	 *
+	 * If you are the room chief, you are expected to provide the hog count for your own team now
+	 * using flib_netconn_send_teamHogCount. The color of the team is already set to the one you
+	 * provided in addTeam.
+	 */
+	void flib_netconn_onTeamAccepted(flib_netconn *conn, void (*callback)(void *context, const char *team), void *context);
+
+	/**
+	 * When you query the server vars with flib_netconn_send_getServerVars (only works as admin),
+	 * the server replies with a list of them. This callback is called for each entry in that list.
+	 */
+	void flib_netconn_onServerVar(flib_netconn *conn, void (*callback)(void *context, const char *name, const char *value), void *context);
+
+
+// Callbacks that are only relevant in a room
+
+	/**
+	 * You just left a room and entered the lobby again.
+	 * reason is one of the NETCONN_ROOMLEAVE_ constants (usually a kick).
+	 * This will not be called when you actively leave a room using PART.
+	 * Don't confuse with onRoomLeave, which indicates that *someone else* left the room.
+	 */
+	void flib_netconn_onLeaveRoom(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void *context);
+
+	/**
+	 * Someone joined or left the room you are currently in.
+	 * Analogous to onLobbyJoin/leave, you will receive the join callback for all players that are
+	 * already in the room when you join, including for yourself (this is actually how it is
+	 * determined that you joined a room).
+	 *
+	 * However, you will *not* receive onRoomLeave messages for everyone when you leave the room.
+	 */
+	void flib_netconn_onRoomJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context);
+	void flib_netconn_onRoomLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMessage), void* context);
+
+	/**
+	 * A new team was added to the room. The person who adds a team does NOT receive this callback
+	 * (he gets onTeamAccepted instead).
+	 *
+	 * The team does not contain bindings, stats, weaponset, color or the number of hogs (but it is
+	 * assumed to be the default of 4).
+	 *
+	 * If you receive this message and you are the room chief, you may want to send a color and hog
+	 * count for this team using flib_netconn_send_teamHogCount / teamColor for QtFrontend
+	 * compatibility.
+	 *
+	 * The server currently sends another message with the color of the team to the same recipients
+	 * as this teamAdd message, which will trigger an onTeamColorChanged callback. See the
+	 * description of flib_netconn_send_addTeam for more information.
+	 */
+	void flib_netconn_onTeamAdd(flib_netconn *conn, void (*callback)(void *context, const flib_team *team), void *context);
+
+	/**
+	 * A team was removed from the room. The person who removed the team will not receive this
+	 * callback.
+	 */
+	void flib_netconn_onTeamDelete(flib_netconn *conn, void (*callback)(void *context, const char *teamname), void *context);
+
+	/**
+	 * The number of hogs in a team has been changed by the room chief. If you are the chief and
+	 * change the number of hogs yourself, you will not receive this callback.
+	 */
+	void flib_netconn_onHogCountChanged(flib_netconn *conn, void (*callback)(void *context, const char *teamName, int hogs), void *context);
+
+	/**
+	 * The color of a team has been set or changed. The client who set or changed the color will
+	 * not receive this callback.
+	 *
+	 * Normally, only the chief can change the color of a team. However, this message is also
+	 * generated when a team is added, so you can receive it even as chief.
+	 */
+	void flib_netconn_onTeamColorChanged(flib_netconn *conn, void (*callback)(void *context, const char *teamName, int colorIndex), void *context);
+
+	/**
+	 * The room chief has changed the game scheme (or you just joined a room).
+	 * You will not receive this callback if you changed the scheme yourself.
+	 */
+	void flib_netconn_onSchemeChanged(flib_netconn *conn, void (*callback)(void *context, const flib_scheme *scheme), void *context);
+
+	/**
+	 * The room chief has changed the map (or you just joined a room). Only non-chiefs receive these
+	 * messages.
+	 *
+	 * To reduce the number of callback functions, the netconn keeps track of the current map
+	 * settings and always passes the entire current map config, but informs the callee about what
+	 * has changed (see the NETCONN_MAPCHANGE_ constants).
+	 *
+	 * Caution: Due to the way the protocol works, the map might not be complete at this point if it
+	 * is a hand-drawn map, because the "full" map config does not include the drawn map data.
+	 */
+	void flib_netconn_onMapChanged(flib_netconn *conn, void (*callback)(void *context, const flib_map *map, int changetype), void *context);
+
+	/**
+	 * The room chief has changed the game style (or you just joined a room). If you are the chief
+	 * and change the style yourself, you will not receive this callback.
+	 */
+	void flib_netconn_onScriptChanged(flib_netconn *conn, void (*callback)(void *context, const char *script), void *context);
+
+	/**
+	 * The room chief has changed the weaponset (or you just joined a room). If you are the chief
+	 * and change the weaponset yourself, you will not receive this callback.
+	 */
+	void flib_netconn_onWeaponsetChanged(flib_netconn *conn, void (*callback)(void *context, const flib_weaponset *weaponset), void *context);
+
+	/**
+	 * The game is starting. Fire up the engine and join in!
+	 * You can let the netconn generate the right game setup using flib_netconn_create_gamesetup
+	 */
+	void flib_netconn_onRunGame(flib_netconn *conn, void (*callback)(void *context), void *context);
+
+	/**
+	 * You are in a room, a game is in progress, and the server is sending you the new input for the
+	 * engine to keep up to date with the current happenings. Pass it on to the engine using
+	 * flib_gameconn_send_enginemsg.
+	 */
+	void flib_netconn_onEngineMessage(flib_netconn *conn, void (*callback)(void *context, const uint8_t *message, size_t size), void *context);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn_callbacks.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,149 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "netconn_internal.h"
+
+#include "../util/logging.h"
+#include "../util/util.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+static void defaultCallback_onMessage(void *context, int msgtype, const char *msg) {
+	flib_log_i("Net: [%i] %s", msgtype, msg);
+}
+
+static void defaultCallback_onChat(void *context, const char *nick, const char *msg) {
+	flib_log_i("%s: %s", nick, msg);
+}
+
+// Change the name by suffixing it with a number. If it already ends in a number, increase that number by 1.
+static void defaultCallback_onNickTaken(void *context, const char *requestedNick) {
+	flib_netconn *conn = context;
+	size_t namelen = strlen(requestedNick);
+	int digits = 0;
+	while(digits<namelen && isdigit(requestedNick[namelen-1-digits])) {
+		digits++;
+	}
+	long suffix = 0;
+	if(digits>0) {
+		suffix = atol(requestedNick+namelen-digits)+1;
+	}
+	char *newPlayerName = flib_asprintf("%.*s%li", namelen-digits, requestedNick, suffix);
+	if(newPlayerName) {
+		flib_netconn_send_nick(conn, newPlayerName);
+	} else {
+		flib_netconn_send_quit(conn, "Nick already taken.");
+	}
+	free(newPlayerName);
+}
+
+// Default behavior: Quit
+static void defaultCallback_onPasswordRequest(void *context, const char *requestedNick) {
+	flib_netconn_send_quit((flib_netconn*)context, "Authentication failed");
+}
+
+void netconn_clearCallbacks(flib_netconn *conn) {
+	flib_netconn_onMessage(conn, NULL, NULL);
+	flib_netconn_onConnected(conn, NULL, NULL);
+	flib_netconn_onDisconnected(conn, NULL, NULL);
+	flib_netconn_onRoomlist(conn, NULL, NULL);
+	flib_netconn_onRoomAdd(conn, NULL, NULL);
+	flib_netconn_onRoomDelete(conn, NULL, NULL);
+	flib_netconn_onRoomUpdate(conn, NULL, NULL);
+	flib_netconn_onClientFlags(conn, NULL, NULL);
+	flib_netconn_onChat(conn, NULL, NULL);
+	flib_netconn_onLobbyJoin(conn, NULL, NULL);
+	flib_netconn_onLobbyLeave(conn, NULL, NULL);
+	flib_netconn_onRoomJoin(conn, NULL, NULL);
+	flib_netconn_onRoomLeave(conn, NULL, NULL);
+	flib_netconn_onNickTaken(conn, NULL, NULL);
+	flib_netconn_onPasswordRequest(conn, NULL, NULL);
+	flib_netconn_onEnterRoom(conn, NULL, NULL);
+	flib_netconn_onLeaveRoom(conn, NULL, NULL);
+	flib_netconn_onTeamAdd(conn, NULL, NULL);
+	flib_netconn_onTeamDelete(conn, NULL, NULL);
+	flib_netconn_onRunGame(conn, NULL, NULL);
+	flib_netconn_onTeamAccepted(conn, NULL, NULL);
+	flib_netconn_onHogCountChanged(conn, NULL, NULL);
+	flib_netconn_onTeamColorChanged(conn, NULL, NULL);
+	flib_netconn_onEngineMessage(conn, NULL, NULL);
+	flib_netconn_onSchemeChanged(conn, NULL, NULL);
+	flib_netconn_onMapChanged(conn, NULL, NULL);
+	flib_netconn_onScriptChanged(conn, NULL, NULL);
+	flib_netconn_onWeaponsetChanged(conn, NULL, NULL);
+	flib_netconn_onServerVar(conn, NULL, NULL);
+}
+
+/**
+ * This macro generates a callback setter function. It uses the name of the callback to
+ * automatically generate the function name and the fields to set, so a consistent naming
+ * convention needs to be enforced (not that that is a bad thing). If null is passed as
+ * callback to the generated function, the defaultCb will be set instead (with conn
+ * as the context).
+ */
+#define GENERATE_CB_SETTER(cbName, cbParameterTypes, defaultCb) \
+	void flib_netconn_##cbName(flib_netconn *conn, void (*callback)cbParameterTypes, void *context) { \
+		if(!log_badargs_if(conn==NULL)) { \
+			conn->cbName##Cb = callback ? callback : &defaultCb; \
+			conn->cbName##Ctx = callback ? context : conn; \
+		} \
+	}
+
+/**
+ * Generate a callback setter function like GENERATE_CB_SETTER, and automatically generate a
+ * no-op callback function as well that is used as default.
+ */
+#define GENERATE_CB_SETTER_AND_DEFAULT(cbName, cbParameterTypes) \
+	static void _noop_callback_##cbName cbParameterTypes {} \
+	GENERATE_CB_SETTER(cbName, cbParameterTypes, _noop_callback_##cbName)
+
+GENERATE_CB_SETTER(onMessage, (void *context, int msgtype, const char *msg), defaultCallback_onMessage);
+GENERATE_CB_SETTER_AND_DEFAULT(onConnected, (void *context));
+GENERATE_CB_SETTER_AND_DEFAULT(onDisconnected, (void *context, int reason, const char *message));
+GENERATE_CB_SETTER_AND_DEFAULT(onRoomlist, (void *context, const flib_room **rooms, int roomCount));
+GENERATE_CB_SETTER_AND_DEFAULT(onRoomAdd, (void *context, const flib_room *room));
+GENERATE_CB_SETTER_AND_DEFAULT(onRoomDelete, (void *context, const char *name));
+GENERATE_CB_SETTER_AND_DEFAULT(onRoomUpdate, (void *context, const char *oldName, const flib_room *room));
+GENERATE_CB_SETTER_AND_DEFAULT(onClientFlags, (void *context, const char *nick, const char *flags, bool newFlagState));
+GENERATE_CB_SETTER(onChat, (void *context, const char *nick, const char *msg), defaultCallback_onChat);
+GENERATE_CB_SETTER_AND_DEFAULT(onLobbyJoin, (void *context, const char *nick));
+GENERATE_CB_SETTER_AND_DEFAULT(onLobbyLeave, (void *context, const char *nick, const char *partMsg));
+GENERATE_CB_SETTER_AND_DEFAULT(onRoomJoin, (void *context, const char *nick));
+GENERATE_CB_SETTER_AND_DEFAULT(onRoomLeave, (void *context, const char *nick, const char *partMessage));
+GENERATE_CB_SETTER(onNickTaken, (void *context, const char *nick), defaultCallback_onNickTaken);
+GENERATE_CB_SETTER(onPasswordRequest, (void *context, const char *nick), defaultCallback_onPasswordRequest);
+GENERATE_CB_SETTER_AND_DEFAULT(onEnterRoom, (void *context, bool chief));
+GENERATE_CB_SETTER_AND_DEFAULT(onLeaveRoom, (void *context, int reason, const char *message));
+GENERATE_CB_SETTER_AND_DEFAULT(onTeamAdd, (void *context, const flib_team *team));
+GENERATE_CB_SETTER_AND_DEFAULT(onTeamDelete, (void *context, const char *teamname));
+GENERATE_CB_SETTER_AND_DEFAULT(onRunGame, (void *context));
+GENERATE_CB_SETTER_AND_DEFAULT(onTeamAccepted, (void *context, const char *teamName));
+GENERATE_CB_SETTER_AND_DEFAULT(onHogCountChanged, (void *context, const char *teamName, int hogs));
+GENERATE_CB_SETTER_AND_DEFAULT(onTeamColorChanged, (void *context, const char *teamName, int colorIndex));
+GENERATE_CB_SETTER_AND_DEFAULT(onEngineMessage, (void *context, const uint8_t *message, size_t size));
+GENERATE_CB_SETTER_AND_DEFAULT(onSchemeChanged, (void *context, const flib_scheme *scheme));
+GENERATE_CB_SETTER_AND_DEFAULT(onMapChanged, (void *context, const flib_map *map, int changetype));
+GENERATE_CB_SETTER_AND_DEFAULT(onScriptChanged, (void *context, const char *script));
+GENERATE_CB_SETTER_AND_DEFAULT(onWeaponsetChanged, (void *context, const flib_weaponset *weaponset));
+GENERATE_CB_SETTER_AND_DEFAULT(onServerVar, (void *context, const char *name, const char *value));
+
+#undef GENERATE_CB_SETTER_AND_DEFAULT
+#undef GENERATE_CB_SETTER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn_internal.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,151 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Common definitions needed by netconn functions, to allow splitting them into several files.
+ */
+
+#ifndef NETCONN_INTERNAL_H_
+#define NETCONN_INTERNAL_H_
+
+#include "netconn.h"
+#include "netbase.h"
+#include "../model/map.h"
+#include "../model/team.h"
+#include "../model/weapon.h"
+#include "../model/room.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+struct _flib_netconn {
+	flib_netbase *netBase;
+	char *playerName;
+	char *dataDirPath;
+
+	int netconnState;			// One of the NETCONN_STATE constants
+
+	bool isChief;				// Player can modify the current room
+	flib_map *map;
+	flib_teamlist pendingTeamlist;
+	flib_teamlist teamlist;
+	flib_scheme *scheme;
+	char *style;
+	flib_weaponset *weaponset;
+
+	void (*onMessageCb)(void *context, int msgtype, const char *msg);
+	void *onMessageCtx;
+
+	void (*onConnectedCb)(void *context);
+	void *onConnectedCtx;
+
+	void (*onDisconnectedCb)(void *context, int reason, const char *message);
+	void *onDisconnectedCtx;
+
+	void (*onRoomlistCb)(void *context, const flib_room **rooms, int roomCount);
+	void *onRoomlistCtx;
+
+	void (*onRoomAddCb)(void *context, const flib_room *room);
+	void *onRoomAddCtx;
+
+	void (*onRoomDeleteCb)(void *context, const char *name);
+	void *onRoomDeleteCtx;
+
+	void (*onRoomUpdateCb)(void *context, const char *oldName, const flib_room *room);
+	void *onRoomUpdateCtx;
+
+	void (*onClientFlagsCb)(void *context, const char *nick, const char *flags, bool newFlagState);
+	void *onClientFlagsCtx;
+
+	void (*onChatCb)(void *context, const char *nick, const char *msg);
+	void *onChatCtx;
+
+	void (*onLobbyJoinCb)(void *context, const char *nick);
+	void *onLobbyJoinCtx;
+
+	void (*onLobbyLeaveCb)(void *context, const char *nick, const char *partMessage);
+	void *onLobbyLeaveCtx;
+
+	void (*onRoomJoinCb)(void *context, const char *nick);
+	void *onRoomJoinCtx;
+
+	void (*onRoomLeaveCb)(void *context, const char *nick, const char *partMessage);
+	void *onRoomLeaveCtx;
+
+	void (*onNickTakenCb)(void *context, const char *nick);
+	void *onNickTakenCtx;
+
+	void (*onPasswordRequestCb)(void *context, const char *nick);
+	void *onPasswordRequestCtx;
+
+	void (*onEnterRoomCb)(void *context, bool chief);
+	void *onEnterRoomCtx;
+
+	void (*onLeaveRoomCb)(void *context, int reason, const char *message);
+	void *onLeaveRoomCtx;
+
+	void (*onTeamAddCb)(void *context, const flib_team *team);
+	void *onTeamAddCtx;
+
+	void (*onTeamDeleteCb)(void *context, const char *teamname);
+	void *onTeamDeleteCtx;
+
+	void (*onRunGameCb)(void *context);
+	void *onRunGameCtx;
+
+	void (*onTeamAcceptedCb)(void *context, const char *teamName);
+	void *onTeamAcceptedCtx;
+
+	void (*onHogCountChangedCb)(void *context, const char *teamName, int hogs);
+	void *onHogCountChangedCtx;
+
+	void (*onTeamColorChangedCb)(void *context, const char *teamName, int colorIndex);
+	void *onTeamColorChangedCtx;
+
+	void (*onEngineMessageCb)(void *context, const uint8_t *message, size_t size);
+	void *onEngineMessageCtx;
+
+	void (*onSchemeChangedCb)(void *context, const flib_scheme *scheme);
+	void *onSchemeChangedCtx;
+
+	void (*onMapChangedCb)(void *context, const flib_map *map, int changetype);
+	void *onMapChangedCtx;
+
+	void (*onScriptChangedCb)(void *context, const char *script);
+	void *onScriptChangedCtx;
+
+	void (*onWeaponsetChangedCb)(void *context, const flib_weaponset *weaponset);
+	void *onWeaponsetChangedCtx;
+
+	void (*onServerVarCb)(void *context, const char *name, const char *value);
+	void *onServerVarCtx;
+
+	bool running;
+	bool destroyRequested;
+};
+
+void netconn_clearCallbacks(flib_netconn *conn);
+void netconn_leaveRoom(flib_netconn *conn);
+void netconn_setMap(flib_netconn *conn, const flib_map *map);
+void netconn_setWeaponset(flib_netconn *conn, const flib_weaponset *weaponset);
+void netconn_setScript(flib_netconn *conn, const char *script);
+void netconn_setScheme(flib_netconn *conn, const flib_scheme *scheme);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netconn_send.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,495 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "netconn_internal.h"
+
+#include "../util/logging.h"
+#include "../util/util.h"
+#include "../util/buffer.h"
+#include "../md5/md5.h"
+#include "../base64/base64.h"
+
+#include <zlib.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+// cmdname is always given as literal from functions in this file, so it is never null.
+static int sendVoid(flib_netconn *conn, const char *cmdname) {
+	if(log_e_if(!conn, "Invalid parameter sending %s command", cmdname)) {
+		return -1;
+	}
+	return flib_netbase_sendf(conn->netBase, "%s\n\n", cmdname);
+}
+
+// Testing for !*str prevents sending 0-length parameters (they trip up the protocol)
+static int sendStr(flib_netconn *conn, const char *cmdname, const char *str) {
+	if(log_e_if(!conn || flib_strempty(str), "Invalid parameter sending %s command", cmdname)) {
+		return -1;
+	}
+	return flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", cmdname, str);
+}
+
+static int sendInt(flib_netconn *conn, const char *cmdname, int param) {
+	if(log_e_if(!conn, "Invalid parameter sending %s command", cmdname)) {
+		return -1;
+	}
+	return flib_netbase_sendf(conn->netBase, "%s\n%i\n\n", cmdname, param);
+}
+
+int flib_netconn_send_nick(flib_netconn *conn, const char *nick) {
+	int result = -1;
+	if(!log_badargs_if2(conn==NULL, flib_strempty(nick))) {
+		char *tmpName = flib_strdupnull(nick);
+		if(tmpName) {
+			if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) {
+				free(conn->playerName);
+				conn->playerName = tmpName;
+				tmpName = NULL;
+				result = 0;
+			}
+		}
+		free(tmpName);
+	}
+	return result;
+}
+
+int flib_netconn_send_password(flib_netconn *conn, const char *passwd) {
+	int result = -1;
+	if(!log_badargs_if2(conn==NULL, passwd==NULL)) {
+		md5_state_t md5state;
+		uint8_t md5bytes[16];
+		char md5hex[33];
+		md5_init(&md5state);
+		md5_append(&md5state, (unsigned char*)passwd, strlen(passwd));
+		md5_finish(&md5state, md5bytes);
+		for(int i=0;i<sizeof(md5bytes); i++) {
+			// Needs to be lowercase - server checks case sensitive
+			snprintf(md5hex+i*2, 3, "%02x", (unsigned)md5bytes[i]);
+		}
+		result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "PASSWORD", md5hex);
+	}
+	return result;
+}
+
+int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) {
+	return sendStr(conn, "QUIT", (quitmsg && *quitmsg) ? quitmsg : "User quit");
+}
+
+int flib_netconn_send_chat(flib_netconn *conn, const char *chat) {
+	if(!flib_strempty(chat)) {
+		return sendStr(conn, "CHAT", chat);
+	}
+	return 0;
+}
+
+int flib_netconn_send_kick(flib_netconn *conn, const char *playerName) {
+	return sendStr(conn, "KICK", playerName);
+}
+
+int flib_netconn_send_playerInfo(flib_netconn *conn, const char *playerName) {
+	return sendStr(conn, "INFO", playerName);
+}
+
+int flib_netconn_send_request_roomlist(flib_netconn *conn) {
+	return sendVoid(conn, "LIST");
+}
+
+int flib_netconn_send_joinRoom(flib_netconn *conn, const char *room) {
+	if(!sendStr(conn, "JOIN_ROOM", room)) {
+		conn->isChief = false;
+		return 0;
+	}
+	return -1;
+}
+
+int flib_netconn_send_playerFollow(flib_netconn *conn, const char *playerName) {
+	return sendStr(conn, "FOLLOW", playerName);
+}
+
+int flib_netconn_send_createRoom(flib_netconn *conn, const char *room) {
+	if(!sendStr(conn, "CREATE_ROOM", room)) {
+		conn->isChief = true;
+		return 0;
+	}
+	return -1;
+}
+
+int flib_netconn_send_ban(flib_netconn *conn, const char *playerName) {
+	return sendStr(conn, "BAN", playerName);
+}
+
+int flib_netconn_send_clearAccountsCache(flib_netconn *conn) {
+	return sendVoid(conn, "CLEAR_ACCOUNTS_CACHE");
+}
+
+int flib_netconn_send_setServerVar(flib_netconn *conn, const char *name, const char *value) {
+	if(log_badargs_if3(conn==NULL, flib_strempty(name), flib_strempty(value))) {
+		return -1;
+	}
+	return flib_netbase_sendf(conn->netBase, "%s\n%s\n%s\n\n", "SET_SERVER_VAR", name, value);
+}
+
+int flib_netconn_send_getServerVars(flib_netconn *conn) {
+	return sendVoid(conn, "GET_SERVER_VAR");
+}
+int flib_netconn_send_leaveRoom(flib_netconn *conn, const char *str) {
+	int result = -1;
+	if(conn->netconnState==NETCONN_STATE_ROOM) {
+		result = (str && *str) ? sendStr(conn, "PART", str) : sendVoid(conn, "PART");
+		if(!result) {
+			netconn_leaveRoom(conn);
+		}
+	}
+	return result;
+}
+
+int flib_netconn_send_toggleReady(flib_netconn *conn) {
+	return sendVoid(conn, "TOGGLE_READY");
+}
+
+static void addTeamToPendingList(flib_netconn *conn, const flib_team *team) {
+	flib_team *teamcopy = flib_team_copy(team);
+	if(teamcopy) {
+		teamcopy->remoteDriven = false;
+		free(teamcopy->ownerName);
+		teamcopy->ownerName = flib_strdupnull(conn->playerName);
+		if(teamcopy->ownerName) {
+			flib_teamlist_delete(&conn->pendingTeamlist, team->name);
+			if(!flib_teamlist_insert(&conn->pendingTeamlist, teamcopy, 0)) {
+				teamcopy = NULL;
+			}
+		}
+	}
+	flib_team_destroy(teamcopy);
+}
+
+int flib_netconn_send_addTeam(flib_netconn *conn, const flib_team *team) {
+	int result = -1;
+	if(!log_badargs_if2(conn==NULL, team==NULL)) {
+		bool missingInfo = flib_strempty(team->name) || flib_strempty(team->grave) || flib_strempty(team->fort) || flib_strempty(team->voicepack) || flib_strempty(team->flag);
+		for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+			missingInfo |= flib_strempty(team->hogs[i].name) || flib_strempty(team->hogs[i].hat);
+		}
+		if(!log_e_if(missingInfo, "Incomplete team definition")) {
+			flib_vector *vec = flib_vector_create();
+			if(vec) {
+				bool error = false;
+				error |= flib_vector_appendf(vec, "ADD_TEAM\n%s\n%i\n%s\n%s\n%s\n%s\n%i\n", team->name, team->colorIndex, team->grave, team->fort, team->voicepack, team->flag, team->hogs[0].difficulty);
+				for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+					error |= flib_vector_appendf(vec, "%s\n%s\n", team->hogs[i].name, team->hogs[i].hat);
+				}
+				error |= flib_vector_appendf(vec, "\n");
+				if(!error && !flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec))) {
+					addTeamToPendingList(conn, team);
+					result = 0;
+				}
+			}
+			flib_vector_destroy(vec);
+		}
+	}
+	return result;
+}
+
+int flib_netconn_send_removeTeam(flib_netconn *conn, const char *teamname) {
+	flib_team *team = flib_teamlist_find(&conn->teamlist, teamname);
+	if(team && !team->remoteDriven && !sendStr(conn, "REMOVE_TEAM", teamname)) {
+		flib_teamlist_delete(&conn->teamlist, teamname);
+		return 0;
+	}
+	return -1;
+}
+
+int flib_netconn_send_renameRoom(flib_netconn *conn, const char *roomName) {
+	return sendStr(conn, "ROOM_NAME", roomName);
+}
+
+int flib_netconn_send_teamHogCount(flib_netconn *conn, const char *teamname, int hogcount) {
+	if(!log_badargs_if5(conn==NULL, flib_strempty(teamname), hogcount<1, hogcount>HEDGEHOGS_PER_TEAM, !conn->isChief)
+			&& !flib_netbase_sendf(conn->netBase, "HH_NUM\n%s\n%i\n\n", teamname, hogcount)) {
+		flib_team *team = flib_teamlist_find(&conn->teamlist, teamname);
+		if(team) {
+			team->hogsInGame = hogcount;
+		}
+		return 0;
+	}
+	return -1;
+}
+
+int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, int colorIndex) {
+	if(!log_badargs_if3(conn==NULL, flib_strempty(teamname), !conn->isChief)
+			&& !flib_netbase_sendf(conn->netBase, "TEAM_COLOR\n%s\n%i\n\n", teamname, colorIndex)) {
+		flib_team *team = flib_teamlist_find(&conn->teamlist, teamname);
+		if(team) {
+			team->colorIndex = colorIndex;
+		}
+		return 0;
+	}
+	return -1;
+}
+
+int flib_netconn_send_weaponset(flib_netconn *conn, const flib_weaponset *weaponset) {
+	if(!log_badargs_if3(conn==NULL, weaponset==NULL, flib_strempty(weaponset->name))) {
+		char ammostring[WEAPONS_COUNT*4+1];
+		strcpy(ammostring, weaponset->loadout);
+		strcat(ammostring, weaponset->crateprob);
+		strcat(ammostring, weaponset->delay);
+		strcat(ammostring, weaponset->crateammo);
+		if(conn->isChief) {
+			if(!flib_netbase_sendf(conn->netBase, "CFG\nAMMO\n%s\n%s\n\n", weaponset->name, ammostring)) {
+				netconn_setWeaponset(conn, weaponset);
+				return 0;
+			}
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_map(flib_netconn *conn, const flib_map *map) {
+	if(log_badargs_if2(conn==NULL, map==NULL)) {
+		return -1;
+	}
+	bool error = false;
+
+	if(map->seed) {
+		error |= flib_netconn_send_mapSeed(conn, map->seed);
+	}
+	error |= flib_netconn_send_mapTemplate(conn, map->templateFilter);
+	if(map->theme) {
+		error |= flib_netconn_send_mapTheme(conn, map->theme);
+	}
+	error |= flib_netconn_send_mapGen(conn, map->mapgen);
+	error |= flib_netconn_send_mapMazeSize(conn, map->mazeSize);
+	if(map->drawData && map->drawDataSize>0) {
+		error |= flib_netconn_send_mapDrawdata(conn, map->drawData, map->drawDataSize);
+	}
+	// Name is sent last, because the QtFrontend uses this to update its preview, and to show/hide
+	// certain fields
+	if(map->name) {
+		error |= flib_netconn_send_mapName(conn, map->name);
+	}
+	return error;
+}
+
+int flib_netconn_send_mapName(flib_netconn *conn, const char *mapName) {
+	if(log_badargs_if2(conn==NULL, mapName==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendStr(conn, "CFG\nMAP", mapName)) {
+			char *copy = flib_strdupnull(mapName);
+			if(copy) {
+				free(conn->map->name);
+				conn->map->name = copy;
+				return 0;
+			}
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_mapGen(flib_netconn *conn, int mapGen) {
+	if(log_badargs_if(conn==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendInt(conn, "CFG\nMAPGEN", mapGen)) {
+			conn->map->mapgen = mapGen;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_mapTemplate(flib_netconn *conn, int templateFilter) {
+	if(log_badargs_if(conn==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendInt(conn, "CFG\nTEMPLATE", templateFilter)) {
+			conn->map->templateFilter = templateFilter;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_mapMazeSize(flib_netconn *conn, int mazeSize) {
+	if(log_badargs_if(conn==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendInt(conn, "CFG\nMAZE_SIZE", mazeSize)) {
+			conn->map->mazeSize = mazeSize;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_mapSeed(flib_netconn *conn, const char *seed) {
+	if(log_badargs_if2(conn==NULL, seed==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendStr(conn, "CFG\nSEED", seed)) {
+			char *copy = flib_strdupnull(seed);
+			if(copy) {
+				free(conn->map->seed);
+				conn->map->seed = copy;
+				return 0;
+			}
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_mapTheme(flib_netconn *conn, const char *theme) {
+	if(log_badargs_if2(conn==NULL, theme==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendStr(conn, "CFG\nTHEME", theme)) {
+			char *copy = flib_strdupnull(theme);
+			if(copy) {
+				free(conn->map->theme);
+				conn->map->theme = copy;
+				return 0;
+			}
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_mapDrawdata(flib_netconn *conn, const uint8_t *drawData, size_t size) {
+	int result = -1;
+	if(!log_badargs_if3(conn==NULL, drawData==NULL && size>0, size>SIZE_MAX/2) && conn->isChief) {
+		uLongf zippedSize = compressBound(size);
+		uint8_t *zipped = flib_malloc(zippedSize+4); // 4 extra bytes for header
+		if(zipped) {
+			// Create the QCompress size header (uint32 big endian)
+			zipped[0] = (size>>24) & 0xff;
+			zipped[1] = (size>>16) & 0xff;
+			zipped[2] = (size>>8) & 0xff;
+			zipped[3] = (size) & 0xff;
+
+			if(compress(zipped+4, &zippedSize, drawData, size) != Z_OK) {
+				flib_log_e("Error compressing drawn map data.");
+			} else {
+				char *base64encout = NULL;
+				base64_encode_alloc((const char*)zipped, zippedSize+4, &base64encout);
+				if(!base64encout) {
+					flib_log_e("Error base64-encoding drawn map data.");
+				} else {
+					result = flib_netbase_sendf(conn->netBase, "CFG\nDRAWNMAP\n%s\n\n", base64encout);
+				}
+				free(base64encout);
+			}
+		}
+		free(zipped);
+	}
+
+	if(!result) {
+		uint8_t *copy = flib_bufdupnull(drawData, size);
+		if(copy) {
+			free(conn->map->drawData);
+			conn->map->drawData = copy;
+			conn->map->drawDataSize = size;
+		}
+	}
+	return result;
+}
+
+int flib_netconn_send_script(flib_netconn *conn, const char *scriptName) {
+	if(log_badargs_if2(conn==NULL, scriptName==NULL)) {
+		return -1;
+	}
+	if(conn->isChief) {
+		if(!sendStr(conn, "CFG\nSCRIPT", scriptName)) {
+			netconn_setScript(conn, scriptName);
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int flib_netconn_send_scheme(flib_netconn *conn, const flib_scheme *scheme) {
+	int result = -1;
+	if(!log_badargs_if3(conn==NULL, scheme==NULL, flib_strempty(scheme->name)) && conn->isChief) {
+		flib_vector *vec = flib_vector_create();
+		if(vec) {
+			bool error = false;
+			error |= flib_vector_appendf(vec, "CFG\nSCHEME\n%s\n", scheme->name);
+			for(int i=0; i<flib_meta.modCount; i++) {
+				error |= flib_vector_appendf(vec, "%s\n", scheme->mods[i] ? "true" : "false");
+			}
+			for(int i=0; i<flib_meta.settingCount; i++) {
+				error |= flib_vector_appendf(vec, "%i\n", scheme->settings[i]);
+			}
+			error |= flib_vector_appendf(vec, "\n");
+			if(!error) {
+				result = flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec));
+			}
+		}
+		flib_vector_destroy(vec);
+	}
+
+	if(!result) {
+		netconn_setScheme(conn, scheme);
+	}
+	return result;
+}
+
+int flib_netconn_send_startGame(flib_netconn *conn) {
+	return sendVoid(conn, "START_GAME");
+}
+
+int flib_netconn_send_toggleRestrictJoins(flib_netconn *conn) {
+	return sendVoid(conn, "TOGGLE_RESTRICT_JOINS");
+}
+
+int flib_netconn_send_toggleRestrictTeams(flib_netconn *conn) {
+	return sendVoid(conn, "TOGGLE_RESTRICT_TEAMS");
+}
+
+int flib_netconn_send_teamchat(flib_netconn *conn, const char *chat) {
+	if(!flib_strempty(chat)) {
+		return sendStr(conn, "TEAMCHAT", chat);
+	}
+	return 0;
+}
+
+int flib_netconn_send_engineMessage(flib_netconn *conn, const uint8_t *message, size_t size) {
+	int result = -1;
+	if(!log_badargs_if2(conn==NULL, message==NULL && size>0)) {
+		char *base64encout = NULL;
+		base64_encode_alloc((const char*)message, size, &base64encout);
+		if(base64encout) {
+			result = flib_netbase_sendf(conn->netBase, "EM\n%s\n\n", base64encout);
+		}
+		free(base64encout);
+	}
+	return result;
+}
+
+int flib_netconn_send_roundfinished(flib_netconn *conn, bool withoutError) {
+	return sendInt(conn, "ROUNDFINISHED", withoutError ? 1 : 0);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netprotocol.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,192 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "netprotocol.h"
+
+#include "../util/util.h"
+#include "../util/logging.h"
+
+#include "../base64/base64.h"
+
+#include <zlib.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int fillTeamFromMsg(flib_team *team, char **parts) {
+	team->name = flib_strdupnull(parts[0]);
+	team->grave = flib_strdupnull(parts[1]);
+	team->fort = flib_strdupnull(parts[2]);
+	team->voicepack = flib_strdupnull(parts[3]);
+	team->flag = flib_strdupnull(parts[4]);
+	team->ownerName = flib_strdupnull(parts[5]);
+	if(!team->name || !team->grave || !team->fort || !team->voicepack || !team->flag || !team->ownerName) {
+		return -1;
+	}
+
+	errno = 0;
+	long difficulty = strtol(parts[6], NULL, 10);
+	if(errno) {
+		return -1;
+	}
+
+	for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) {
+		flib_hog *hog = &team->hogs[i];
+		hog->difficulty = difficulty;
+		hog->name = flib_strdupnull(parts[7+2*i]);
+		hog->hat = flib_strdupnull(parts[8+2*i]);
+		if(!hog->name || !hog->hat) {
+			return -1;
+		}
+	}
+
+	// Set some default assumptions as well
+	team->colorIndex = DEFAULT_COLOR_INDEX;
+	team->hogsInGame = DEFAULT_HEDGEHOG_COUNT;
+	team->remoteDriven = true;
+	return 0;
+}
+
+flib_team *flib_team_from_netmsg(char **parts) {
+	flib_team *result = NULL;
+	flib_team *tmpTeam = flib_calloc(1, sizeof(flib_team));
+	if(tmpTeam) {
+		if(!fillTeamFromMsg(tmpTeam, parts)) {
+			result = tmpTeam;
+			tmpTeam = NULL;
+		} else {
+			flib_log_e("Error parsing team from net.");
+		}
+	}
+	flib_team_destroy(tmpTeam);
+	return result;
+}
+
+flib_scheme *flib_scheme_from_netmsg(char **parts) {
+	flib_scheme *result = flib_scheme_create(parts[0]);
+	if(result) {
+		for(int i=0; i<flib_meta.modCount; i++) {
+			result->mods[i] = !strcmp(parts[i+1], "true");
+		}
+		for(int i=0; i<flib_meta.settingCount; i++) {
+			result->settings[i] = atoi(parts[i+flib_meta.modCount+1]);
+		}
+	}
+	return result;
+}
+
+flib_map *flib_map_from_netmsg(char **parts) {
+	flib_map *result = flib_map_create_named(parts[3], parts[0]);
+	if(result) {
+		result->mapgen = atoi(parts[1]);
+		result->mazeSize = atoi(parts[2]);
+		result->templateFilter = atoi(parts[4]);
+	}
+	return result;
+}
+
+int flib_drawnmapdata_from_netmsg(char *netmsg, uint8_t** outbuf, size_t *outlen) {
+	int result = -1;
+
+	// First step: base64 decoding
+	char *base64decout = NULL;
+	size_t base64declen;
+	bool ok = base64_decode_alloc(netmsg, strlen(netmsg), &base64decout, &base64declen);
+	if(ok && base64declen>3) {
+		// Second step: unzip with the QCompress header. That header is just a big-endian
+		// uint32 indicating the length of the uncompressed data.
+		uint8_t *ubyteBuf = (uint8_t*)base64decout;
+		uint32_t unzipLen =
+				(((uint32_t)ubyteBuf[0])<<24)
+				+ (((uint32_t)ubyteBuf[1])<<16)
+				+ (((uint32_t)ubyteBuf[2])<<8)
+				+ ubyteBuf[3];
+		if(unzipLen==0) {
+			*outbuf = NULL;
+			*outlen = 0;
+			result = 0;
+		} else {
+			uint8_t *out = flib_malloc(unzipLen);
+			if(out) {
+				uLongf actualUnzipLen = unzipLen;
+				int resultcode = uncompress(out, &actualUnzipLen, (Bytef*)(base64decout+4), base64declen-4);
+				if(resultcode == Z_OK) {
+					*outbuf = out;
+					*outlen = actualUnzipLen;
+					out = NULL;
+					result = 0;
+				} else {
+					flib_log_e("Uncompressing drawn map failed. Code: %i", resultcode);
+				}
+			}
+			free(out);
+		}
+	} else {
+		flib_log_e("base64 decoding of drawn map failed.");
+	}
+	free(base64decout);
+	return result;
+}
+
+flib_room *flib_room_from_netmsg(char **params) {
+	flib_room *result = NULL;
+	flib_room *tmpRoom = flib_calloc(1, sizeof(flib_room));
+	if(tmpRoom) {
+		tmpRoom->inProgress = !strcmp(params[0], "True");
+		tmpRoom->name = flib_strdupnull(params[1]);
+		tmpRoom->playerCount = atoi(params[2]);
+		tmpRoom->teamCount = atoi(params[3]);
+		tmpRoom->owner = flib_strdupnull(params[4]);
+		tmpRoom->map = flib_strdupnull(params[5]);
+		tmpRoom->scheme = flib_strdupnull(params[6]);
+		tmpRoom->weapons = flib_strdupnull(params[7]);
+		if(tmpRoom->name && tmpRoom->owner && tmpRoom->map && tmpRoom->scheme && tmpRoom->weapons) {
+			result = tmpRoom;
+			tmpRoom = NULL;
+		}
+	}
+	flib_room_destroy(tmpRoom);
+	return result;
+}
+
+int fillRoomArray(flib_room **array, char **params, int count) {
+	for(int i=0; i<count; i++) {
+		array[i] = flib_room_from_netmsg(params + 8*i);
+		if(!array[i]) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+flib_room **flib_room_array_from_netmsg(char **params, int count) {
+	flib_room **result = flib_calloc(count, sizeof(flib_room*));
+	if(result) {
+		if(fillRoomArray(result, params, count)) {
+			for(int i=0; i<count; i++) {
+				flib_room_destroy(result[i]);
+			}
+			free(result);
+			result = NULL;
+		}
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/net/netprotocol.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,66 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef NETPROTOCOL_H_
+#define NETPROTOCOL_H_
+
+#include "../model/team.h"
+#include "../model/scheme.h"
+#include "../model/map.h"
+#include "../model/room.h"
+
+#include <stddef.h>
+
+/**
+ * Create a new team from this 23-part net message
+ */
+flib_team *flib_team_from_netmsg(char **parts);
+
+/**
+ * Create a new scheme from this net message, which must have
+ * meta->modCount+meta->settingCount+1 parts.
+ */
+flib_scheme *flib_scheme_from_netmsg(char **parts);
+
+/**
+ * Create a new map from this five-part netmsg
+ */
+flib_map *flib_map_from_netmsg(char **parts);
+
+/**
+ * Decode the drawn map data from this netmessage line.
+ *
+ * The data is first base64 decoded and then quncompress()ed.
+ * The return value is a newly allocated byte buffer, the length
+ * is written to the variable pointed to by outlen.
+ * Returns NULL on error.
+ */
+int flib_drawnmapdata_from_netmsg(char *netmsg, uint8_t **outbuf, size_t *outlen);
+
+/**
+ * Create a new room from this 8-part net message
+ */
+flib_room *flib_room_from_netmsg(char **params);
+
+/**
+ * Create an array of count rooms from count*8 netmessage parts
+ */
+flib_room **flib_room_array_from_netmsg(char **params, int count);
+
+#endif /* NETPROTOCOL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/socket.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,191 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "socket.h"
+#include "util/logging.h"
+#include "util/util.h"
+#include <stdlib.h>
+#include <SDL_net.h>
+#include <time.h>
+
+struct _flib_tcpsocket {
+	TCPsocket sock;
+	SDLNet_SocketSet sockset;
+};
+
+struct _flib_acceptor {
+	TCPsocket sock;
+	uint16_t port;
+};
+
+static uint32_t getPeerIp(TCPsocket sock) {
+	IPaddress *addr = SDLNet_TCP_GetPeerAddress(sock);
+	return SDLNet_Read32(&addr->host);
+}
+
+static bool connectionIsLocal(TCPsocket sock) {
+	return getPeerIp(sock) == (uint32_t)((127UL<<24)+1); // 127.0.0.1
+}
+
+static flib_tcpsocket *createSocket(TCPsocket sdlsock) {
+	flib_tcpsocket *result = flib_calloc(1, sizeof(flib_tcpsocket));
+	if(result) {
+		result->sock = sdlsock;
+		result->sockset = SDLNet_AllocSocketSet(1);
+
+		if(!result->sockset) {
+			flib_log_e("Can't allocate socket: Out of memory!");
+			SDLNet_FreeSocketSet(result->sockset);
+			free(result);
+			result = NULL;
+		} else {
+			SDLNet_AddSocket(result->sockset, (SDLNet_GenericSocket)result->sock);
+		}
+	}
+	return result;
+}
+
+TCPsocket listen(uint16_t port) {
+	IPaddress addr;
+	addr.host = INADDR_ANY;
+	SDLNet_Write16(port, &addr.port);
+	TCPsocket sock = SDLNet_TCP_Open(&addr);
+	if(!sock) {
+		flib_log_w("Unable to listen on port %u: %s", (unsigned)port, SDLNet_GetError());
+	}
+	return sock;
+}
+
+flib_acceptor *flib_acceptor_create(uint16_t port) {
+	flib_acceptor *result = flib_calloc(1, sizeof(flib_acceptor));
+	if(result) {
+		if(port > 0) {
+			result->port = port;
+			result->sock = listen(result->port);
+		} else {
+			/* SDL_net does not seem to have a way to listen on a random unused port
+			   and find out which port that is, so let's try to find one ourselves. */
+			srand(time(NULL));
+			for(int i=0; !result->sock && i<1000; i++) {
+				// IANA suggests using ports in the range 49152-65535 for things like this
+				result->port = 49152+(rand()%(65535-49152));
+				result->sock = listen(result->port);
+			}
+		}
+		if(!result->sock) {
+			flib_log_e("Failed to create acceptor.");
+			free(result);
+			result = NULL;
+		}
+	}
+	return result;
+}
+
+uint16_t flib_acceptor_listenport(flib_acceptor *acceptor) {
+	if(!acceptor) {
+		flib_log_e("Call to flib_acceptor_listenport with acceptor==null");
+		return 0;
+	}
+	return acceptor->port;
+}
+
+void flib_acceptor_close(flib_acceptor *acceptor) {
+	if(acceptor) {
+		SDLNet_TCP_Close(acceptor->sock);
+		free(acceptor);
+	}
+}
+
+flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly) {
+	flib_tcpsocket *result = NULL;
+	if(!acceptor) {
+		flib_log_e("Call to flib_socket_accept with acceptor==null");
+	} else {
+		TCPsocket sock = NULL;
+		while(!result && (sock = SDLNet_TCP_Accept(acceptor->sock))) {
+			if(localOnly && !connectionIsLocal(sock)) {
+				flib_log_i("Rejected nonlocal connection attempt from %s", flib_format_ip(getPeerIp(sock)));
+			} else {
+				result = createSocket(sock);
+			}
+			if(!result) {
+				SDLNet_TCP_Close(sock);
+			}
+		}
+	}
+	return result;
+}
+
+flib_tcpsocket *flib_socket_connect(const char *host, uint16_t port) {
+	flib_tcpsocket *result = NULL;
+	if(!host || port==0) {
+		flib_log_e("Invalid parameter in flib_socket_connect");
+	} else {
+		IPaddress ip;
+		if(SDLNet_ResolveHost(&ip,host,port)==-1) {
+		   flib_log_e("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+		} else {
+			TCPsocket sock=SDLNet_TCP_Open(&ip);
+			if(!sock) {
+				flib_log_e("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+			} else {
+				result = createSocket(sock);
+				if(result) {
+					sock = NULL;
+				}
+			}
+			SDLNet_TCP_Close(sock);
+		}
+	}
+	return result;
+}
+
+void flib_socket_close(flib_tcpsocket *sock) {
+	if(sock) {
+		SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock);
+		SDLNet_TCP_Close(sock->sock);
+		SDLNet_FreeSocketSet(sock->sockset);
+		free(sock);
+	}
+}
+
+int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen) {
+	if(!sock || (maxlen>0 && !data)) {
+		flib_log_e("Call to flib_socket_nbrecv with sock==null or data==null");
+		return -1;
+	}
+	int readySockets = SDLNet_CheckSockets(sock->sockset, 0);
+	if(readySockets>0) {
+		int size = SDLNet_TCP_Recv(sock->sock, data, maxlen);
+		return size>0 ? size : -1;
+	} else if(readySockets==0) {
+		return 0;
+	} else {
+		flib_log_e("Error in select system call: %s", SDLNet_GetError());
+		return -1;
+	}
+}
+
+int flib_socket_send(flib_tcpsocket *sock, const void *data, int len) {
+	if(!sock || (len>0 && !data)) {
+		flib_log_e("Call to flib_socket_send with sock==null or data==null");
+		return -1;
+	}
+	return SDLNet_TCP_Send(sock->sock, data, len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/socket.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,91 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * Sockets for TCP networking.
+ *
+ * This layer offers some functionality over what SDL_net offers directly: listening
+ * sockets (called acceptors here) can be bound to port 0, which will make them listen
+ * on a random unused port, if one can be found. To support this feature, you can also
+ * query the local port that an acceptor is listening on.
+ *
+ * Further, we support nonblocking reads here.
+ */
+
+#ifndef SOCKET_H_
+#define SOCKET_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct _flib_tcpsocket flib_tcpsocket;
+typedef struct _flib_acceptor flib_acceptor;
+
+/**
+ * Create a new acceptor which will listen for incoming TCP connections
+ * on the given port. If port is 0, this will listen on a random
+ * unused port which can then be queried with flib_acceptor_listenport.
+ *
+ * Returns NULL on error.
+ */
+flib_acceptor *flib_acceptor_create(uint16_t port);
+
+/**
+ * Return the port on which the acceptor is listening.
+ */
+uint16_t flib_acceptor_listenport(flib_acceptor *acceptor);
+
+/**
+ * Close the acceptor and free its memory. NULL-safe.
+ */
+void flib_acceptor_close(flib_acceptor *acceptor);
+
+/**
+ * Try to accept a connection from an acceptor (listening socket).
+ * if localOnly is true, this will only accept connections which came from 127.0.0.1
+ * Returns NULL if nothing can be accepted.
+ */
+flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly);
+
+/**
+ * Try to connect to the server at the given address.
+ */
+flib_tcpsocket *flib_socket_connect(const char *host, uint16_t port);
+
+/**
+ * Close the socket and free its memory. NULL-safe.
+ */
+void flib_socket_close(flib_tcpsocket *socket);
+
+/**
+ * Attempt to receive up to maxlen bytes from the socket, but does not
+ * block if nothing is available.
+ * Returns the ammount of data received, 0 if there was nothing to receive,
+ * or a negative number if the connection was closed or an error occurred.
+ */
+int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen);
+
+/**
+ * Blocking send all the data in the data buffer. Returns the actual ammount
+ * of data sent, or a negative value on error. If the value returned here
+ * is less than len, either the connection closed or an error occurred.
+ */
+int flib_socket_send(flib_tcpsocket *sock, const void *data, int len);
+
+#endif /* SOCKET_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/buffer.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,177 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "buffer.h"
+#include "logging.h"
+#include "util.h"
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#define MIN_VECTOR_CAPACITY 16
+
+struct _flib_vector {
+	void *data;
+	size_t size;
+	size_t capacity;
+};
+
+flib_vector *flib_vector_create() {
+	flib_vector *result = NULL;
+	flib_vector *tmpVector = flib_calloc(1, sizeof(flib_vector));
+	if(tmpVector) {
+		tmpVector->data = flib_malloc(MIN_VECTOR_CAPACITY);
+		if(tmpVector->data) {
+			tmpVector->size = 0;
+			tmpVector->capacity = MIN_VECTOR_CAPACITY;
+			result = tmpVector;
+			tmpVector = NULL;
+		}
+	}
+	flib_vector_destroy(tmpVector);
+	return result;
+}
+
+void flib_vector_destroy(flib_vector *vec) {
+	if(vec) {
+		free(vec->data);
+		free(vec);
+	}
+}
+
+static int setCapacity(flib_vector *vec, size_t newCapacity) {
+	if(newCapacity == vec->capacity) {
+		return 0;
+	}
+	void *newData = realloc(vec->data, newCapacity);
+	if(newData) {
+		vec->data = newData;
+		vec->capacity = newCapacity;
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+static int allocateExtraCapacity(flib_vector *vec, size_t extraCapacity) {
+	if(extraCapacity <= SIZE_MAX - vec->capacity) {
+		return setCapacity(vec, vec->capacity + extraCapacity);
+	} else {
+		return -1;
+	}
+}
+
+int flib_vector_resize(flib_vector *vec, size_t newSize) {
+	if(log_badargs_if(vec==NULL)) {
+		return -1;
+	}
+
+	if(vec->capacity < newSize) {
+		// Resize exponentially for constant amortized time,
+		// But at least by as much as we need of course
+		size_t extraCapacity = (vec->capacity)/2;
+		size_t minExtraCapacity = newSize - vec->capacity;
+		if(extraCapacity < minExtraCapacity) {
+			extraCapacity = minExtraCapacity;
+		}
+
+		if(allocateExtraCapacity(vec, extraCapacity)) {
+			allocateExtraCapacity(vec, minExtraCapacity);
+		}
+	} else if(vec->capacity/2 > newSize) {
+		size_t newCapacity = newSize+newSize/4;
+		if(newCapacity < MIN_VECTOR_CAPACITY) {
+			newCapacity = MIN_VECTOR_CAPACITY;
+		}
+		setCapacity(vec, newCapacity);
+	}
+
+	if(vec->capacity >= newSize) {
+		vec->size = newSize;
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+int flib_vector_append(flib_vector *vec, const void *data, size_t len) {
+	if(!log_badargs_if2(vec==NULL, data==NULL && len>0)
+			&& !log_oom_if(len > SIZE_MAX-vec->size)) {
+		size_t oldSize = vec->size;
+		if(!log_oom_if(flib_vector_resize(vec, vec->size+len))) {
+			memmove(((uint8_t*)vec->data) + oldSize, data, len);
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int flib_vector_appendf(flib_vector *vec, const char *fmt, ...) {
+	int result = -1;
+	if(!log_badargs_if2(vec==NULL, fmt==NULL)) {
+		va_list argp;
+		va_start(argp, fmt);
+		char *formatted = flib_vasprintf(fmt, argp);
+		va_end(argp);
+
+
+		if(formatted) {
+			size_t len = strlen(formatted);
+			result = flib_vector_append(vec, formatted, len);
+		}
+	}
+	return result;
+}
+
+flib_buffer flib_vector_as_buffer(flib_vector *vec) {
+	if(log_badargs_if(vec==NULL)) {
+		flib_buffer result = {NULL, 0};
+		return result;
+	} else {
+		flib_buffer result = {vec->data, vec->size};
+		return result;
+	}
+}
+
+flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec) {
+	if(log_badargs_if(vec==NULL)) {
+		flib_constbuffer result = {NULL, 0};
+		return result;
+	} else {
+		flib_constbuffer result = {vec->data, vec->size};
+		return result;
+	}
+}
+
+void *flib_vector_data(flib_vector *vec) {
+	if(log_badargs_if(vec==NULL)) {
+		return NULL;
+	} else {
+		return vec->data;
+	}
+}
+
+size_t flib_vector_size(flib_vector *vec) {
+	if(log_badargs_if(vec==NULL)) {
+		return 0;
+	} else {
+		return vec->size;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/buffer.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,104 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef BUFFER_H_
+#define BUFFER_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * A simple struct to hold both the pointer to an array and its size,
+ * for e.g. conveniently returning it from a function.
+ *
+ * Convention: Size is zero iff data is a NULL pointer.
+ */
+typedef struct {
+	void *data;
+	size_t size;
+} flib_buffer;
+
+/**
+ * Just like flib_buffer, but the contents are not supposed to be modified.
+ */
+typedef struct {
+	const void *data;
+	size_t size;
+} flib_constbuffer;
+
+/**
+ * Simple variable-capacity data structure that can be efficiently appended to.
+ */
+typedef struct _flib_vector flib_vector;
+
+/**
+ * Create a new vector. Needs to be destroyed again later with flib_vector_destroy.
+ * May return NULL if memory runs out.
+ */
+flib_vector *flib_vector_create();
+
+/**
+ * Free the memory of this vector
+ */
+void flib_vector_destroy(flib_vector *vec);
+
+/**
+ * Resize the vector. This changes the size, and ensures the capacity is large enough to
+ * for the new size. Can also free memory if the new size is smaller. There is no guarantee
+ * about the contents of extra memory.
+ */
+int flib_vector_resize(flib_vector *vec, size_t newSize);
+
+/**
+ * Append the provided data to the end of the vector, enlarging it as required.
+ * The vector remains unchanged if appending fails.
+ * Returns 0 on success.
+ */
+int flib_vector_append(flib_vector *vec, const void *data, size_t len);
+
+/**
+ * Append data from a format string to the buffer (without trailing 0)
+ * Returns 0 on success.
+ */
+int flib_vector_appendf(flib_vector *vec, const char *template, ...);
+
+/**
+ * Return a pointer to the current data buffer of the vector. This pointer can
+ * become invalid if the vector size or capacity is changed.
+ */
+void *flib_vector_data(flib_vector *vec);
+
+/**
+ * Return the current size of the vector.
+ */
+size_t flib_vector_size(flib_vector *vec);
+
+/**
+ * Return a buffer pointing to the current contents of the vector.
+ * These will become invalid if the vector size or capacity is changed.
+ */
+flib_buffer flib_vector_as_buffer(flib_vector *vec);
+
+/**
+ * Return a constbuffer pointing to the current contents of the vector.
+ * These will become invalid if the vector size or capacity is changed.
+ */
+flib_constbuffer flib_vector_as_constbuffer(flib_vector *vec);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/inihelper.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,321 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "inihelper.h"
+#include "../iniparser/dictionary.h"
+#include "../iniparser/iniparser.h"
+
+#include "logging.h"
+#include "util.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdarg.h>
+
+struct _flib_ini {
+	dictionary *inidict;
+	char *currentSection;
+};
+
+static char *createDictKey(const char *sectionName, const char *keyName) {
+	return flib_asprintf("%s:%s", sectionName, keyName);
+}
+
+/**
+ * Turns a string into a lowercase string, in-place.
+ */
+static void strToLower(char *str) {
+	if(str) {
+		while(*str) {
+			*str = tolower(*str);
+			str++;
+		}
+	}
+}
+
+flib_ini *flib_ini_create(const char *filename) {
+	flib_ini *result = NULL;
+	flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini));
+	if(tmpIni) {
+		if(filename) {
+			tmpIni->inidict = iniparser_load(filename);
+		}
+		if(!tmpIni->inidict) {
+			tmpIni->inidict = dictionary_new(0);
+		}
+		if(tmpIni->inidict) {
+			result = tmpIni;
+			tmpIni = NULL;
+		}
+	}
+	flib_ini_destroy(tmpIni);
+	return result;
+}
+
+flib_ini *flib_ini_load(const char *filename) {
+	flib_ini *result = NULL;
+	if(!log_badargs_if(filename==NULL)) {
+		flib_ini *tmpIni = flib_calloc(1, sizeof(flib_ini));
+		if(tmpIni) {
+			tmpIni->inidict = iniparser_load(filename);
+			if(tmpIni->inidict) {
+				result = tmpIni;
+				tmpIni = NULL;
+			}
+		}
+		flib_ini_destroy(tmpIni);
+	}
+	return result;
+}
+
+int flib_ini_save(flib_ini *ini, const char *filename) {
+	int result = INI_ERROR_OTHER;
+	if(!log_badargs_if2(ini==NULL, filename==NULL)) {
+		FILE *file = fopen(filename, "wb");
+		if(!file) {
+			flib_log_e("Error opening file \"%s\" for writing.", filename);
+		} else {
+			iniparser_dump_ini(ini->inidict, file);
+			if(fclose(file)) {
+				flib_log_e("Write error on ini file \"%s\"", filename);
+			} else {
+				result = 0;
+			}
+		}
+	}
+	return result;
+}
+
+void flib_ini_destroy(flib_ini *ini) {
+	if(ini) {
+		if(ini->inidict) {
+			iniparser_freedict(ini->inidict);
+		}
+		free(ini->currentSection);
+		free(ini);
+	}
+}
+
+int flib_ini_enter_section(flib_ini *ini, const char *section) {
+	int result = INI_ERROR_OTHER;
+	if(ini) {
+		free(ini->currentSection);
+		ini->currentSection = NULL;
+	}
+	if(!log_badargs_if2(ini==NULL, section==NULL)) {
+		if(!iniparser_find_entry(ini->inidict, section)) {
+			flib_log_d("Ini section %s not found", section);
+			result = INI_ERROR_NOTFOUND;
+		} else {
+			ini->currentSection = flib_strdupnull(section);
+			if(ini->currentSection) {
+				// Usually iniparser ignores case, but some section-handling functions don't,
+				// so we set it to lowercase manually
+				strToLower(ini->currentSection);
+				result = 0;
+			}
+		}
+	}
+	return result;
+}
+
+int flib_ini_create_section(flib_ini *ini, const char *section) {
+	int result = INI_ERROR_OTHER;
+	if(!log_badargs_if2(ini==NULL, section==NULL)) {
+		result = flib_ini_enter_section(ini, section);
+		if(result == INI_ERROR_NOTFOUND) {
+			if(iniparser_set(ini->inidict, section, NULL)) {
+				flib_log_e("Error creating ini section %s", section);
+				result = INI_ERROR_OTHER;
+			} else {
+				result = flib_ini_enter_section(ini, section);
+			}
+		}
+	}
+	return result;
+}
+
+/**
+ * The result is an internal string of the iniparser, don't free it.
+ */
+static char *findValue(dictionary *dict, const char *section, const char *key) {
+	char *result = NULL;
+	char *dictKey = createDictKey(section, key);
+	if(dictKey) {
+		result = iniparser_getstring(dict, dictKey, NULL);
+	}
+	free(dictKey);
+	return result;
+}
+
+int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key) {
+	char *tmpValue = NULL;
+	int result = flib_ini_get_str_opt(ini, &tmpValue, key, NULL);
+	if(result==0) {
+		if(tmpValue == NULL) {
+			result = INI_ERROR_NOTFOUND;
+		} else {
+			*outVar = tmpValue;
+			tmpValue = NULL;
+		}
+	}
+	free(tmpValue);
+	return result;
+}
+
+int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def) {
+	int result = INI_ERROR_OTHER;
+	if(!log_badargs_if4(ini==NULL, ini->currentSection==NULL, outVar==NULL, key==NULL)) {
+		const char *value = findValue(ini->inidict, ini->currentSection, key);
+		if(!value) {
+			value = def;
+		}
+		char *valueDup = flib_strdupnull(value);
+		if(valueDup || !def) {
+			*outVar = valueDup;
+			result = 0;
+		}
+	}
+	return result;
+}
+
+int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key) {
+	char *tmpValue = NULL;
+	int result = flib_ini_get_str(ini, &tmpValue, key);
+	if(result==0) {
+		errno = 0;
+		long val = strtol(tmpValue, NULL, 10);
+		if(errno!=0 || val<INT_MIN || val>INT_MAX) {
+			flib_log_w("Cannot parse ini setting %s/%s = \"%s\" as integer.", ini->currentSection, key, tmpValue);
+			result = INI_ERROR_FORMAT;
+		} else {
+			*outVar = val;
+		}
+	}
+	free(tmpValue);
+	return result;
+}
+
+int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def) {
+	int tmpValue;
+	int result = flib_ini_get_int(ini, &tmpValue, key);
+	if(result == 0) {
+		*outVar = tmpValue;
+	} else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) {
+		*outVar = def;
+		result = 0;
+	}
+	return result;
+}
+
+int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key) {
+	char *tmpValue = NULL;
+	int result = flib_ini_get_str(ini, &tmpValue, key);
+	if(result==0) {
+		bool trueval = strchr("1tTyY", tmpValue[0]);
+		bool falseval = strchr("0fFnN", tmpValue[0]);
+		if(!trueval && !falseval) {
+			flib_log_w("ini setting %s/%s = \"%s\" is not a recognized truth value.", ini->currentSection, key, tmpValue);
+			result = INI_ERROR_FORMAT;
+		} else {
+			*outVar = trueval;
+		}
+	}
+	free(tmpValue);
+	return result;
+}
+
+int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def) {
+	bool tmpValue;
+	int result = flib_ini_get_bool(ini, &tmpValue, key);
+	if(result == 0) {
+		*outVar = tmpValue;
+	} else if(result == INI_ERROR_NOTFOUND || result == INI_ERROR_FORMAT) {
+		*outVar = def;
+		result = 0;
+	}
+	return result;
+}
+
+int flib_ini_set_str(flib_ini *ini, const char *key, const char *value) {
+	int result = INI_ERROR_OTHER;
+	if(!log_badargs_if4(ini==NULL, ini->currentSection==NULL, key==NULL, value==NULL)) {
+		char *dictKey = createDictKey(ini->currentSection, key);
+		if(dictKey) {
+			result = iniparser_set(ini->inidict, dictKey, value);
+			if(result) {
+				flib_log_e("Error setting ini entry %s to %s", dictKey, value);
+			}
+		}
+		free(dictKey);
+	}
+	return result;
+}
+
+int flib_ini_set_int(flib_ini *ini, const char *key, int value) {
+	int result = INI_ERROR_OTHER;
+	char *strvalue = flib_asprintf("%i", value);
+	if(strvalue) {
+		result = flib_ini_set_str(ini, key, strvalue);
+	}
+	free(strvalue);
+	return result;
+}
+
+int flib_ini_set_bool(flib_ini *ini, const char *key, bool value) {
+	return flib_ini_set_str(ini, key, value ? "true" : "false");
+}
+
+int flib_ini_get_sectioncount(flib_ini *ini) {
+	if(!log_badargs_if(ini==NULL)) {
+		return iniparser_getnsec(ini->inidict);
+	}
+	return INI_ERROR_OTHER;
+}
+
+char *flib_ini_get_sectionname(flib_ini *ini, int number) {
+	if(!log_badargs_if2(ini==NULL, number<0)) {
+		return flib_strdupnull(iniparser_getsecname(ini->inidict, number));
+	}
+	return NULL;
+}
+
+int flib_ini_get_keycount(flib_ini *ini) {
+	if(!log_badargs_if2(ini==NULL, ini->currentSection==NULL)) {
+		return iniparser_getsecnkeys(ini->inidict, ini->currentSection);
+	}
+	return INI_ERROR_OTHER;
+}
+
+char *flib_ini_get_keyname(flib_ini *ini, int number) {
+	char *result = NULL;
+	if(!log_badargs_if3(ini==NULL, ini->currentSection==NULL, number<0)) {
+		int keyCount = iniparser_getsecnkeys(ini->inidict, ini->currentSection);
+		char **keys = iniparser_getseckeys(ini->inidict, ini->currentSection);
+		if(keys && keyCount>number) {
+			// The keys are in the format section:key, so we have to skip the section and colon.
+			result = flib_strdupnull(keys[number]+strlen(ini->currentSection)+1);
+		}
+		free(keys);
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/inihelper.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,178 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Convenience interface for ini reading/writing.
+ *
+ * We currently use iniparser in the background, but using its interface directly is a bit verbose.
+ * This module is supposed to 1. make ini reading and writing a bit more convenient, and 2. hide
+ * the iniparser dependency so it can at need be easily replaced.
+ */
+
+#ifndef INIHELPER_H_
+#define INIHELPER_H_
+
+#include <stdbool.h>
+
+#define INI_ERROR_NOTFOUND -1
+#define INI_ERROR_FORMAT -2
+#define INI_ERROR_OTHER -100
+
+typedef struct _flib_ini flib_ini;
+
+/**
+ * Create a new ini data structure, pre-filled with the contents of
+ * the file "filename" if it exists. If filename is null, or the file
+ * is not found, an empty ini will be created. However, if an error
+ * occurs while reading the ini file (or any other error), null
+ * is returned.
+ *
+ * This behavior is useful for modifying an existing ini file without
+ * discarding unknown keys.
+ */
+flib_ini *flib_ini_create(const char *filename);
+
+/**
+ * Similar to flib_ini_create, but fails if the file is not found
+ * or if filename is null.
+ */
+flib_ini *flib_ini_load(const char *filename);
+
+/**
+ * Store the ini to the file "filename", overwriting
+ * the previous contents. Returns 0 on success.
+ */
+int flib_ini_save(flib_ini *ini, const char *filename);
+
+void flib_ini_destroy(flib_ini *ini);
+
+/**
+ * Enter the section with the specified name. Returns 0 on
+ * success, INI_ERROR_NOTFOUND if the section does not exist
+ * and a different value if another error occurs.
+ * If an error occurs, there is no current section.
+ *
+ * The section name should only consist of letters and
+ * numbers.
+ */
+int flib_ini_enter_section(flib_ini *ini, const char *section);
+
+/**
+ * Creates and enters the section with the specified name. Simply
+ * enters the section if it exists already. Returns 0 on success
+ * and a different value if another error occurs.
+ * If an error occurs, there is no current section.
+ */
+int flib_ini_create_section(flib_ini *ini, const char *section);
+
+/**
+ * Find a key in the current section and store the value in outVar
+ * as a newly allocated string. Returns 0 on success, INI_ERROR_NOTFOUND
+ * if the key was not found and a different value for other errors,
+ * e.g. if there is no current section.
+ */
+int flib_ini_get_str(flib_ini *ini, char **outVar, const char *key);
+
+/**
+ * Find a key in the current section and store the value in outVar
+ * as a newly allocated string. If the key is not found, the default
+ * value will be used instead. Returns 0 on success.
+ */
+int flib_ini_get_str_opt(flib_ini *ini, char **outVar, const char *key, const char *def);
+
+/**
+ * Find a key in the current section and store the value in outVar
+ * as an int. Returns 0 on success, INI_ERROR_NOTFOUND
+ * if the key was not found, INI_ERROR_FORMAT if it was found but
+ * could not be converted to an int, and a different value for other
+ * errors, e.g. if there is no current section.
+ */
+int flib_ini_get_int(flib_ini *ini, int *outVar, const char *key);
+
+/**
+ * Find a key in the current section and store the value in outVar
+ * as an int. If the key is not found, the default value will be used instead.
+ * Returns 0 on success, INI_ERROR_FORMAT if the value was found but
+ * could not be converted to int, and another value otherwise.
+ */
+int flib_ini_get_int_opt(flib_ini *ini, int *outVar, const char *key, int def);
+
+/**
+ * Find a key in the current section and store the value in outVar
+ * as a bool. Treats everything beginning with "Y", "T" or "1" as true,
+ * everything starting with "N", "F" or "1" as false.
+ *
+ * Returns 0 on success, INI_ERROR_NOTFOUND if the key was not found,
+ * INI_ERROR_FORMAT if the value could not be interpreted as boolean,
+ * and another value otherwise.
+ */
+int flib_ini_get_bool(flib_ini *ini, bool *outVar, const char *key);
+
+/**
+ * Find a key in the current section and store the value in outVar
+ * as a bool. If the key is not found, the default value will be
+ * used instead. Returns 0 on success, INI_ERROR_FORMAT if the
+ * value could not be interpreted as boolean, and another value otherwise.
+ */
+int flib_ini_get_bool_opt(flib_ini *ini, bool *outVar, const char *key, bool def);
+
+/**
+ * In the current section, associate key with value. Returns 0 on success.
+ */
+int flib_ini_set_str(flib_ini *ini, const char *key, const char *value);
+
+/**
+ * In the current section, associate key with value. Returns 0 on success.
+ */
+int flib_ini_set_int(flib_ini *ini, const char *key, int value);
+
+/**
+ * In the current section, associate key with value. Returns 0 on success.
+ */
+int flib_ini_set_bool(flib_ini *ini, const char *key, bool value);
+
+/**
+ * Returns the number of sections in the ini file, or a negative value on error.
+ */
+int flib_ini_get_sectioncount(flib_ini *ini);
+
+/**
+ * Returns the name of the section, or NULL on error. The returned string must
+ * be free()d.
+ *
+ * Note: There is no guarantee that the order of the sections
+ * will remain stable if the ini is modified.
+ */
+char *flib_ini_get_sectionname(flib_ini *ini, int number);
+
+/**
+ * Returns the number of keys in the current section, or -1 on error.
+ */
+int flib_ini_get_keycount(flib_ini *ini);
+
+/**
+ * Returns the name of the key in the current section, or NULL on error.
+ * The returned string must be free()d.
+ *
+ * Note: There is no guarantee that the order of the keys in a section
+ * will remain stable if the ini is modified.
+ */
+char *flib_ini_get_keyname(flib_ini *ini, int number);
+
+#endif /* INIHELPER_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/list.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,80 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/**
+ * Simple dynamic array manipulation functions.
+ */
+
+#ifndef LIST_H_
+#define LIST_H_
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include "util.h"
+#include "logging.h"
+
+/**
+ * Generate a static function that inserts a new value into a heap array of the given type,
+ * using realloc and memmove to increase the capacity and shift existing values.
+ * The function takes a pointer to the array variable and a pointer to the size variable
+ * because both can be changed by this operation (realloc / increment).
+ * The function returns 0 on success and leaves the array unchanged on error.
+ */
+#define GENERATE_STATIC_LIST_INSERT(fname, type) \
+	static int fname(type **listptr, int *listSizePtr, type element, int pos) { \
+		int result = -1; \
+		if(!log_badargs_if4(listptr==NULL, listSizePtr==NULL, pos < 0, pos > *listSizePtr)) { \
+			type *newList = flib_realloc(*listptr, ((*listSizePtr)+1)*sizeof(type)); \
+			if(newList) { \
+				memmove(newList + (pos+1), newList + pos, ((*listSizePtr)-pos)*sizeof(type)); \
+				newList[pos] = element; \
+				(*listSizePtr)++; \
+				*listptr = newList; \
+				result = 0; \
+			} \
+		} \
+		return result; \
+	}
+
+/**
+ * Generate a static function that deletes a value from a heap array of the given type,
+ * using realloc and memmove to decrease the capacity and shift existing values.
+ * The function takes a pointer to the array variable and a pointer to the size variable
+ * because both can be changed by this operation (realloc / decrement).
+ * The function returns 0 on success and leaves the array unchanged on error.
+ */
+#define GENERATE_STATIC_LIST_DELETE(fname, type) \
+	static int fname(type **listPtr, int *listSizePtr, int pos) { \
+		int result = -1; \
+		if(!log_badargs_if4(listPtr==NULL, listSizePtr==NULL, pos < 0, pos >= *listSizePtr)) { \
+			memmove((*listPtr) + pos, (*listPtr) + (pos+1), ((*listSizePtr)-(pos+1))*sizeof(type)); \
+			(*listSizePtr)--; \
+			\
+			size_t newCharSize = (*listSizePtr)*sizeof(type); \
+			type *newList = flib_realloc((*listPtr), newCharSize); \
+			if(newList || newCharSize==0) { \
+				(*listPtr) = newList; \
+			} /* If the realloc fails, just keep using the old buffer...*/ \
+			result = 0; \
+		} \
+		return result; \
+	}
+
+#endif /* LIST_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/logging.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,145 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "logging.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+static int flib_loglevel = FLIB_LOGLEVEL_INFO;
+static FILE *flib_logfile = NULL;
+void (*flib_logCallback)(int level, const char *msg) = NULL;
+
+char* flib_format_ip(uint32_t numip) {
+	static char ip[16];
+	snprintf(ip, 16, "%u.%u.%u.%u", (unsigned)(numip>>24), (unsigned)((numip>>16)&0xff), (unsigned)((numip>>8)&0xff), (unsigned)(numip&0xff));
+	return ip;
+}
+
+static inline FILE *flib_log_getfile() {
+	if(flib_logfile==NULL) {
+		return stdout;
+	} else {
+		return flib_logfile;
+	}
+}
+
+static int log_time(char *buffer) {
+    time_t timer;
+    struct tm* tm_info;
+
+    time(&timer);
+    tm_info = localtime(&timer);
+
+    return strftime(buffer, 25, "%Y-%m-%d %H:%M:%S", tm_info);
+}
+
+static char getPrefix(int level) {
+	switch(level) {
+	case FLIB_LOGLEVEL_ERROR: return 'E';
+	case FLIB_LOGLEVEL_WARNING: return 'W';
+	case FLIB_LOGLEVEL_INFO: return 'I';
+	case FLIB_LOGLEVEL_DEBUG: return 'D';
+	default: return '?';
+	}
+}
+
+static void _flib_vflog(const char *func, int level, const char *fmt, va_list args) {
+	if(level >= flib_loglevel) {
+		char logbuffer[1024];
+		logbuffer[0] = getPrefix(level);
+		logbuffer[1] = ' ';
+
+		int pos = 2;
+
+		int len = log_time(logbuffer+pos);
+		if(len>=0) {
+			pos += len;
+			if(pos>sizeof(logbuffer)-1) pos = sizeof(logbuffer)-1;
+		} else {
+			return;
+		}
+
+		len = snprintf(logbuffer+pos, sizeof(logbuffer)-pos, " [%-30s] ", func);
+		if(len>=0) {
+			pos += len;
+			if(pos>sizeof(logbuffer)-1) pos = sizeof(logbuffer)-1;
+		} else {
+			return;
+		}
+
+		len = vsnprintf(logbuffer+pos, sizeof(logbuffer)-pos, fmt, args);
+		if(len>=0) {
+			pos += len;
+			if(pos>sizeof(logbuffer)-1) pos = sizeof(logbuffer)-1;
+		} else {
+			return;
+		}
+
+		if(flib_logCallback != NULL) {
+			flib_logCallback(level, logbuffer);
+		} else {
+			FILE *logfile = flib_log_getfile();
+			fputs(logbuffer, logfile);
+			fputc('\n', logfile);
+			fflush(logfile);
+		}
+	}
+}
+
+void _flib_flog(const char *func, int level, const char *fmt, ...) {
+	va_list argp;
+	va_start(argp, fmt);
+	_flib_vflog(func, level, fmt, argp);
+	va_end(argp);
+}
+
+bool _flib_fassert(const char *func, int level, bool cond, const char *fmt, ...) {
+	if(!cond) {
+		va_list argp;
+		va_start(argp, fmt);
+		_flib_vflog(func, level, fmt, argp);
+		va_end(argp);
+	}
+	return !cond;
+}
+
+int flib_log_getLevel() {
+	return flib_loglevel;
+}
+
+void flib_log_setLevel(int level) {
+	flib_loglevel = level;
+}
+
+void flib_log_setFile(FILE *file) {
+	flib_logfile = file;
+	flib_logCallback = NULL;
+}
+
+bool flib_log_isActive(int level) {
+	return level >= flib_log_getLevel();
+}
+
+void flib_log_setCallback(void (*logCallback)(int level, const char *msg)) {
+	flib_logCallback = logCallback;
+	flib_logfile = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/logging.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,106 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef LOGGING_H_
+#define LOGGING_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#define FLIB_LOGLEVEL_ALL -100
+#define FLIB_LOGLEVEL_DEBUG -1
+#define FLIB_LOGLEVEL_INFO 0
+#define FLIB_LOGLEVEL_WARNING 1
+#define FLIB_LOGLEVEL_ERROR 2
+#define FLIB_LOGLEVEL_NONE 100
+
+/**
+ * Returns a pointer to a static buffer, don't free or store.
+ */
+char* flib_format_ip(uint32_t numip);
+
+/**
+ * Evaluates the expression cond. If it is true, a formatted error will be logged.
+ * Returns true if an error is logged, false otherwise (i.e. the boolean value of the argument)
+ * Usage: log_e_if(errorHasHappened, "Format string", formatArg, ...);
+ */
+#define log_e_if(cond, ...) _flib_fassert(__func__, FLIB_LOGLEVEL_ERROR, !(bool)(cond), __VA_ARGS__)
+#define log_w_if(cond, ...) _flib_fassert(__func__, FLIB_LOGLEVEL_WARNING, !(bool)(cond), __VA_ARGS__)
+
+/**
+ * Helper macros for log_badargs_if
+ * The t parameters are the textual representation of the c parameters. They need to be passed
+ * explicitly, to prevent them from being expanded in prescan.
+ */
+#define _flib_lbi(c1,t1) log_e_if(c1, "Invalid Argument (%s)", t1)
+#define _flib_lbi2(c1,t1,c2,t2) (_flib_lbi(c1,t1) || _flib_lbi(c2,t2))
+#define _flib_lbi3(c1,t1,c2,t2,c3,t3) (_flib_lbi(c1,t1) || _flib_lbi2(c2,t2,c3,t3))
+#define _flib_lbi4(c1,t1,c2,t2,c3,t3,c4,t4) (_flib_lbi(c1,t1) || _flib_lbi3(c2,t2,c3,t3,c4,t4))
+#define _flib_lbi5(c1,t1,c2,t2,c3,t3,c4,t4,c5,t5) (_flib_lbi(c1,t1) || _flib_lbi4(c2,t2,c3,t3,c4,t4,c5,t5))
+#define _flib_lbi6(c1,t1,c2,t2,c3,t3,c4,t4,c5,t5,c6,t6) (_flib_lbi(c1,t1) || _flib_lbi5(c2,t2,c3,t3,c4,t4,c5,t5,c6,t6))
+
+/**
+ * These macros log an "Invalid Argument" error for the first of their arguments that evaluates to true.
+ * The text of the argument is included in the log message.
+ * The expression returns true if any of its arguments is true (i.e. if an argument error was logged).
+ *
+ * For example, log_badargs_if(x==NULL) will log "Invalid Argument (x==NULL)" and return true if x is NULL.
+ */
+#define log_badargs_if(c1) _flib_lbi(c1,#c1)
+#define log_badargs_if2(c1, c2) _flib_lbi2(c1,#c1,c2,#c2)
+#define log_badargs_if3(c1, c2, c3) _flib_lbi3(c1,#c1,c2,#c2,c3,#c3)
+#define log_badargs_if4(c1, c2, c3, c4) _flib_lbi4(c1,#c1,c2,#c2,c3,#c3,c4,#c4)
+#define log_badargs_if5(c1, c2, c3, c4, c5) _flib_lbi5(c1,#c1,c2,#c2,c3,#c3,c4,#c4,c5,#c5)
+#define log_badargs_if6(c1, c2, c3, c4, c5, c6) _flib_lbi6(c1,#c1,c2,#c2,c3,#c3,c4,#c4,c5,#c5,c6,#c6)
+
+#define log_oom_if(cond) log_e_if(cond, "Out of Memory")
+
+#define flib_log_e(...) _flib_flog(__func__, FLIB_LOGLEVEL_ERROR, __VA_ARGS__)
+#define flib_log_w(...) _flib_flog(__func__, FLIB_LOGLEVEL_WARNING, __VA_ARGS__)
+#define flib_log_i(...) _flib_flog(__func__, FLIB_LOGLEVEL_INFO, __VA_ARGS__)
+#define flib_log_d(...) _flib_flog(__func__, FLIB_LOGLEVEL_DEBUG, __VA_ARGS__)
+
+bool _flib_fassert(const char *func, int level, bool cond, const char *fmt, ...);
+void _flib_flog(const char *func, int level, const char *fmt, ...);
+
+/**
+ * Only log messages that are at least the indicated level
+ */
+void flib_log_setLevel(int level);
+int flib_log_getLevel();
+
+/**
+ * Log to the indicated file. You can pass NULL to log to stdout.
+ * This overrides setCallback and vice versa.
+ */
+void flib_log_setFile(FILE *logfile);
+
+/**
+ * Returns whether messages of this level are logged at the moment.
+ */
+bool flib_log_isActive(int level);
+
+/**
+ * Allows logging through an arbitrary callback function. Useful for integrating into an
+ * existing logging system. This overrides setFile and vice versa.
+ */
+void flib_log_setCallback(void (*logCallback)(int level, const char *msg));
+
+#endif /* LOGGING_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/util.c	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,212 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "util.h"
+#include "logging.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+
+char *flib_asprintf(const char *fmt, ...) {
+	va_list argp;
+	va_start(argp, fmt);
+	char *result = flib_vasprintf(fmt, argp);
+	va_end(argp);
+	return result;
+}
+
+char *flib_vasprintf(const char *fmt, va_list args) {
+	char *result = NULL;
+	if(!log_badargs_if(fmt==NULL)) {
+		int requiredSize = vsnprintf(NULL, 0, fmt, args)+1;					// Figure out how much memory we need,
+		if(!log_e_if(requiredSize<0, "Error formatting string with template \"%s\"", fmt)) {
+			char *tmpbuf = flib_malloc(requiredSize);						// allocate it
+			if(tmpbuf && vsnprintf(tmpbuf, requiredSize, fmt, args)>=0) {	// and then do the actual formatting.
+				result = tmpbuf;
+				tmpbuf = NULL;
+			}
+			free(tmpbuf);
+		}
+	}
+	return result;
+}
+
+char *flib_join(char **parts, int partCount, const char *delimiter) {
+	char *result = NULL;
+	if(!log_badargs_if2(parts==NULL, delimiter==NULL)) {
+		size_t totalSize = 1;
+		size_t delimLen = strlen(delimiter);
+		for(int i=0; i<partCount; i++) {
+			totalSize += strlen(parts[i]) + delimLen;
+		}
+		result = flib_malloc(totalSize);
+
+		if(result) {
+			size_t outpos = 0;
+			for(int i=0; i<partCount; i++) {
+				if(i>0) {
+					strcpy(result+outpos, delimiter);
+					outpos += delimLen;
+				}
+				strcpy(result+outpos, parts[i]);
+				outpos += strlen(parts[i]);
+			}
+		}
+	}
+	return result;
+}
+
+char *flib_strdupnull(const char *str) {
+	return str==NULL ? NULL : flib_asprintf("%s", str);
+}
+
+void *flib_bufdupnull(const void *buf, size_t size) {
+	void *result = NULL;
+	if(!log_badargs_if(buf==NULL && size>0)) {
+		result = flib_malloc(size);
+		if(result) {
+			memcpy(result, buf, size);
+		}
+	}
+	return result;
+}
+
+void *flib_malloc(size_t size) {
+	void *result = malloc(size);
+	if(!result && size>0) {
+		flib_log_e("Out of memory trying to malloc %zu bytes.", size);
+	}
+	return result;
+}
+
+void *flib_calloc(size_t count, size_t elementsize) {
+	void *result = calloc(count, elementsize);
+	if(!result && count>0 && elementsize>0) {
+		flib_log_e("Out of memory trying to calloc %zu objects of %zu bytes each.", count, elementsize);
+	}
+	return result;
+}
+
+void *flib_realloc(void *ptr, size_t size) {
+	void *result = realloc(ptr, size);
+	if(!result && size>0) {
+		flib_log_e("Out of memory trying to realloc %zu bytes.", size);
+	}
+	return result;
+}
+
+static bool isAsciiAlnum(char c) {
+	return (c>='0' && c<='9') || (c>='a' && c <='z') || (c>='A' && c <='Z');
+}
+
+char *flib_urlencode(const char *inbuf) {
+	return flib_urlencode_pred(inbuf, isAsciiAlnum);
+}
+
+static size_t countCharsToEscape(const char *inbuf, bool (*needsEscaping)(char c)) {
+	size_t result = 0;
+	for(const char *c=inbuf; *c; c++) {
+		if(needsEscaping(*c)) {
+			result++;
+		}
+	}
+	return result;
+}
+
+char *flib_urlencode_pred(const char *inbuf, bool (*needsEscaping)(char c)) {
+	char *result = NULL;
+	if(inbuf && !log_badargs_if(needsEscaping == NULL)) {
+		size_t insize = strlen(inbuf);
+		if(!log_e_if(insize > SIZE_MAX/4, "String too long: %zu bytes.", insize)) {
+			size_t escapeCount = countCharsToEscape(inbuf, needsEscaping);
+			result = flib_malloc(insize + escapeCount*2 + 1);
+		}
+		if(result) {
+			char *out = result;
+			for(const char *in = inbuf; *in; in++) {
+				if(!needsEscaping(*in)) {
+					*out = *in;
+					out++;
+				} else {
+					snprintf(out, 4, "%%%02x", (unsigned)(*(uint8_t*)in));
+					out += 3;
+				}
+			}
+			*out = 0;
+		}
+	}
+	return result;
+}
+
+char *flib_urldecode(const char *inbuf) {
+	if(!inbuf) {
+		return NULL;
+	}
+	char *outbuf = flib_malloc(strlen(inbuf)+1);
+	if(!outbuf) {
+		return NULL;
+	}
+
+    size_t inpos = 0, outpos = 0;
+    while(inbuf[inpos]) {
+        if(inbuf[inpos] == '%' && isxdigit(inbuf[inpos+1]) && isxdigit(inbuf[inpos+2])) {
+            char temp[3] = {inbuf[inpos+1],inbuf[inpos+2],0};
+            outbuf[outpos++] = strtol(temp, NULL, 16);
+            inpos += 3;
+        } else {
+        	outbuf[outpos++] = inbuf[inpos++];
+        }
+    }
+    outbuf[outpos] = 0;
+    char *shrunk = realloc(outbuf, outpos+1);
+    return shrunk ? shrunk : outbuf;
+}
+
+bool flib_contains_dir_separator(const char *str) {
+	if(!log_badargs_if(!str)) {
+		for(;*str;str++) {
+			if(*str=='\\' || *str=='/') {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+bool flib_strempty(const char *str) {
+	return !str || !*str;
+}
+
+int flib_gets(char *str, size_t strlen) {
+	if(fgets(str, strlen, stdin)) {
+		for(char *s=str; *s; s++) {
+			if(*s=='\r' || *s=='\n') {
+				*s = 0;
+				break;
+			}
+		}
+		return 0;
+	}
+	return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/frontlib/util/util.h	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,122 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (C) 2012 Simeon Maxein <smaxein@googlemail.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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLIB_UTIL_H_
+#define FLIB_UTIL_H_
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+/**
+ * Prints a format string to a newly allocated buffer of the required size.
+ * Parameters are like those for printf. Returns NULL on error.
+ *
+ * Returned buffer must be free()d
+ */
+char *flib_asprintf(const char *fmt, ...);
+
+/**
+ * Exactly as flib_asprintf, but accepts a va_list.
+ */
+char *flib_vasprintf(const char *fmt, va_list args);
+
+/**
+ * Creates a new string (that must be freed) containing all parts
+ * joined together, with the specified delimiter between each.
+ */
+char *flib_join(char **parts, int partCount, const char *delimiter);
+
+/**
+ * Return a duplicate of the provided string, or NULL if an error
+ * occurs or if str is already NULL.
+ *
+ * Returned buffer must be free()d
+ */
+char *flib_strdupnull(const char *str);
+
+/**
+ * Return a duplicate of the provided buffer, or NULL if an error
+ * occurs or if buf is already NULL or if size is 0.
+ *
+ * Returned buffer must be free()d
+ */
+void *flib_bufdupnull(const void *buf, size_t size);
+
+/**
+ * Simple malloc wrapper that automatically logs an error if no memory
+ * is available. Otherwise behaves exactly like malloc.
+ */
+void *flib_malloc(size_t size);
+
+/**
+ * Simple calloc wrapper that automatically logs an error if no memory
+ * is available. Otherwise behaves exactly like calloc.
+ */
+void *flib_calloc(size_t count, size_t elementsize);
+
+/**
+ * Simple realloc wrapper that automatically logs an error if no memory
+ * is available. Otherwise behaves exactly like realloc.
+ */
+void *flib_realloc(void *ptr, size_t size);
+
+/**
+ * Replace all non-alphanumeric and non-ascii bytes with escape
+ * sequences in the form %XX. Does not modify the original string,
+ * but returns a newly allocated one that must be free()d. Returns
+ * null on failure or if null was passed as argument.
+ *
+ * This should work fine with all ASCII-based charsets including UTF-8.
+ */
+char *flib_urlencode(const char *str);
+
+/**
+ * Replace some bytes with escape sequences in the form %XX.
+ * Does not modify the original string, but returns a newly allocated
+ * one that must be free()d.
+ *
+ * All bytes for which the predicate function returns true are escaped.
+ *
+ * Returns null on failure or if null was passed as argument.
+ */
+char *flib_urlencode_pred(const char *str, bool (*needsEscaping)(char c));
+
+/**
+ * Replace escape sequences of the form %XX with their byte values.
+ * Does not modify the original string, but returns a newly allocated
+ * one that must be free()d. Returns null on failure or if null was
+ * passed as argument.
+ */
+char *flib_urldecode(const char *str);
+
+/**
+ * Figure out if the string contains / or \. Useful in routines that
+ * construct filenames.
+ */
+bool flib_contains_dir_separator(const char *str);
+
+/**
+ * Returns true if str is either NULL or points to a 0-length string
+ */
+bool flib_strempty(const char *str);
+
+int flib_gets(char *str, size_t strlen);
+
+#endif
--- a/project_files/hedgewars.pro	Sun Nov 18 23:09:29 2012 +0400
+++ b/project_files/hedgewars.pro	Sun Nov 18 23:10:26 2012 +0400
@@ -1,7 +1,7 @@
 TEMPLATE = app
 TARGET = hedgewars
 DEPENDPATH += ../QTfrontend/
-INCLUDEPATH += ../QTfrontend/
+INCLUDEPATH += ../QTfrontend
 INCLUDEPATH += ../QTfrontend/model
 INCLUDEPATH += ../QTfrontend/ui
 INCLUDEPATH += ../QTfrontend/ui/widget
@@ -9,7 +9,8 @@
 INCLUDEPATH += ../QTfrontend/ui/dialog
 INCLUDEPATH += ../QTfrontend/net
 INCLUDEPATH += ../QTfrontend/util
-INCLUDEPATH += ../misc/quazip/
+INCLUDEPATH += ../misc/physfs/src
+INCLUDEPATH += ../misc/physfs/extras
 
 DESTDIR = ../bin
 
@@ -105,7 +106,9 @@
     ../QTfrontend/ui/dialog/upload_video.h \
     ../QTfrontend/campaign.h \
     ../QTfrontend/model/playerslistmodel.h \
-    ../QTfrontend/util/LibavInteraction.h
+    ../QTfrontend/util/LibavInteraction.h \
+    ../QTfrontend/util/FileEngine.h
+
 
 SOURCES += ../QTfrontend/model/ammoSchemeModel.cpp \
     ../QTfrontend/model/MapModel.cpp \
@@ -194,26 +197,32 @@
     ../QTfrontend/ui/dialog/upload_video.cpp \
     ../QTfrontend/campaign.cpp \
     ../QTfrontend/model/playerslistmodel.cpp \
-    ../QTfrontend/util/LibavInteraction.cpp
+    ../QTfrontend/util/LibavInteraction.cpp \
+    ../QTfrontend/util/FileEngine.cpp
 
 
 TRANSLATIONS += ../share/hedgewars/Data/Locale/hedgewars_ar.ts \
     ../share/hedgewars/Data/Locale/hedgewars_bg.ts \
     ../share/hedgewars/Data/Locale/hedgewars_cs.ts \
+    ../share/hedgewars/Data/Locale/hedgewars_da.ts \
     ../share/hedgewars/Data/Locale/hedgewars_de.ts \ 
+    ../share/hedgewars/Data/Locale/hedgewars_el.ts \
     ../share/hedgewars/Data/Locale/hedgewars_en.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_es.ts \
     ../share/hedgewars/Data/Locale/hedgewars_fi.ts \
     ../share/hedgewars/Data/Locale/hedgewars_fr.ts \ 
+    ../share/hedgewars/Data/Locale/hedgewars_gl.ts \
     ../share/hedgewars/Data/Locale/hedgewars_hu.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_it.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_ja.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_ko.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_lt.ts \
+    ../share/hedgewars/Data/Locale/hedgewars_ms.ts \
     ../share/hedgewars/Data/Locale/hedgewars_nl.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_pl.ts \ 
     ../share/hedgewars/Data/Locale/hedgewars_pt_BR.ts \
     ../share/hedgewars/Data/Locale/hedgewars_pt_PT.ts \
+    ../share/hedgewars/Data/Locale/hedgewars_ro.ts \
     ../share/hedgewars/Data/Locale/hedgewars_ru.ts \
     ../share/hedgewars/Data/Locale/hedgewars_sk.ts \
     ../share/hedgewars/Data/Locale/hedgewars_sv.ts \
@@ -224,7 +233,7 @@
 
 RESOURCES += ../QTfrontend/hedgewars.qrc
 
-LIBS += -L../bin -lquazip
+LIBS += -L../bin -lphysfs -lphysfsrwops
 
 macx {
     QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6
--- a/share/hedgewars/Data/Locale/cs.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/cs.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
       ["Hooray!"] = "Hurá!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/da.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/da.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
         ["Hooray!"] = "Hurra!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/de.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/de.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 	["Hooray!"] = "Hurra!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/el.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/el.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-; Greek locale
+; Greek locale
 
 00:00=Χειροβομβίδα
 00:01=Χειροβομβίδα Διασποράς
--- a/share/hedgewars/Data/Locale/es.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/es.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 	["Hooray!"] = "¡Hurra!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/fr.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/fr.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -331,7 +331,7 @@
 	  ["Hmmm...perhaps a little more time will help."] = "humm...Peut être qu'un peu plus de temps aiderait",
 --      ["Hogminator"] = "",
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "",
       ["Hooray!"] = "Hourra ! ",
       ["Hostage Situation"] = "Situation d'otage",
--- a/share/hedgewars/Data/Locale/hedgewars_ar.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_ar.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -342,7 +342,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -829,14 +829,6 @@
         <source>Control</source>
         <translation>تحكم</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2147,6 +2139,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_bg.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_bg.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -831,14 +831,6 @@
         <source>Control</source>
         <translation>Контрол</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2150,6 +2142,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_cs.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_cs.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -345,7 +345,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -838,14 +838,6 @@
         <source>Control</source>
         <translation>Ovládání</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2160,6 +2152,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_da.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_da.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -2,6 +2,13 @@
 <!DOCTYPE TS>
 <TS version="2.0" language="da">
 <context>
+    <name>AbstractPage</name>
+    <message>
+        <source>Go back</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>AmmoSchemeModel</name>
     <message>
         <source>new</source>
@@ -16,15 +23,15 @@
     <name>DrawMapWidget</name>
     <message>
         <source>File error</source>
-        <translation>Fejl i fil</translation>
+        <translation type="obsolete">Fejl i fil</translation>
     </message>
     <message>
         <source>Cannot open file &apos;%1&apos; for writing</source>
-        <translation>Kan ikke åbne filen &apos;%1&apos; til skrivning</translation>
+        <translation type="obsolete">Kan ikke åbne filen &apos;%1&apos; til skrivning</translation>
     </message>
     <message>
         <source>Cannot read file &apos;%1&apos;</source>
-        <translation>Kan ikke læse filen &apos;%1&apos;</translation>
+        <translation type="obsolete">Kan ikke læse filen &apos;%1&apos;</translation>
     </message>
 </context>
 <context>
@@ -49,11 +56,11 @@
     </message>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>Illegal ammo scheme</source>
-        <translation>Ugyldig ammunitionssystem</translation>
+        <translation type="obsolete">Ugyldig ammunitionssystem</translation>
     </message>
     <message>
         <source>Edit schemes</source>
@@ -69,22 +76,29 @@
     </message>
 </context>
 <context>
+    <name>HWAskQuitDialog</name>
+    <message>
+        <source>Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>HWChatWidget</name>
     <message>
         <source>%1 *** %2 has been removed from your ignore list</source>
-        <translation>%1 *** %2 er blevet fjernet fra din ignoreringsliste</translation>
+        <translation type="obsolete">%1 *** %2 er blevet fjernet fra din ignoreringsliste</translation>
     </message>
     <message>
         <source>%1 *** %2 has been added to your ignore list</source>
-        <translation>%1 *** %2 er blevet tilføjet til din ignoreringsliste</translation>
+        <translation type="obsolete">%1 *** %2 er blevet tilføjet til din ignoreringsliste</translation>
     </message>
     <message>
         <source>%1 *** %2 has been removed from your friends list</source>
-        <translation>%1 *** %2 er blevet fjernet fra din venneliste</translation>
+        <translation type="obsolete">%1 *** %2 er blevet fjernet fra din venneliste</translation>
     </message>
     <message>
         <source>%1 *** %2 has been added to your friends list</source>
-        <translation>%1 *** %2 er blevet tilføjet til din venneliste</translation>
+        <translation type="obsolete">%1 *** %2 er blevet tilføjet til din venneliste</translation>
     </message>
     <message>
         <source>%1 has been removed from your ignore list</source>
@@ -132,26 +146,26 @@
     </message>
     <message>
         <source>Kicking %1 ...</source>
-        <translation>Smider %1 ud...</translation>
+        <translation type="obsolete">Smider %1 ud...</translation>
     </message>
 </context>
 <context>
     <name>HWForm</name>
     <message>
         <source>new</source>
-        <translation>ny</translation>
+        <translation type="obsolete">ny</translation>
     </message>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Unable to start the server</source>
-        <translation>Ude af stand til at starte serveren</translation>
+        <translation type="obsolete">Ude af stand til at starte serveren</translation>
     </message>
     <message>
         <source>Cannot save record to file %1</source>
@@ -159,7 +173,7 @@
     </message>
     <message>
         <source>Please select record from the list above</source>
-        <translation>Vælg venligst en optagelse fra den ovenstående liste</translation>
+        <translation type="obsolete">Vælg venligst en optagelse fra den ovenstående liste</translation>
     </message>
     <message>
         <source>DefaultTeam</source>
@@ -189,7 +203,7 @@
     </message>
     <message>
         <source>Password</source>
-        <translation>Kodeord</translation>
+        <translation type="obsolete">Kodeord</translation>
     </message>
     <message>
         <source>Your nickname %1 is
@@ -214,7 +228,7 @@
  your nickname %1
 on the server.
 Please pick another nickname:</source>
-        <translation>En eller anden bruger allerede
+        <translation type="obsolete">En eller anden bruger allerede
 dit brugernavn %1
 på serveren.
 Vælg venligst et andet brugernavn:</translation>
@@ -223,6 +237,11 @@
         <source>No nickname supplied.</source>
         <translation>Intet brugernavn indtastet.</translation>
     </message>
+    <message>
+        <source>Someone already uses your nickname %1 on the server.
+Please pick another nickname:</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>HWGame</name>
@@ -349,7 +368,7 @@
     </message>
     <message>
         <source>Password</source>
-        <translation>Kodeord</translation>
+        <translation type="obsolete">Kodeord</translation>
     </message>
     <message>
         <source>Your nickname %1 is
@@ -389,12 +408,38 @@
     </message>
     <message>
         <source>Nickname</source>
-        <translation>Brugernavn</translation>
+        <translation type="obsolete">Brugernavn</translation>
     </message>
     <message>
         <source>User quit</source>
         <translation>En bruger forlod</translation>
     </message>
+    <message>
+        <source>Remote host has closed connection</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The server is too old. Disconnecting now.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWPasswordDialog</name>
+    <message>
+        <source>Password</source>
+        <translation type="unfinished">Kodeord</translation>
+    </message>
+</context>
+<context>
+    <name>HWUploadVideoDialog</name>
+    <message>
+        <source>Upload video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>KB</name>
@@ -404,14 +449,34 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageAdmin</name>
     <message>
         <source>Server message:</source>
-        <translation>Serverbesked:</translation>
+        <translation type="obsolete">Serverbesked:</translation>
     </message>
     <message>
         <source>Set message</source>
-        <translation>Indstil besked</translation>
+        <translation type="obsolete">Indstil besked</translation>
     </message>
     <message>
         <source>Clear Accounts Cache</source>
@@ -450,7 +515,7 @@
     </message>
     <message>
         <source>Cancel</source>
-        <translation>Annuler</translation>
+        <translation type="obsolete">Annuler</translation>
     </message>
 </context>
 <context>
@@ -487,6 +552,10 @@
         <source>All files</source>
         <translation>Alle filer</translation>
     </message>
+    <message>
+        <source>Eraser</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageEditTeam</name>
@@ -503,7 +572,7 @@
     <name>PageGameStats</name>
     <message>
         <source>&lt;p&gt;The best shot award was won by &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; pts.&lt;/p&gt;</source>
-        <translation>&lt;p&gt;Prisen for det bedste skud gik til &lt;b&gt;%1&lt;/b&gt; med &lt;b&gt;%2&lt;/b&gt; point.&lt;/p&gt;</translation>
+        <translation type="obsolete">&lt;p&gt;Prisen for det bedste skud gik til &lt;b&gt;%1&lt;/b&gt; med &lt;b&gt;%2&lt;/b&gt; point.&lt;/p&gt;</translation>
     </message>
     <message numerus="yes">
         <source>&lt;p&gt;The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.&lt;/p&gt;</source>
@@ -586,14 +655,21 @@
     </message>
 </context>
 <context>
+    <name>PageInfo</name>
+    <message>
+        <source>Open the snapshot folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageMain</name>
     <message>
         <source>Local Game (Play a game on a single computer)</source>
-        <translation>Lokalt spil (Spil et spil på én enkelt computer)</translation>
+        <translation type="obsolete">Lokalt spil (Spil et spil på én enkelt computer)</translation>
     </message>
     <message>
         <source>Network Game (Play a game across a network)</source>
-        <translation>Netværksspil (Spil et spil over et netværk)</translation>
+        <translation type="obsolete">Netværksspil (Spil et spil over et netværk)</translation>
     </message>
     <message>
         <source>Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they&apos;ll win or lose together.</source>
@@ -844,6 +920,46 @@
         <source>Downloadable Content</source>
         <translation>Indhold der kan Downloades</translation>
     </message>
+    <message>
+        <source>Local Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game on a single computer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game across a network</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read about who is behind the Hedgewars Project</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Access the user created content downloadable from our website</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Exit game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manage videos recorded from game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit game preferences</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageMultiplayer</name>
@@ -856,11 +972,11 @@
     <name>PageNet</name>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>Please select server from the list above</source>
-        <translation>Vælg venligst en server fra den ovenstående liste</translation>
+        <translation type="obsolete">Vælg venligst en server fra den ovenstående liste</translation>
     </message>
 </context>
 <context>
@@ -871,15 +987,15 @@
     </message>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>Please enter room name</source>
-        <translation>Indtast venligst navnet på rummet</translation>
+        <translation type="obsolete">Indtast venligst navnet på rummet</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
 </context>
 <context>
@@ -892,6 +1008,14 @@
         <source>Official server</source>
         <translation>Officiel server</translation>
     </message>
+    <message>
+        <source>Join or host your own game server in a Local Area Network.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Join hundreds of players online!</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageOptions</name>
@@ -909,15 +1033,15 @@
     </message>
     <message>
         <source>New weapon scheme</source>
-        <translation>Nyt våbensystem</translation>
+        <translation type="obsolete">Nyt våbensystem</translation>
     </message>
     <message>
         <source>Edit weapon scheme</source>
-        <translation>Rediger våbensystem</translation>
+        <translation type="obsolete">Rediger våbensystem</translation>
     </message>
     <message>
         <source>Delete weapon scheme</source>
-        <translation>Slet våbensystem</translation>
+        <translation type="obsolete">Slet våbensystem</translation>
     </message>
     <message>
         <source>You can&apos;t edit teams from team selection. Go back to main menu to add, edit or delete teams.</source>
@@ -947,16 +1071,60 @@
         <source>Delete weapon set</source>
         <translation>Slet våbensæt</translation>
     </message>
+    <message>
+        <source>General</source>
+        <translation type="unfinished">Generelt</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished">Advanceret</translation>
+    </message>
+    <message>
+        <source>Reset to default colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy host</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy port</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>System proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Socks5 proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HTTP proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PagePlayDemo</name>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Rename dialog</source>
@@ -968,15 +1136,15 @@
     </message>
     <message>
         <source>Cannot rename to</source>
-        <translation>Kan ikke omdøbe til</translation>
+        <translation type="obsolete">Kan ikke omdøbe til</translation>
     </message>
     <message>
         <source>Cannot delete file</source>
-        <translation>Kan ikke slette fil</translation>
+        <translation type="obsolete">Kan ikke slette fil</translation>
     </message>
     <message>
         <source>Please select record from the list</source>
-        <translation>Vælg venligst en optagelse fra listen</translation>
+        <translation type="obsolete">Vælg venligst en optagelse fra listen</translation>
     </message>
 </context>
 <context>
@@ -991,15 +1159,15 @@
     </message>
     <message>
         <source>Refresh</source>
-        <translation>Opdater</translation>
+        <translation type="obsolete">Opdater</translation>
     </message>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Admin features</source>
@@ -1012,60 +1180,60 @@
     <message>
         <source>This game is in lobby.
 You may join and start playing once the game starts.</source>
-        <translation>Dette spil er i lobbyen.
+        <translation type="obsolete">Dette spil er i lobbyen.
 Du kan tilslutte dig og spille med når spillet starter.</translation>
     </message>
     <message>
         <source>This game is in progress.
 You may join and spectate now but you&apos;ll have to wait for the game to end to start playing.</source>
-        <translation>Dette spil er i gang.
+        <translation type="obsolete">Dette spil er i gang.
 Du kan tilslutte dig og kigge med med det samme, men du må vente på at spillet slutter med selv at kunne spille med.</translation>
     </message>
     <message>
         <source>%1 is the host. He may adjust settings and start the game.</source>
-        <translation>%1 er værten. Han kan ændre indstillingerne og starte spillet.</translation>
+        <translation type="obsolete">%1 er værten. Han kan ændre indstillingerne og starte spillet.</translation>
     </message>
     <message>
         <source>Random Map</source>
-        <translation>Tilfældig Bane</translation>
+        <translation type="obsolete">Tilfældig Bane</translation>
     </message>
     <message>
         <source>Games may be played on precreated or randomized maps.</source>
-        <translation>Man kan spille enten på allerede lavede eller tilfældigt genererede baner.</translation>
+        <translation type="obsolete">Man kan spille enten på allerede lavede eller tilfældigt genererede baner.</translation>
     </message>
     <message>
         <source>The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</source>
-        <translation>Spilsystemet definerer generelle indstillinger og præferencer, så som rundelængden, Pludselig Død og Vampyr.</translation>
+        <translation type="obsolete">Spilsystemet definerer generelle indstillinger og præferencer, så som rundelængden, Pludselig Død og Vampyr.</translation>
     </message>
     <message>
         <source>The Weapon Scheme defines available weapons and their ammunition count.</source>
-        <translation>Våbensystemet definere hvilke våben der er tilgængelige og hvor meget ammunition de har.</translation>
+        <translation type="obsolete">Våbensystemet definere hvilke våben der er tilgængelige og hvor meget ammunition de har.</translation>
     </message>
     <message numerus="yes">
         <source>There are %1 clients connected to this room.</source>
-        <translation>
+        <translation type="obsolete">
             <numerusform>Der er %1 klient forbundet til dette rum.</numerusform>
             <numerusform>Der er %1 klienter forbundet til dette rum.</numerusform>
         </translation>
     </message>
     <message numerus="yes">
         <source>There are %1 teams participating in this room.</source>
-        <translation>
+        <translation type="obsolete">
             <numerusform>Der deltager %1 hold i dette rum.</numerusform>
             <numerusform>Der deltager %1 hold i dette rum.</numerusform>
         </translation>
     </message>
     <message>
         <source>Please enter room name</source>
-        <translation>Indtast venligst rummets navn</translation>
+        <translation type="obsolete">Indtast venligst rummets navn</translation>
     </message>
     <message>
         <source>Please select room from the list</source>
-        <translation>Vælg venligst et rum fra listen</translation>
+        <translation type="obsolete">Vælg venligst et rum fra listen</translation>
     </message>
     <message>
         <source>Random Maze</source>
-        <translation>Tilfældig Labyrint</translation>
+        <translation type="obsolete">Tilfældig Labyrint</translation>
     </message>
     <message>
         <source>Rules:</source>
@@ -1085,12 +1253,12 @@
     </message>
     <message>
         <source>Warning</source>
-        <translation>Advarsel</translation>
+        <translation type="obsolete">Advarsel</translation>
     </message>
     <message>
         <source>The game you are trying to join has started.
 Do you still want to join the room?</source>
-        <translation>Det spil du forsøge at tilslutte dig er allerede startet.
+        <translation type="obsolete">Det spil du forsøge at tilslutte dig er allerede startet.
 Har du stadig lyst til at tilslutte dig rummet?</translation>
     </message>
     <message numerus="yes">
@@ -1117,7 +1285,7 @@
     </message>
     <message>
         <source>Add an indestructable border around the terrain</source>
-        <translation>Tilføj en kant rundt om banen som ikke kan destrueres</translation>
+        <translation type="obsolete">Tilføj en kant rundt om banen som ikke kan destrueres</translation>
     </message>
     <message>
         <source>Lower gravity</source>
@@ -1133,7 +1301,7 @@
     </message>
     <message>
         <source>Enable random mines</source>
-        <translation>Aktiver tilfældige miner</translation>
+        <translation type="obsolete">Aktiver tilfældige miner</translation>
     </message>
     <message>
         <source>Gain 80% of the damage you do back in health</source>
@@ -1255,27 +1423,71 @@
     <name>PageSinglePlayer</name>
     <message>
         <source>Simple Game (a quick game against the computer, settings are chosen for you)</source>
-        <translation>Simpelt spil (et hurtigt spil mod computeren, hvor indstillingerne er valgt på forhånd)</translation>
+        <translation type="obsolete">Simpelt spil (et hurtigt spil mod computeren, hvor indstillingerne er valgt på forhånd)</translation>
     </message>
     <message>
         <source>Multiplayer (play a hotseat game against your friends, or AI teams)</source>
-        <translation>Multiplayer (spil mod flere venner eller AI hold ved samme computer)</translation>
+        <translation type="obsolete">Multiplayer (spil mod flere venner eller AI hold ved samme computer)</translation>
     </message>
     <message>
         <source>Training Mode (Practice your skills in a range of training missions)</source>
-        <translation>Træningsspil (Rafiner dine evner i en række forskellige træningsmissioner)</translation>
+        <translation type="obsolete">Træningsspil (Rafiner dine evner i en række forskellige træningsmissioner)</translation>
     </message>
     <message>
         <source>Demos (Watch recorded demos)</source>
-        <translation>Demoer (Afspil optagede demoer)</translation>
+        <translation type="obsolete">Demoer (Afspil optagede demoer)</translation>
     </message>
     <message>
         <source>Load (Load a previously saved game)</source>
-        <translation>Indlæs (Indlæs et tidligere gemt spil)</translation>
+        <translation type="obsolete">Indlæs (Indlæs et tidligere gemt spil)</translation>
     </message>
     <message>
         <source>Campaign Mode (...)</source>
-        <translation>Kampagnespil (...)</translation>
+        <translation type="obsolete">Kampagnespil (...)</translation>
+    </message>
+    <message>
+        <source>Simple Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a quick game against the computer with random settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Multiplayer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a hotseat game against your friends, or AI teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Campaign Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Training Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Practice your skills in a range of training missions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Watch recorded demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation type="unfinished">Indlæs</translation>
+    </message>
+    <message>
+        <source>Load a previously saved game</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -1288,6 +1500,52 @@
         <source>Select a mission!</source>
         <translation>Vælg en mission!</translation>
     </message>
+    <message>
+        <source>Pick the mission or training to play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Start fighting</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageVideos</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished">Navn</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>%1 bytes</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>(in progress...)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Date: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>encoding</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QAction</name>
@@ -1376,7 +1634,7 @@
     </message>
     <message>
         <source>Reduced quality</source>
-        <translation>Reduceret kvalitet</translation>
+        <translation type="obsolete">Reduceret kvalitet</translation>
     </message>
     <message>
         <source>Show ammo menu tooltips</source>
@@ -1394,6 +1652,26 @@
         <source>Frontend effects</source>
         <translation>Effekter (frontend)</translation>
     </message>
+    <message>
+        <source>Save password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Save account name and password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video is private</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Record audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Use game resolution</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QComboBox</name>
@@ -1439,7 +1717,7 @@
     </message>
     <message>
         <source>Default</source>
-        <translation>Standard</translation>
+        <translation type="obsolete">Standard</translation>
     </message>
     <message>
         <source>hand drawn map...</source>
@@ -1530,7 +1808,7 @@
     </message>
     <message>
         <source>Weapons</source>
-        <translation>Våben</translation>
+        <translation type="obsolete">Våben</translation>
     </message>
     <message>
         <source>Audio/Graphic options</source>
@@ -1564,6 +1842,30 @@
         <source>Schemes and Weapons</source>
         <translation>Spilsystemer og Våben</translation>
     </message>
+    <message>
+        <source>Custom colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Miscellaneous</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video recording options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QLabel</name>
@@ -1581,7 +1883,7 @@
     </message>
     <message>
         <source>This program is distributed under the GNU General Public License</source>
-        <translation>Dette program distribueres under GNU General Public License</translation>
+        <translation type="obsolete">Dette program distribueres under GNU General Public License</translation>
     </message>
     <message>
         <source>Developers:</source>
@@ -1617,7 +1919,7 @@
     </message>
     <message>
         <source>Net nick</source>
-        <translation>Brugernavn</translation>
+        <translation type="obsolete">Brugernavn</translation>
     </message>
     <message>
         <source>Resolution</source>
@@ -1697,7 +1999,7 @@
     </message>
     <message>
         <source>Restart game to apply</source>
-        <translation>Genstart spil for at anvende</translation>
+        <translation type="obsolete">Genstart spil for at anvende</translation>
     </message>
     <message>
         <source>Explosives</source>
@@ -1749,7 +2051,7 @@
     </message>
     <message>
         <source>Password</source>
-        <translation>Kodeord</translation>
+        <translation type="obsolete">Kodeord</translation>
     </message>
     <message>
         <source>% Get Away Time</source>
@@ -1759,6 +2061,68 @@
         <source>This program is distributed under the GNU General Public License v2</source>
         <translation>Dette program distribueres under GNU General Public License v2</translation>
     </message>
+    <message>
+        <source>There are videos that are currently being processed.
+Exiting now will abort them.
+Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please provide either the YouTube account name or the email address associated with the Google Account.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Account name (or email): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video title: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video description: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tags (comma separated): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Summary   </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation type="unfinished">Brugernavn</translation>
+    </message>
+    <message>
+        <source>Format</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Framerate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Bitrate (Kbps)</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QLineEdit</name>
@@ -1770,6 +2134,10 @@
         <source>hedgehog %1</source>
         <translation>pindsvin %1</translation>
     </message>
+    <message>
+        <source>anonymous</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QMainWindow</name>
@@ -1782,7 +2150,7 @@
     <name>QMessageBox</name>
     <message>
         <source>Network</source>
-        <translation>Netværk</translation>
+        <translation type="obsolete">Netværk</translation>
     </message>
     <message>
         <source>Connection to server is lost</source>
@@ -1796,33 +2164,33 @@
         <source>Failed to open data directory:
 %1
 Please check your installation</source>
-        <translation>Det mislykkedes at åbne data mappen:
+        <translation type="obsolete">Det mislykkedes at åbne data mappen:
 %1
 Tjek venligst om spillet er installeret korrekt</translation>
     </message>
     <message>
         <source>Weapons</source>
-        <translation>Våben</translation>
+        <translation type="obsolete">Våben</translation>
     </message>
     <message>
         <source>Can not edit default weapon set</source>
-        <translation>Kan ikke ændre standardvåbensæt</translation>
+        <translation type="obsolete">Kan ikke ændre standardvåbensæt</translation>
     </message>
     <message>
         <source>Can not delete default weapon set</source>
-        <translation>Kan ikke slette standardvåbensæt</translation>
+        <translation type="obsolete">Kan ikke slette standardvåbensæt</translation>
     </message>
     <message>
         <source>Really delete this weapon set?</source>
-        <translation>Vil du virkelig slette dette våbensæt?</translation>
+        <translation type="obsolete">Vil du virkelig slette dette våbensæt?</translation>
     </message>
     <message>
         <source>Can not overwrite default weapon set &apos;%1&apos;!</source>
-        <translation>Kan ikke overskrive standardvåbensættet &apos;%1&apos;!</translation>
+        <translation type="obsolete">Kan ikke overskrive standardvåbensættet &apos;%1&apos;!</translation>
     </message>
     <message>
         <source>All file associations have been set.</source>
-        <translation>Alle filtilknytninger er blevet indstillede.</translation>
+        <translation type="obsolete">Alle filtilknytninger er blevet indstillede.</translation>
     </message>
     <message>
         <source>File association failed.</source>
@@ -1830,42 +2198,252 @@
     </message>
     <message>
         <source>Teams</source>
-        <translation>Hold</translation>
+        <translation type="obsolete">Hold</translation>
     </message>
     <message>
         <source>Really delete this team?</source>
-        <translation>Vil du virkelig slette dette hold?</translation>
+        <translation type="obsolete">Vil du virkelig slette dette hold?</translation>
     </message>
     <message>
         <source>Schemes</source>
-        <translation>Spilsystemer</translation>
+        <translation type="obsolete">Spilsystemer</translation>
     </message>
     <message>
         <source>Can not delete default scheme &apos;%1&apos;!</source>
-        <translation>Kan ikke slette standardspilsystemet &apos;%1&apos;!</translation>
+        <translation type="obsolete">Kan ikke slette standardspilsystemet &apos;%1&apos;!</translation>
     </message>
     <message>
         <source>Really delete this game scheme?</source>
-        <translation>Vil du virkelig slette dette spilsystem?</translation>
+        <translation type="obsolete">Vil du virkelig slette dette spilsystem?</translation>
     </message>
     <message>
         <source>Can not delete default weapon set &apos;%1&apos;!</source>
-        <translation>Kan ikke slette standardvåbensættet &apos;%1&apos;!</translation>
+        <translation type="obsolete">Kan ikke slette standardvåbensættet &apos;%1&apos;!</translation>
+    </message>
+    <message>
+        <source>Teams - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the team &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default scheme &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a record from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Success</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All file associations have been set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please fill out all fields</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully posted the issue on hedgewars.googlecode.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error during authentication at google.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Main - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot create directory %1</source>
+        <translation type="unfinished">Kan ikke oprette mappe %1</translation>
+    </message>
+    <message>
+        <source>Failed to open data directory:
+%1
+
+Please check your installation!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>TCP - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start the server: %1.</source>
+        <translation type="unfinished">Ude af stand til at starte serveren: %1.</translation>
+    </message>
+    <message>
+        <source>Unable to run engine at </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error code: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while authenticating at google.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Login or password is incorrect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video upload - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while sending metadata to youtube.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Netgame - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a server from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter room name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Record Play - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select record from the list</source>
+        <translation type="unfinished">Vælg venligst en optagelse fra listen</translation>
+    </message>
+    <message>
+        <source>Cannot rename to </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete file </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Room Name - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select room from the list</source>
+        <translation type="unfinished">Vælg venligst et rum fra listen</translation>
+    </message>
+    <message>
+        <source>Room Name - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The game you are trying to join has started.
+Do you still want to join the room?</source>
+        <translation type="unfinished">Det spil du forsøge at tilslutte dig er allerede startet.
+Har du stadig lyst til at tilslutte dig rummet?</translation>
+    </message>
+    <message>
+        <source>Schemes - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Schemes - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the game scheme &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the video &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>Do you really want to remove %1 file(s)?</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Do you really want to cancel uploading %1?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File error</source>
+        <translation type="unfinished">Fejl i fil</translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for writing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for reading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot use the ammo &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>QObject</name>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>Cannot create directory %1</source>
-        <translation>Kan ikke oprette mappe %1</translation>
+        <translation type="obsolete">Kan ikke oprette mappe %1</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Nickname</source>
@@ -1950,36 +2528,127 @@
         <source>more</source>
         <translation>mere</translation>
     </message>
+    <message>
+        <source>More info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set default options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open videos directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload to YouTube</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QTableWidget</name>
     <message>
         <source>Room Name</source>
-        <translation>Navn på Rum</translation>
+        <translation type="obsolete">Navn på Rum</translation>
     </message>
     <message>
         <source>C</source>
-        <translation>C</translation>
+        <translation type="obsolete">C</translation>
     </message>
     <message>
         <source>T</source>
-        <translation>T</translation>
+        <translation type="obsolete">T</translation>
     </message>
     <message>
         <source>Owner</source>
-        <translation>Ejer</translation>
+        <translation type="obsolete">Ejer</translation>
     </message>
     <message>
         <source>Map</source>
-        <translation>Bane</translation>
+        <translation type="obsolete">Bane</translation>
     </message>
     <message>
         <source>Rules</source>
-        <translation>Regler</translation>
+        <translation type="obsolete">Regler</translation>
     </message>
     <message>
         <source>Weapons</source>
-        <translation>Våben</translation>
+        <translation type="obsolete">Våben</translation>
+    </message>
+</context>
+<context>
+    <name>RoomsListModel</name>
+    <message>
+        <source>In progress</source>
+        <translation type="unfinished">I gang</translation>
+    </message>
+    <message>
+        <source>Room Name</source>
+        <translation type="unfinished">Navn på Rum</translation>
+    </message>
+    <message>
+        <source>C</source>
+        <translation type="unfinished">C</translation>
+    </message>
+    <message>
+        <source>T</source>
+        <translation type="unfinished">T</translation>
+    </message>
+    <message>
+        <source>Owner</source>
+        <translation type="unfinished">Ejer</translation>
+    </message>
+    <message>
+        <source>Map</source>
+        <translation type="unfinished">Bane</translation>
+    </message>
+    <message>
+        <source>Rules</source>
+        <translation type="unfinished">Regler</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="unfinished">Våben</translation>
+    </message>
+    <message>
+        <source>Random Map</source>
+        <translation type="unfinished">Tilfældig Bane</translation>
+    </message>
+    <message>
+        <source>Random Maze</source>
+        <translation type="unfinished">Tilfældig Labyrint</translation>
+    </message>
+    <message>
+        <source>Hand-drawn</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -2013,15 +2682,15 @@
     <name>TCPBase</name>
     <message>
         <source>Error</source>
-        <translation>Fejl</translation>
+        <translation type="obsolete">Fejl</translation>
     </message>
     <message>
         <source>Unable to start the server: %1.</source>
-        <translation>Ude af stand til at starte serveren: %1.</translation>
+        <translation type="obsolete">Ude af stand til at starte serveren: %1.</translation>
     </message>
     <message>
         <source>Unable to run engine: %1 (</source>
-        <translation>Ude af stand til at starte spilmotoren: %1 (</translation>
+        <translation type="obsolete">Ude af stand til at starte spilmotoren: %1 (</translation>
     </message>
 </context>
 <context>
@@ -2068,7 +2737,7 @@
     </message>
     <message>
         <source>Add Mines</source>
-        <translation>Tilføj Miner</translation>
+        <translation type="obsolete">Tilføj Miner</translation>
     </message>
     <message>
         <source>Random Order</source>
@@ -2295,6 +2964,14 @@
         <source>slot 10</source>
         <translation>åbning 10</translation>
     </message>
+    <message>
+        <source>mute audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>record</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds (categories)</name>
@@ -2381,6 +3058,10 @@
         <source>Toggle labels above hedgehogs:</source>
         <translation>Slå mærkater over pindsvin fra og til:</translation>
     </message>
+    <message>
+        <source>Record video:</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds (keys)</name>
--- a/share/hedgewars/Data/Locale/hedgewars_de.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_de.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -346,23 +346,43 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished">Dauer: %1m %2s</translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished">Video: %1x%2, </translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished">%1 fps, </translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished">Audio: </translation>
+    </message>
+</context>
+<context>
     <name>LibavIteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
-        <translation>Dauer: %1m %2s</translation>
+        <translation type="obsolete">Dauer: %1m %2s</translation>
     </message>
     <message>
         <source>Video: %1x%2, </source>
-        <translation>Video: %1x%2, </translation>
+        <translation type="obsolete">Video: %1x%2, </translation>
     </message>
     <message>
         <source>%1 fps, </source>
-        <translation>%1 fps, </translation>
+        <translation type="obsolete">%1 fps, </translation>
     </message>
     <message>
         <source>Audio: </source>
-        <translation>Audio: </translation>
+        <translation type="obsolete">Audio: </translation>
     </message>
 </context>
 <context>
@@ -835,11 +855,11 @@
     </message>
     <message>
         <source>DLC</source>
-        <translation>DLC</translation>
+        <translation type="obsolete">DLC</translation>
     </message>
     <message>
         <source>Downloadable Content</source>
-        <translation>Herunterladbare Inhalte</translation>
+        <translation type="obsolete">Herunterladbare Inhalte</translation>
     </message>
 </context>
 <context>
@@ -2159,6 +2179,26 @@
         <source>Cancel uploading</source>
         <translation>Hochladen abbrechen</translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_el.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_el.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -2,11 +2,22 @@
 <!DOCTYPE TS>
 <TS version="2.0" language="el">
 <context>
+    <name>AbstractPage</name>
+    <message>
+        <source>Go back</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>AmmoSchemeModel</name>
     <message>
         <source>new</source>
         <translation type="unfinished">Νέο</translation>
     </message>
+    <message>
+        <source>copy of</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>FreqSpinBox</name>
@@ -30,11 +41,11 @@
     </message>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>Illegal ammo scheme</source>
-        <translation type="unfinished">Ασύμβατος σχεδιασμός όπλων</translation>
+        <translation type="obsolete">Ασύμβατος σχεδιασμός όπλων</translation>
     </message>
     <message>
         <source>Edit schemes</source>
@@ -42,45 +53,104 @@
     </message>
     <message>
         <source>When this option is enabled selecting a game scheme will auto-select a weapon (and viceversa)</source>
-        <translation type="unfinished">Όταν αυτή η επιλογη είναι ενεργοποιημένη, επιλέγοντας ένα σχεδιασμό παιχνιδιού θα επιλέγεται αυτομάτως ένα όπλο (και αντιστρόφως)</translation>
+        <translation type="obsolete">Όταν αυτή η επιλογη είναι ενεργοποιημένη, επιλέγοντας ένα σχεδιασμό παιχνιδιού θα επιλέγεται αυτομάτως ένα όπλο (και αντιστρόφως)</translation>
+    </message>
+    <message>
+        <source>Game Options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>When this option is enabled selecting a game scheme will auto-select a weapon</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWAskQuitDialog</name>
+    <message>
+        <source>Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>HWChatWidget</name>
     <message>
         <source>%1 *** %2 has been removed from your ignore list</source>
-        <translation type="unfinished">%1 *** %2 αφαιρέθηκε από τη &quot;μαύρη&quot; λίστα</translation>
+        <translation type="obsolete">%1 *** %2 αφαιρέθηκε από τη &quot;μαύρη&quot; λίστα</translation>
     </message>
     <message>
         <source>%1 *** %2 has been added to your ignore list</source>
-        <translation type="unfinished">%1 *** %2 προστέθηκε στη &quot;μαύρη&quot; λίστα</translation>
+        <translation type="obsolete">%1 *** %2 προστέθηκε στη &quot;μαύρη&quot; λίστα</translation>
     </message>
     <message>
         <source>%1 *** %2 has been removed from your friends list</source>
-        <translation type="unfinished">%1 *** %2 αφαιρέθηκε από τη λίστα φίλων</translation>
+        <translation type="obsolete">%1 *** %2 αφαιρέθηκε από τη λίστα φίλων</translation>
     </message>
     <message>
         <source>%1 *** %2 has been added to your friends list</source>
-        <translation type="unfinished">%1 *** %2 προστέθηκε στη λίστα φίλων</translation>
+        <translation type="obsolete">%1 *** %2 προστέθηκε στη λίστα φίλων</translation>
+    </message>
+    <message>
+        <source>%1 has been removed from your ignore list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 has been added to your ignore list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 has been removed from your friends list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 has been added to your friends list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Stylesheet imported from %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Couldn&apos;t read %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>StyleSheet discarded</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>StyleSheet saved to %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to save StyleSheet to %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 is not a valid command!</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
     <name>HWForm</name>
     <message>
         <source>new</source>
-        <translation type="unfinished">Νέο</translation>
+        <translation type="obsolete">Νέο</translation>
     </message>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation type="unfinished">Εντάξει</translation>
+        <translation type="obsolete">Εντάξει</translation>
     </message>
     <message>
         <source>Unable to start the server</source>
-        <translation type="unfinished">Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής</translation>
+        <translation type="obsolete">Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής</translation>
     </message>
     <message>
         <source>Cannot save record to file %1</source>
@@ -88,7 +158,7 @@
     </message>
     <message>
         <source>Please select record from the list above</source>
-        <translation type="unfinished">Παρακαλώ επέλεξε εγγραφή από την παραπάνω λίστα</translation>
+        <translation type="obsolete">Παρακαλώ επέλεξε εγγραφή από την παραπάνω λίστα</translation>
     </message>
     <message>
         <source>DefaultTeam</source>
@@ -106,17 +176,61 @@
         <translatorcomment>Τύπος Αρχείων</translatorcomment>
         <translation type="unfinished">Αρχείο Αποθήκευσης Hedgewars</translation>
     </message>
+    <message>
+        <source>Game aborted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Your nickname %1 is
+registered on Hedgewars.org
+Please provide your password below
+or pick another nickname in game config:</source>
+        <translation type="unfinished">Το ψευδώνυμο %1 είναι ήδη
+καταχωρημένο στο Hedgewars.org
+Παρακαλώ εισάγετε τον κωδικό σας
+ή επιλέξτε άλλο ψευδώνυμο από τις
+ρυθμίσεις του παιχνιδιού:</translation>
+    </message>
+    <message>
+        <source>No password supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation type="unfinished">Ψευδώνυμο</translation>
+    </message>
+    <message>
+        <source>Someone already uses your nickname %1 on the server.
+Please pick another nickname:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No nickname supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demo name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demo name:</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>HWGame</name>
     <message>
         <source>el.txt</source>
-        <translation>el.txt</translation>
+        <translation type="obsolete">el.txt</translation>
     </message>
     <message>
         <source>Cannot open demofile %1</source>
         <translation type="unfinished">Δεν μπορεί να φορτωθεί το αρχείο επιδείξεων %1</translation>
     </message>
+    <message>
+        <source>en.txt</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>HWMapContainer</name>
@@ -184,6 +298,14 @@
         <source>Large floating islands</source>
         <translation type="unfinished">Μεγάλα επιπλέοντα νησιά</translation>
     </message>
+    <message>
+        <source>Seed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>HWNetServersModel</name>
@@ -224,7 +346,7 @@
     </message>
     <message>
         <source>Password</source>
-        <translation type="unfinished">Κωδικός</translation>
+        <translation type="obsolete">Κωδικός</translation>
     </message>
     <message>
         <source>Your nickname %1 is
@@ -257,12 +379,42 @@
 registered on Hedgewars.org
 Please provide your password below
 or pick another nickname in game config:</source>
-        <translation type="unfinished">Το ψευδώνυμο %1 είναι ήδη
+        <translation type="obsolete">Το ψευδώνυμο %1 είναι ήδη
 καταχωρημένο στο Hedgewars.org
 Παρακαλώ εισάγετε τον κωδικό σας
 ή επιλέξτε άλλο ψευδώνυμο από τις
 ρυθμίσεις του παιχνιδιού:</translation>
     </message>
+    <message>
+        <source>User quit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remote host has closed connection</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The server is too old. Disconnecting now.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWPasswordDialog</name>
+    <message>
+        <source>Password</source>
+        <translation type="unfinished">Κωδικός</translation>
+    </message>
+</context>
+<context>
+    <name>HWUploadVideoDialog</name>
+    <message>
+        <source>Upload video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>KB</name>
@@ -272,6 +424,26 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageAdmin</name>
     <message>
         <source>Server message:</source>
@@ -318,6 +490,45 @@
     </message>
 </context>
 <context>
+    <name>PageDrawMap</name>
+    <message>
+        <source>Eraser</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Undo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation type="unfinished">Φόρτωση</translation>
+    </message>
+    <message>
+        <source>Save</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load drawn map</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Drawn Maps</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Save drawn map</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageEditTeam</name>
     <message>
         <source>General</source>
@@ -408,14 +619,28 @@
     </message>
 </context>
 <context>
+    <name>PageInGame</name>
+    <message>
+        <source>In game...</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageInfo</name>
+    <message>
+        <source>Open the snapshot folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageMain</name>
     <message>
         <source>Local Game (Play a game on a single computer)</source>
-        <translation type="unfinished">Τοπικό Παιχνίδι (Παίξιμο παιχνιδιού σε ένα υπολογιστή)</translation>
+        <translation type="obsolete">Τοπικό Παιχνίδι (Παίξιμο παιχνιδιού σε ένα υπολογιστή)</translation>
     </message>
     <message>
         <source>Network Game (Play a game across a network)</source>
-        <translation type="unfinished">Δικτυακό Παιχνίδι (Παίξιμο παιχνιδιού σε δίκτυο)</translation>
+        <translation type="obsolete">Δικτυακό Παιχνίδι (Παίξιμο παιχνιδιού σε δίκτυο)</translation>
     </message>
     <message>
         <source>Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they&apos;ll win or lose together.</source>
@@ -510,7 +735,7 @@
     <message>
         <source>The Windows version of Hedgewars supports Xfire. Make sure to add Hedgwars to its game list so your friends can see you playing.</source>
         <comment>Tips</comment>
-        <translation type="unfinished">Η έκδοση Hedgewars για Windows υποστηρίζει Xfire. Σιγουρευτείτε οτι προσθέσατε το Hedgewars στη λίστα παιχνιδιών του, ώστε οι φίλοι σας να μπορούν να σας δουν όταν εσείς παίζετε.</translation>
+        <translation type="obsolete">Η έκδοση Hedgewars για Windows υποστηρίζει Xfire. Σιγουρευτείτε οτι προσθέσατε το Hedgewars στη λίστα παιχνιδιών του, ώστε οι φίλοι σας να μπορούν να σας δουν όταν εσείς παίζετε.</translation>
     </message>
     <message>
         <source>You should never install Hedgewars on computers you don&apos;t own (school, university, work, etc.). Please ask the responsible person instead!</source>
@@ -580,7 +805,7 @@
     <message>
         <source>The Homing Bee can be tricky to use. It&apos;s turn radius depends on it&apos;s velocity, so try to not use full power.</source>
         <comment>Tips</comment>
-        <translation type="unfinished">Η Αυτοκαθοδηγούμενη Μέλισσα μπορεί να είναι δύσκολη στη χρήση. Η ακτίνα καμπυλότητάς της εξαρτάται από την ταχύτητά της, επομένως προσπαθήστε να μην χρησιμοποιείτε την πλήρη ισχύ.</translation>
+        <translation type="obsolete">Η Αυτοκαθοδηγούμενη Μέλισσα μπορεί να είναι δύσκολη στη χρήση. Η ακτίνα καμπυλότητάς της εξαρτάται από την ταχύτητά της, επομένως προσπαθήστε να μην χρησιμοποιείτε την πλήρη ισχύ.</translation>
     </message>
     <message>
         <source>Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.</source>
@@ -610,7 +835,7 @@
     <message>
         <source>Use the Incinerating Grenade to temporary keep hedgehogs from passing terrain such as tunnels or platforms.</source>
         <comment>Tips</comment>
-        <translation type="unfinished">Χρησιμοποιήστε την Καυστική Χειροβομβίδα για να εμποδίσετε προσωρινώς τους σκατζόχοιρους από το να διασχίσουν έδαφος, όπως σήραγγες ή εξέδρες.</translation>
+        <translation type="obsolete">Χρησιμοποιήστε την Καυστική Χειροβομβίδα για να εμποδίσετε προσωρινώς τους σκατζόχοιρους από το να διασχίσουν έδαφος, όπως σήραγγες ή εξέδρες.</translation>
     </message>
     <message>
         <source>Want to know who&apos;s behind the game? Click on the Hedgewars logo in the main menu to see the credits.</source>
@@ -662,6 +887,65 @@
         <comment>Tips</comment>
         <translation type="unfinished">Μπορείτε να βρείτε τα αρχεία ρυθμίσεων του Hedgewars στο &quot;.hedgewars&quot; στον προσωπικό σας φάκελο. Δημιουργήστε αντίγραφα ασφαλείας ή πάρτε τα αρχεία μαζί σας, αλλά μην τα επεξεργαστείτε χειροκίνητα.</translation>
     </message>
+    <message>
+        <source>Local Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game on a single computer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game across a network</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read about who is behind the Hedgewars Project</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloadable Content</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Access the user created content downloadable from our website</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Exit game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manage videos recorded from game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit game preferences</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageMultiplayer</name>
@@ -674,11 +958,11 @@
     <name>PageNet</name>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>Please select server from the list above</source>
-        <translation type="unfinished">Παρακαλώ επιλέξτε εξυπηρετητή από την παρακάτω λίστα</translation>
+        <translation type="obsolete">Παρακαλώ επιλέξτε εξυπηρετητή από την παρακάτω λίστα</translation>
     </message>
 </context>
 <context>
@@ -698,6 +982,14 @@
         <source>Official server</source>
         <translation type="unfinished">Επίσημος εξυπηρετητής</translation>
     </message>
+    <message>
+        <source>Join or host your own game server in a Local Area Network.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Join hundreds of players online!</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageOptions</name>
@@ -715,30 +1007,98 @@
     </message>
     <message>
         <source>New weapon scheme</source>
-        <translation type="unfinished">Νέος σχεδιασμός όπλων</translation>
+        <translation type="obsolete">Νέος σχεδιασμός όπλων</translation>
     </message>
     <message>
         <source>Edit weapon scheme</source>
-        <translation type="unfinished">Επεξεργασία σχεδιασμού όπλων</translation>
+        <translation type="obsolete">Επεξεργασία σχεδιασμού όπλων</translation>
     </message>
     <message>
         <source>Delete weapon scheme</source>
-        <translation type="unfinished">Διαγραφή σχεδιασμού όπλων</translation>
+        <translation type="obsolete">Διαγραφή σχεδιασμού όπλων</translation>
     </message>
     <message>
         <source>You can&apos;t edit teams from team selection. Go back to main menu to add, edit or delete teams.</source>
         <translation type="unfinished">Δεν μπορείτε να επεξεργαστείτε τις ομάδες από την επιλογή ομάδων. Πηγαίνετε πίσω στην κύρια σελίδα για να προσθέσετε, να επεξεργαστείτε ή να διαγράψετε ομάδες.</translation>
     </message>
+    <message>
+        <source>General</source>
+        <translation type="unfinished">Γενικά</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished">Για προχωρημένους</translation>
+    </message>
+    <message>
+        <source>New scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>New weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Reset to default colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy host</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy port</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>System proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Socks5 proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HTTP proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PagePlayDemo</name>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation type="unfinished">Εντάξει</translation>
+        <translation type="obsolete">Εντάξει</translation>
     </message>
     <message>
         <source>Rename dialog</source>
@@ -750,15 +1110,15 @@
     </message>
     <message>
         <source>Cannot rename to</source>
-        <translation type="unfinished">Δεν μπορεί να γίνει μετονομασία σε</translation>
+        <translation type="obsolete">Δεν μπορεί να γίνει μετονομασία σε</translation>
     </message>
     <message>
         <source>Cannot delete file</source>
-        <translation type="unfinished">Δεν μπορεί να διαγραφεί το αρχείο</translation>
+        <translation type="obsolete">Δεν μπορεί να διαγραφεί το αρχείο</translation>
     </message>
     <message>
         <source>Please select record from the list</source>
-        <translation type="unfinished">Παρακαλώ επιλέξτε εγγραφή από την λίστα</translation>
+        <translation type="obsolete">Παρακαλώ επιλέξτε εγγραφή από την λίστα</translation>
     </message>
 </context>
 <context>
@@ -773,15 +1133,15 @@
     </message>
     <message>
         <source>Refresh</source>
-        <translation type="unfinished">Ανανέωση</translation>
+        <translation type="obsolete">Ανανέωση</translation>
     </message>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation type="unfinished">Εντάξει</translation>
+        <translation type="obsolete">Εντάξει</translation>
     </message>
     <message>
         <source>Admin features</source>
@@ -794,64 +1154,64 @@
     <message>
         <source>This game is in lobby.
 You may join and start playing once the game starts.</source>
-        <translation type="unfinished">Αυτό το παιχνίδι είναι σε αναμονή.
+        <translation type="obsolete">Αυτό το παιχνίδι είναι σε αναμονή.
 Μπορείτε να συνδεθείτε και να παίξετε μόλις το παιχνίδι ξεκινήσει.</translation>
     </message>
     <message>
         <source>This game is in progress.
 You may join and spectate now but you&apos;ll have to wait for the game to end to start playing.</source>
-        <translation type="unfinished">Αυτό το παιχνίδι είναι σε εξέλιξη.
+        <translation type="obsolete">Αυτό το παιχνίδι είναι σε εξέλιξη.
 Μπορείτε να συνδεθείτε και να παρακολουθείτε την εξέλιξη αλλά θα πρέπει να περιμένετε να τελειώσει το παιχνίδι για να ξεκινήσετε να παίζετε.</translation>
     </message>
     <message>
         <source>%1 is the host. He may adjust settings and start the game.</source>
-        <translation type="unfinished">%1 είναι ο οικοδεσπότης. Μπορεί να προσαρμόζει τις ρυθμίσεις και να ξεκινά το παιχνίδι.</translation>
+        <translation type="obsolete">%1 είναι ο οικοδεσπότης. Μπορεί να προσαρμόζει τις ρυθμίσεις και να ξεκινά το παιχνίδι.</translation>
     </message>
     <message>
         <source>Random Map</source>
-        <translation type="unfinished">Τυχαίος χάρτης</translation>
+        <translation type="obsolete">Τυχαίος χάρτης</translation>
     </message>
     <message>
         <source>Games may be played on precreated or randomized maps.</source>
-        <translation type="unfinished">Τα παιχνίδια μπορούν να παίζονται σε προκατασκευασμένους ή τυχαιοποιημένους χάρτες.</translation>
+        <translation type="obsolete">Τα παιχνίδια μπορούν να παίζονται σε προκατασκευασμένους ή τυχαιοποιημένους χάρτες.</translation>
     </message>
     <message>
         <source>The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</source>
-        <translation type="unfinished">Ο σχεδιασμός του παιχνιδιού καθορίζει τις γενικές επιλογές και τις προτιμήσεις όπως τον Χρόνο του Γύρου, τον Ξαφνικό Θάνατο ή τον Βαμπιρισμό.</translation>
+        <translation type="obsolete">Ο σχεδιασμός του παιχνιδιού καθορίζει τις γενικές επιλογές και τις προτιμήσεις όπως τον Χρόνο του Γύρου, τον Ξαφνικό Θάνατο ή τον Βαμπιρισμό.</translation>
     </message>
     <message>
         <source>The Weapon Scheme defines available weapons and their ammunition count.</source>
-        <translation type="unfinished">Ο Σχεδιασμός των Όπλων καθορίζει τα διαθέσιμα όπλα και το ποσό των πυρομαχικών.</translation>
+        <translation type="obsolete">Ο Σχεδιασμός των Όπλων καθορίζει τα διαθέσιμα όπλα και το ποσό των πυρομαχικών.</translation>
     </message>
     <message numerus="yes">
         <source>There are %1 clients connected to this room.</source>
-        <translation type="unfinished">
+        <translation type="obsolete">
             <numerusform>Υπάρχει %1 χρήστης συνδεδεμένος σε αυτό το δωμάτιο.</numerusform>
             <numerusform>Υπάρχουν %1 χρήστες συνδεδεμένοι σε αυτό το δωμάτιο.</numerusform>
         </translation>
     </message>
     <message numerus="yes">
         <source>There are %1 teams participating in this room.</source>
-        <translation type="unfinished">
+        <translation type="obsolete">
             <numerusform>%1 ομάδα συμμετέχει σε αυτό το δωμάτιο.</numerusform>
             <numerusform>%1 ομάδες συμμετέχουν σε αυτό το δωμάτιο.</numerusform>
         </translation>
     </message>
     <message>
         <source>Please enter room name</source>
-        <translation type="unfinished">Εισάγετε το όνομα του δωματίου</translation>
+        <translation type="obsolete">Εισάγετε το όνομα του δωματίου</translation>
     </message>
     <message>
         <source>Please select room from the list</source>
-        <translation type="unfinished">Παρακαλώ επιλέξτε δωμάτιο από τη λίστα</translation>
+        <translation type="obsolete">Παρακαλώ επιλέξτε δωμάτιο από τη λίστα</translation>
     </message>
     <message>
         <source>Random Maze</source>
-        <translation type="unfinished">Τυχαίος Λαβύρινθος</translation>
+        <translation type="obsolete">Τυχαίος Λαβύρινθος</translation>
     </message>
     <message>
         <source>State:</source>
-        <translation type="unfinished">Κατάσταση :</translation>
+        <translation type="obsolete">Κατάσταση :</translation>
     </message>
     <message>
         <source>Rules:</source>
@@ -871,14 +1231,21 @@
     </message>
     <message>
         <source>Warning</source>
-        <translation type="unfinished">Προσοχή</translation>
+        <translation type="obsolete">Προσοχή</translation>
     </message>
     <message>
         <source>The game you are trying to join has started.
 Do you still want to join the room?</source>
-        <translation type="unfinished">Το παιχνίδι στο οποίο προσπαθείτε να συνδεθείτε έχει ήδη ξεκινήσει.
+        <translation type="obsolete">Το παιχνίδι στο οποίο προσπαθείτε να συνδεθείτε έχει ήδη ξεκινήσει.
 Θέλετε ακόμα να συνδεθείτε με το δωμάτιο;</translation>
     </message>
+    <message numerus="yes">
+        <source>%1 players online</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
 </context>
 <context>
     <name>PageScheme</name>
@@ -896,7 +1263,7 @@
     </message>
     <message>
         <source>Add an indestructable border around the terrain</source>
-        <translation type="unfinished">Προσθήκη ενός άφθαρτου συνόρου γύρω από την πίστα</translation>
+        <translation type="obsolete">Προσθήκη ενός άφθαρτου συνόρου γύρω από την πίστα</translation>
     </message>
     <message>
         <source>Lower gravity</source>
@@ -986,6 +1353,30 @@
         <source>Each hedgehog has its own ammo. It does not share with the team.</source>
         <translation type="unfinished">Κάθε σκατζόχοιρος έχει τα δικά του πυρομαχικά. Δεν τα μοιράζεται με την ομάδα.</translation>
     </message>
+    <message>
+        <source>Add an indestructible border around the terrain</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You will not have to worry about wind anymore.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Wind will affect almost everything.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Teams in each clan take successive turns sharing their turn time.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add an indestructible border along the bottom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageSelectWeapon</name>
@@ -997,32 +1388,141 @@
         <source>Delete</source>
         <translation type="unfinished">Διαγραφή</translation>
     </message>
+    <message>
+        <source>New</source>
+        <translation type="unfinished">Νέο</translation>
+    </message>
+    <message>
+        <source>Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageSinglePlayer</name>
     <message>
         <source>Simple Game (a quick game against the computer, settings are chosen for you)</source>
-        <translation type="unfinished">Απλό Παιχνίδι (ένα γρήγορο παιχνίδι εναντίον του υπολογιστή, οι ρυθμίσεις είναι προεπιλεγμένεs)</translation>
+        <translation type="obsolete">Απλό Παιχνίδι (ένα γρήγορο παιχνίδι εναντίον του υπολογιστή, οι ρυθμίσεις είναι προεπιλεγμένεs)</translation>
     </message>
     <message>
         <source>Multiplayer (play a hotseat game against your friends, or AI teams)</source>
-        <translation type="unfinished">Πολλοί Παίχτες (ένα παιχνίδι εναντίον των φίλων σας ή του υπολογιστή)</translation>
+        <translation type="obsolete">Πολλοί Παίχτες (ένα παιχνίδι εναντίον των φίλων σας ή του υπολογιστή)</translation>
     </message>
     <message>
         <source>Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT</source>
-        <translation type="unfinished">Εξάσκηση (Εξασκήστε τις δεξιότητές σας σε ένα εύρος εκπαιδευτικών αποστολών). ΣΕ ΕΞΕΛΙΞΗ</translation>
+        <translation type="obsolete">Εξάσκηση (Εξασκήστε τις δεξιότητές σας σε ένα εύρος εκπαιδευτικών αποστολών). ΣΕ ΕΞΕΛΙΞΗ</translation>
     </message>
     <message>
         <source>Demos (Watch recorded demos)</source>
-        <translation type="unfinished">Επιδείξεις (Παρακολουθήστε καταγεγραμμένες επιδείξεις)</translation>
+        <translation type="obsolete">Επιδείξεις (Παρακολουθήστε καταγεγραμμένες επιδείξεις)</translation>
     </message>
     <message>
         <source>Load (Load a previously saved game)</source>
-        <translation type="unfinished">Φόρτωση Σωσμένου Παιχνιδιού (Φορτώστε ένα σωσμένο παιχνίδι)</translation>
+        <translation type="obsolete">Φόρτωση Σωσμένου Παιχνιδιού (Φορτώστε ένα σωσμένο παιχνίδι)</translation>
     </message>
     <message>
         <source>Campaign Mode (...). IN DEVELOPMENT</source>
-        <translation type="unfinished">Εκστρατεία ΣΕ ΕΞΕΛΙΞΗ</translation>
+        <translation type="obsolete">Εκστρατεία ΣΕ ΕΞΕΛΙΞΗ</translation>
+    </message>
+    <message>
+        <source>Simple Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a quick game against the computer with random settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Multiplayer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a hotseat game against your friends, or AI teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Campaign Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Training Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Practice your skills in a range of training missions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Watch recorded demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation type="unfinished">Φόρτωση</translation>
+    </message>
+    <message>
+        <source>Load a previously saved game</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageTraining</name>
+    <message>
+        <source>Pick the mission or training to play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Start fighting</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No description available</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select a mission!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageVideos</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished">Όνομα</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>%1 bytes</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>(in progress...)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Date: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>encoding</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -1071,6 +1571,10 @@
         <source>Remove friend</source>
         <translation type="unfinished">Αφαίρεση φίλου</translation>
     </message>
+    <message>
+        <source>Update</source>
+        <translation type="unfinished">Αναβάθμιση</translation>
+    </message>
 </context>
 <context>
     <name>QCheckBox</name>
@@ -1126,6 +1630,26 @@
         <source>Frontend effects</source>
         <translation type="unfinished">Ενεργοποίηση εφε διεπαφής</translation>
     </message>
+    <message>
+        <source>Save password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Save account name and password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video is private</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Record audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Use game resolution</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QComboBox</name>
@@ -1173,6 +1697,74 @@
         <source>Default</source>
         <translation type="obsolete">Default</translation>
     </message>
+    <message>
+        <source>hand drawn map...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Cyan</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cyan/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Blue</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Blue/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Green</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Green/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Side-by-side</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Top-Bottom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Wiggle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Cyan grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cyan/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Blue grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Blue/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Green grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Green/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QGroupBox</name>
@@ -1194,7 +1786,7 @@
     </message>
     <message>
         <source>Weapons</source>
-        <translation type="unfinished">Όπλα</translation>
+        <translation type="obsolete">Όπλα</translation>
     </message>
     <message>
         <source>Audio/Graphic options</source>
@@ -1224,6 +1816,34 @@
         <source>Misc</source>
         <translation type="unfinished">Διάφορα</translation>
     </message>
+    <message>
+        <source>Schemes and Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Custom colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Miscellaneous</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video recording options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QLabel</name>
@@ -1241,7 +1861,7 @@
     </message>
     <message>
         <source>This program is distributed under the GNU General Public License</source>
-        <translation type="unfinished">Το πρόγραμμα αυτό διανέμεται κάτω από την GNU General Public License</translation>
+        <translation type="obsolete">Το πρόγραμμα αυτό διανέμεται κάτω από την GNU General Public License</translation>
     </message>
     <message>
         <source>Developers:</source>
@@ -1277,7 +1897,7 @@
     </message>
     <message>
         <source>Net nick</source>
-        <translation type="unfinished">Ψευδώνυμο</translation>
+        <translation type="obsolete">Ψευδώνυμο</translation>
     </message>
     <message>
         <source>Resolution</source>
@@ -1357,7 +1977,7 @@
     </message>
     <message>
         <source>Restart game to apply</source>
-        <translation type="unfinished">Επανεκκινήστε το παιχνίδι για εφαρμογή των αλλαγών</translation>
+        <translation type="obsolete">Επανεκκινήστε το παιχνίδι για εφαρμογή των αλλαγών</translation>
     </message>
     <message>
         <source>Explosives</source>
@@ -1393,7 +2013,93 @@
     </message>
     <message>
         <source>Bind schemes and weapons</source>
-        <translation type="unfinished">Σύζευξη σχεδιασμών και όπλων</translation>
+        <translation type="obsolete">Σύζευξη σχεδιασμών και όπλων</translation>
+    </message>
+    <message>
+        <source>There are videos that are currently being processed.
+Exiting now will abort them.
+Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please provide either the YouTube account name or the email address associated with the Google Account.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Account name (or email): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video title: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video description: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tags (comma separated): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Summary   </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation type="unfinished">Ψευδώνυμο</translation>
+    </message>
+    <message>
+        <source>Stereo rendering</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>% Rope Length</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>% Get Away Time</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Format</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Framerate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Bitrate (Kbps)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This program is distributed under the GNU General Public License v2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Style</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Scheme</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -1402,6 +2108,14 @@
         <source>unnamed</source>
         <translation type="unfinished">Ανώνυμο</translation>
     </message>
+    <message>
+        <source>hedgehog %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>anonymous</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QMainWindow</name>
@@ -1414,7 +2128,7 @@
     <name>QMessageBox</name>
     <message>
         <source>Network</source>
-        <translation type="unfinished">Δίκτυο</translation>
+        <translation type="obsolete">Δίκτυο</translation>
     </message>
     <message>
         <source>Connection to server is lost</source>
@@ -1428,13 +2142,13 @@
         <source>Failed to open data directory:
 %1
 Please check your installation</source>
-        <translation type="unfinished">Αποτυχία ανοίγματος φακέλου δεδομένων :
+        <translation type="obsolete">Αποτυχία ανοίγματος φακέλου δεδομένων :
  %1
 Παρακαλώ ελέγξτε την εγκατάστασή σας</translation>
     </message>
     <message>
         <source>Weapons</source>
-        <translation type="unfinished">Όπλα</translation>
+        <translation type="obsolete">Όπλα</translation>
     </message>
     <message>
         <source>Can not edit default weapon set</source>
@@ -1442,38 +2156,248 @@
     </message>
     <message>
         <source>Can not delete default weapon set</source>
-        <translation type="unfinished">Δεν μπορεί να διαγραφεί η βασική σειρά όπλων</translation>
+        <translation type="obsolete">Δεν μπορεί να διαγραφεί η βασική σειρά όπλων</translation>
     </message>
     <message>
         <source>Really delete this weapon set?</source>
-        <translation type="unfinished">Σίγουρα να διαγραφεί αυτή η σειρά όπλων ;</translation>
+        <translation type="obsolete">Σίγουρα να διαγραφεί αυτή η σειρά όπλων ;</translation>
     </message>
     <message>
         <source>Can not overwrite default weapon set &apos;%1&apos;!</source>
-        <translation type="unfinished">Δεν μπορεί να αντικατασταθεί η βασική σειρά όπλων &apos;%1&apos;!</translation>
+        <translation type="obsolete">Δεν μπορεί να αντικατασταθεί η βασική σειρά όπλων &apos;%1&apos;!</translation>
     </message>
     <message>
         <source>All file associations have been set.</source>
-        <translation type="unfinished">Όλες οι αντιστοιχίσεις αρχείων έχουν τεθεί.</translation>
+        <translation type="obsolete">Όλες οι αντιστοιχίσεις αρχείων έχουν τεθεί.</translation>
     </message>
     <message>
         <source>File association failed.</source>
         <translation type="unfinished">Η αντιστοίχιση του αρχείου απέτυχε.</translation>
     </message>
+    <message>
+        <source>Teams - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the team &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default scheme &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a record from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Success</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All file associations have been set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please fill out all fields</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully posted the issue on hedgewars.googlecode.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error during authentication at google.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Main - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot create directory %1</source>
+        <translation type="unfinished">Δεν μπορεί να δημιουργηθεί ο κατάλογος %1</translation>
+    </message>
+    <message>
+        <source>Failed to open data directory:
+%1
+
+Please check your installation!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>TCP - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start the server: %1.</source>
+        <translation type="unfinished">Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής : %1.</translation>
+    </message>
+    <message>
+        <source>Unable to run engine at </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error code: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while authenticating at google.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Login or password is incorrect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video upload - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while sending metadata to youtube.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Netgame - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a server from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter room name</source>
+        <translation type="unfinished">Εισάγετε το όνομα του δωματίου</translation>
+    </message>
+    <message>
+        <source>Record Play - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select record from the list</source>
+        <translation type="unfinished">Παρακαλώ επιλέξτε εγγραφή από την λίστα</translation>
+    </message>
+    <message>
+        <source>Cannot rename to </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete file </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Room Name - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select room from the list</source>
+        <translation type="unfinished">Παρακαλώ επιλέξτε δωμάτιο από τη λίστα</translation>
+    </message>
+    <message>
+        <source>Room Name - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The game you are trying to join has started.
+Do you still want to join the room?</source>
+        <translation type="unfinished">Το παιχνίδι στο οποίο προσπαθείτε να συνδεθείτε έχει ήδη ξεκινήσει.
+Θέλετε ακόμα να συνδεθείτε με το δωμάτιο;</translation>
+    </message>
+    <message>
+        <source>Schemes - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Schemes - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the game scheme &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the video &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>Do you really want to remove %1 file(s)?</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Do you really want to cancel uploading %1?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for writing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for reading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot use the ammo &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QObject</name>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>Cannot create directory %1</source>
-        <translation type="unfinished">Δεν μπορεί να δημιουργηθεί ο κατάλογος %1</translation>
+        <translation type="obsolete">Δεν μπορεί να δημιουργηθεί ο κατάλογος %1</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation type="unfinished">Εντάξει</translation>
+        <translation type="obsolete">Εντάξει</translation>
     </message>
     <message>
         <source>Nickname</source>
@@ -1554,20 +2478,103 @@
         <source>Associate file extensions</source>
         <translation type="unfinished">Αντιστοίχηση επεκτάσεων αρχείων</translation>
     </message>
+    <message>
+        <source>More info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set default options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open videos directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload to YouTube</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>more</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QTableWidget</name>
     <message>
         <source>Room Name</source>
+        <translation type="obsolete">Όνομα Δωματίου</translation>
+    </message>
+    <message>
+        <source>C</source>
+        <translation type="obsolete">C</translation>
+    </message>
+    <message>
+        <source>T</source>
+        <translation type="obsolete">T</translation>
+    </message>
+    <message>
+        <source>Owner</source>
+        <translation type="obsolete">Ιδιοκτήτης</translation>
+    </message>
+    <message>
+        <source>Map</source>
+        <translation type="obsolete">Χάρτης</translation>
+    </message>
+    <message>
+        <source>Rules</source>
+        <translation type="obsolete">Κανόνες</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="obsolete">Όπλα</translation>
+    </message>
+</context>
+<context>
+    <name>RoomsListModel</name>
+    <message>
+        <source>In progress</source>
+        <translation type="unfinished">Σε εξέλιξη</translation>
+    </message>
+    <message>
+        <source>Room Name</source>
         <translation type="unfinished">Όνομα Δωματίου</translation>
     </message>
     <message>
         <source>C</source>
-        <translation>C</translation>
+        <translation type="unfinished">C</translation>
     </message>
     <message>
         <source>T</source>
-        <translation>T</translation>
+        <translation type="unfinished">T</translation>
     </message>
     <message>
         <source>Owner</source>
@@ -1585,6 +2592,18 @@
         <source>Weapons</source>
         <translation type="unfinished">Όπλα</translation>
     </message>
+    <message>
+        <source>Random Map</source>
+        <translation type="unfinished">Τυχαίος χάρτης</translation>
+    </message>
+    <message>
+        <source>Random Maze</source>
+        <translation type="unfinished">Τυχαίος Λαβύρινθος</translation>
+    </message>
+    <message>
+        <source>Hand-drawn</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>SelWeaponWidget</name>
@@ -1604,20 +2623,28 @@
         <source>Delays</source>
         <translation type="unfinished">Καθυστερήσεις</translation>
     </message>
+    <message>
+        <source>new</source>
+        <translation type="unfinished">Νέο</translation>
+    </message>
+    <message>
+        <source>copy of</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>TCPBase</name>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Σφάλμα</translation>
+        <translation type="obsolete">Σφάλμα</translation>
     </message>
     <message>
         <source>Unable to start the server: %1.</source>
-        <translation type="unfinished">Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής : %1.</translation>
+        <translation type="obsolete">Δεν είναι δυνατόν να ξεκινήσει ο εξυπηρετητής : %1.</translation>
     </message>
     <message>
         <source>Unable to run engine: %1 (</source>
-        <translation type="unfinished">Δεν είναι δυνατόν να τρέξει η μηχανή : %1 (</translation>
+        <translation type="obsolete">Δεν είναι δυνατόν να τρέξει η μηχανή : %1 (</translation>
     </message>
 </context>
 <context>
@@ -1710,6 +2737,22 @@
         <source>Per Hedgehog Ammo</source>
         <translation type="unfinished">Πυρομαχικά ανά σκατζόχοιρο</translation>
     </message>
+    <message>
+        <source>Disable Wind</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>More Wind</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tag Team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add Bottom Border</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds</name>
@@ -1875,6 +2918,14 @@
         <source>slot 10</source>
         <translation type="unfinished">θέση 10</translation>
     </message>
+    <message>
+        <source>mute audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>record</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds (categories)</name>
@@ -1961,6 +3012,10 @@
         <source>Toggle labels above hedgehogs:</source>
         <translation type="unfinished">Εναλλάξτε τις επιγραφές πάνω από τους σκατζόχοιρους :</translation>
     </message>
+    <message>
+        <source>Record video:</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds (keys)</name>
--- a/share/hedgewars/Data/Locale/hedgewars_en.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_en.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -831,14 +831,6 @@
         <source>Control</source>
         <translation>Control</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2150,6 +2142,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_es.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_es.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -832,12 +832,8 @@
         <translation>Opciones</translation>
     </message>
     <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Downloadable Content</source>
-        <translation type="unfinished">Contenido adicional</translation>
+        <translation type="obsolete">Contenido adicional</translation>
     </message>
 </context>
 <context>
@@ -2152,6 +2148,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
@@ -2185,7 +2201,7 @@
     </message>
     <message>
         <source>Weapons</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">Set de armas</translation>
     </message>
     <message>
         <source>Random Map</source>
--- a/share/hedgewars/Data/Locale/hedgewars_fi.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_fi.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -831,14 +831,6 @@
         <source>Control</source>
         <translation>Säädöt</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2150,6 +2142,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_fr.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_fr.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -831,14 +831,6 @@
         <source>Control</source>
         <translation>Contrôles</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2149,6 +2141,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_gl.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_gl.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -1,1577 +1,3248 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.0" language="gl_ES">
-<context>
-    <name>AmmoSchemeModel</name>
-    <message>
-        <source>new</source>
-        <translation>novo</translation>
-    </message>
-</context>
-<context>
-    <name>FreqSpinBox</name>
-    <message>
-        <source>Never</source>
-        <translation>Nunca</translation>
-    </message>
-    <message numerus="yes">
-        <source>Every %1 turn</source>
-        <translation>
-            <numerusform>Cada rolda</numerusform>
-            <numerusform>Cada %1 roldas</numerusform>
-        </translation>
-    </message>
-</context>
-<context>
-    <name>GameCFGWidget</name>
-    <message>
-        <source>Edit weapons</source>
-        <translation>Editar os armamentos</translation>
-    </message>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>Illegal ammo scheme</source>
-        <translation>Non se permite ese armamento</translation>
-    </message>
-    <message>
-        <source>Edit schemes</source>
-        <translation>Editar os modos de xogo</translation>
-    </message>
-</context>
-<context>
-    <name>HWForm</name>
-    <message>
-        <source>new</source>
-        <translation>novo</translation>
-    </message>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>OK</source>
-        <translation>Aceptar</translation>
-    </message>
-    <message>
-        <source>Unable to start the server</source>
-        <translation>Non se puido iniciar o servidor</translation>
-    </message>
-    <message>
-        <source>Cannot save record to file %1</source>
-        <translation>Non se pode gardar a gravación no ficheiro %1</translation>
-    </message>
-    <message>
-        <source>Please select record from the list above</source>
-        <translation>Selecciona unha gravación da seguinte lista</translation>
-    </message>
-</context>
-<context>
-    <name>HWGame</name>
-    <message>
-        <source>Error reading training config file</source>
-        <translation>Houbo un erro ao ler o ficheiro de configuración do adestramento</translation>
-    </message>
-    <message>
-        <source>en.txt</source>
-        <translation>gl.txt</translation>
-    </message>
-    <message>
-        <source>Cannot open demofile %1</source>
-        <translation>Non se pode abrir a demostración %1</translation>
-    </message>
-</context>
-<context>
-    <name>HWMapContainer</name>
-    <message>
-        <source>Map</source>
-        <translation>Mapa</translation>
-    </message>
-    <message>
-        <source>Themes</source>
-        <translation>Temas visuais</translation>
-    </message>
-    <message>
-        <source>Filter</source>
-        <translation>Filtro</translation>
-    </message>
-    <message>
-        <source>All</source>
-        <translation>Todos</translation>
-    </message>
-    <message>
-        <source>Small</source>
-        <translation>Pequeno</translation>
-    </message>
-    <message>
-        <source>Medium</source>
-        <translation>Mediano</translation>
-    </message>
-    <message>
-        <source>Large</source>
-        <translation>Grande</translation>
-    </message>
-    <message>
-        <source>Cavern</source>
-        <translation>Caverna</translation>
-    </message>
-    <message>
-        <source>Wacky</source>
-        <translation>Absurdo</translation>
-    </message>
-</context>
-<context>
-    <name>HWNetServersModel</name>
-    <message>
-        <source>Title</source>
-        <translation>Nome</translation>
-    </message>
-    <message>
-        <source>IP</source>
-        <translation>IP</translation>
-    </message>
-    <message>
-        <source>Port</source>
-        <translation>Porto</translation>
-    </message>
-</context>
-<context>
-    <name>HWNewNet</name>
-    <message>
-        <source>The host was not found. Please check the host name and port settings.</source>
-        <translation>Non se atopou o anfitrión. Comproba o nome e mailo porto do anfitrión.</translation>
-    </message>
-    <message>
-        <source>Connection refused</source>
-        <translation>Rexeitouse a conexión</translation>
-    </message>
-    <message>
-        <source>Room destroyed</source>
-        <translation>Destruiuse a sala</translation>
-    </message>
-    <message>
-        <source>Quit reason: </source>
-        <translation>Motivo da expulsión:</translation>
-    </message>
-    <message>
-        <source>You got kicked</source>
-        <translation>Botáronte</translation>
-    </message>
-    <message>
-        <source>Password</source>
-        <translation>Contrasinal</translation>
-    </message>
-    <message>
-        <source>Your nickname %1 is
-registered on Hedgewars.org
-Please provide your password
-or pick another nickname:</source>
-        <translation>O teu alcume, «%1»
-está rexistrado en Hedgewars.org
-Introduce o contrasinal ou
-escolle outro alcume:</translation>
-    </message>
-    <message>
-        <source>%1 *** %2 has joined the room</source>
-        <translation>%1 *** %2 entrou na sala</translation>
-    </message>
-    <message>
-        <source>%1 *** %2 has joined</source>
-        <translation>%1 *** %2 uniuse</translation>
-    </message>
-    <message>
-        <source>%1 *** %2 has left (%3)</source>
-        <translation>%1 *** %2 marchou (%3)</translation>
-    </message>
-    <message>
-        <source>%1 *** %2 has left</source>
-        <translation>%1 *** %2 marchou</translation>
-    </message>
-</context>
-<context>
-    <name>KB</name>
-    <message>
-        <source>SDL_ttf returned error while rendering text, most propably it is related to the bug in freetype2. It&apos;s recommended to update your freetype lib.</source>
-        <translation>SDL_ttf devolveu un erro ao renderizar o texto, seguramente sexa por mor do erro de freetype2. Cómpre que actualices a túa biblioteca freetype.</translation>
-    </message>
-</context>
-<context>
-    <name>PageAdmin</name>
-    <message>
-        <source>Server message:</source>
-        <translation>Mensaxe do servidor:</translation>
-    </message>
-    <message>
-        <source>Set message</source>
-        <translation>Establecer a mensaxe</translation>
-    </message>
-    <message>
-        <source>Clear Accounts Cache</source>
-        <translation>Borrar a caché das contas</translation>
-    </message>
-</context>
-<context>
-    <name>PageConnecting</name>
-    <message>
-        <source>Connecting...</source>
-        <translation>Conectando...</translation>
-    </message>
-</context>
-<context>
-    <name>PageEditTeam</name>
-    <message>
-        <source>General</source>
-        <translation>Xeral</translation>
-    </message>
-    <message>
-        <source>Advanced</source>
-        <translation>Avanzado</translation>
-    </message>
-</context>
-<context>
-    <name>PageGameStats</name>
-    <message>
-        <source>&lt;p&gt;The best shot award was won by &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; pts.&lt;/p&gt;</source>
-        <translation>&lt;p&gt;O mellor tirador foi &lt;b&gt;%1&lt;/b&gt;, con &lt;b&gt;%2&lt;/b&gt; puntos.&lt;/p&gt;</translation>
-    </message>
-    <message numerus="yes">
-        <source>&lt;p&gt;The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.&lt;/p&gt;</source>
-        <translation>
-            <numerusform>&lt;p&gt;O mellor asasino é &lt;b&gt;%1&lt;/b&gt;, con &lt;b&gt;%2&lt;/b&gt; vítima nunha rolda.&lt;/p&gt;</numerusform>
-            <numerusform>&lt;p&gt;O mellor asasino é &lt;b&gt;%1&lt;/b&gt;, con &lt;b&gt;%2&lt;/b&gt; vítimas nunha rolda.&lt;/p&gt;</numerusform>
-        </translation>
-    </message>
-    <message numerus="yes">
-        <source>&lt;p&gt;A total of &lt;b&gt;%1&lt;/b&gt; hedgehog(s) were killed during this round.&lt;/p&gt;</source>
-        <translation>
-            <numerusform>&lt;p&gt;Nesta rolda morrereu &lt;b&gt;un&lt;/b&gt; ourizo.&lt;/p&gt;</numerusform>
-            <numerusform>&lt;p&gt;Nesta rolda morreron &lt;b&gt;%1&lt;/b&gt; ourizos.&lt;/p&gt;</numerusform>
-        </translation>
-    </message>
-</context>
-<context>
-    <name>PageMain</name>
-    <message>
-        <source>Local Game (Play a game on a single computer)</source>
-        <translation>Partida local (xoga unha partida nun só computador)</translation>
-    </message>
-    <message>
-        <source>Network Game (Play a game across a network)</source>
-        <translation>Partida na rede (xoga unha partida na rede)</translation>
-    </message>
-</context>
-<context>
-    <name>PageMultiplayer</name>
-    <message>
-        <source>Start</source>
-        <translation>Iniciar</translation>
-    </message>
-</context>
-<context>
-    <name>PageNet</name>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>Please select server from the list above</source>
-        <translation>Selecciona un servidor da seguinte lista</translation>
-    </message>
-</context>
-<context>
-    <name>PageNetGame</name>
-    <message>
-        <source>Control</source>
-        <translation>Control</translation>
-    </message>
-</context>
-<context>
-    <name>PageNetType</name>
-    <message>
-        <source>LAN game</source>
-        <translation>Partida na rede local</translation>
-    </message>
-    <message>
-        <source>Official server</source>
-        <translation>Servidor oficial</translation>
-    </message>
-</context>
-<context>
-    <name>PageOptions</name>
-    <message>
-        <source>New team</source>
-        <translation>Novo equipo</translation>
-    </message>
-    <message>
-        <source>Edit team</source>
-        <translation>Editar o equipo</translation>
-    </message>
-    <message>
-        <source>Weapons set</source>
-        <translation>Armamento</translation>
-    </message>
-    <message>
-        <source>Edit</source>
-        <translation>Editar</translation>
-    </message>
-</context>
-<context>
-    <name>PagePlayDemo</name>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>OK</source>
-        <translation>Aceptar</translation>
-    </message>
-    <message>
-        <source>Rename dialog</source>
-        <translation>Diálogo de cambio de nome</translation>
-    </message>
-    <message>
-        <source>Enter new file name:</source>
-        <translation>Introduce un novo nome para o ficheiro:</translation>
-    </message>
-    <message>
-        <source>Cannot rename to</source>
-        <translation>Non se pode cambiar o nome a</translation>
-    </message>
-    <message>
-        <source>Cannot delete file</source>
-        <translation>Non se pode borrar o ficheiro</translation>
-    </message>
-    <message>
-        <source>Please select record from the list</source>
-        <translation>Selecciona unha gravación da lista</translation>
-    </message>
-</context>
-<context>
-    <name>PageRoomsList</name>
-    <message>
-        <source>Create</source>
-        <translation>Crear</translation>
-    </message>
-    <message>
-        <source>Join</source>
-        <translation>Entrar</translation>
-    </message>
-    <message>
-        <source>Refresh</source>
-        <translation>Actualizar</translation>
-    </message>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>OK</source>
-        <translation>Aceptar</translation>
-    </message>
-    <message>
-        <source>Admin features</source>
-        <translation>Administración</translation>
-    </message>
-    <message>
-        <source>Room Name:</source>
-        <translation>Nome da sala:</translation>
-    </message>
-    <message>
-        <source>This game is in lobby.
-You may join and start playing once the game starts.</source>
-        <translation>Aínda non comezou a partida.
-Podes entrar e empezar a xogar cando comece.</translation>
-    </message>
-    <message>
-        <source>This game is in progress.
-You may join and spectate now but you&apos;ll have to wait for the game to end to start playing.</source>
-        <translation>A partida estase xogando.
-Poder entrar a ver, pero terás que agardar a que remate para xogar ti.</translation>
-    </message>
-    <message>
-        <source>%1 is the host. He may adjust settings and start the game.</source>
-        <translation>%1 é o anfitrión. Pode configurar e iniciar a partida.</translation>
-    </message>
-    <message>
-        <source>Random Map</source>
-        <translation>Mapa ao chou</translation>
-    </message>
-    <message>
-        <source>Games may be played on precreated or randomized maps.</source>
-        <translation>Pódese xogar en mapas elaborados ou mapas xerados ao chou.</translation>
-    </message>
-    <message>
-        <source>The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</source>
-        <translation>O modo de xogo establece as opcións xerais tales coma &quot;tempo por rolda&quot;, &quot;morte súbita&quot; ou &quot;vampirismo&quot;.</translation>
-    </message>
-    <message>
-        <source>The Weapon Scheme defines available weapons and their ammunition count.</source>
-        <translation>O armamento establece as armas dispoñibles e a cantidade de munición para cada unha.</translation>
-    </message>
-    <message numerus="yes">
-        <source>There are %1 clients connected to this room.</source>
-        <translation>
-            <numerusform>Hai un cliente conectado a esta sala.</numerusform>
-            <numerusform>Hai %1 clientes conectados a esta sala.</numerusform>
-        </translation>
-    </message>
-    <message numerus="yes">
-        <source>There are %1 teams participating in this room.</source>
-        <translation>
-            <numerusform>Hai un equipo participando nesta sala.</numerusform>
-            <numerusform>Hai %1 equipos participando nesta sala.</numerusform>
-        </translation>
-    </message>
-    <message>
-        <source>Please enter room name</source>
-        <translation>Introduce o nome da sala</translation>
-    </message>
-    <message>
-        <source>Please select room from the list</source>
-        <translation>Selecciona unha sala da lista</translation>
-    </message>
-</context>
-<context>
-    <name>PageScheme</name>
-    <message>
-        <source>Defend your fort and destroy the opponents, two team colours max!</source>
-        <translation>Defende o teu forte e elimina os inimigos, máximo dous bandos!</translation>
-    </message>
-    <message>
-        <source>Teams will start on opposite sides of the terrain, two team colours max!</source>
-        <translation>Os bandos comezarán en lados opostos da superficie, máximo dous bandos!</translation>
-    </message>
-    <message>
-        <source>Land can not be destroyed!</source>
-        <translation>Non se pode destruír o terreo!</translation>
-    </message>
-    <message>
-        <source>Add an indestructable border around the terrain</source>
-        <translation>Engade un bordo indestructible arredor do terreo</translation>
-    </message>
-    <message>
-        <source>Lower gravity</source>
-        <translation>Baixa gravidade</translation>
-    </message>
-    <message>
-        <source>Assisted aiming with laser sight</source>
-        <translation>Mira láser</translation>
-    </message>
-    <message>
-        <source>All hogs have a personal forcefield</source>
-        <translation>Todos os ourizos teñen un escudo protector</translation>
-    </message>
-    <message>
-        <source>Enable random mines</source>
-        <translation>Activar as minas esparexidas</translation>
-    </message>
-    <message>
-        <source>Gain 80% of the damage you do back in health</source>
-        <translation>Gañar o 80% do daño inflixido en vida</translation>
-    </message>
-    <message>
-        <source>Share your opponents pain, share their damage</source>
-        <translation>Acompañar aos inimigos no sentimento e no dano</translation>
-    </message>
-    <message>
-        <source>Your hogs are unable to move, put your artillery skills to the test</source>
-        <translation>Os ourizos non se poden mover, pon a probas a túa faceta de artilleiro</translation>
-    </message>
-    <message>
-        <source>Random</source>
-        <translation>Ao chou</translation>
-    </message>
-    <message>
-        <source>Seconds</source>
-        <translation>segundos</translation>
-    </message>
-    <message>
-        <source>New</source>
-        <translation>Novo</translation>
-    </message>
-    <message>
-        <source>Delete</source>
-        <translation>Borrar</translation>
-    </message>
-</context>
-<context>
-    <name>PageSelectWeapon</name>
-    <message>
-        <source>Default</source>
-        <translation>Por defecto</translation>
-    </message>
-    <message>
-        <source>Delete</source>
-        <translation>Borrar</translation>
-    </message>
-</context>
-<context>
-    <name>PageSinglePlayer</name>
-    <message>
-        <source>Simple Game (a quick game against the computer, settings are chosen for you)</source>
-        <translation>Partida simple (unha partida rápida xa configurada contra a intelixencia artificial)</translation>
-    </message>
-    <message>
-        <source>Multiplayer (play a hotseat game against your friends, or AI teams)</source>
-        <translation>Partida colectiva (xoga no teu computador contra os teus amigos ou contra a intelixencia artificial)</translation>
-    </message>
-    <message>
-        <source>Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT</source>
-        <translation>Adestramento (practica as túas habilidades nunha serie de misións de adestramento). EN DESENVOLVEMENTO</translation>
-    </message>
-    <message>
-        <source>Demos (Watch recorded demos)</source>
-        <translation>Demostracións (reproduce demostracións gravadas)</translation>
-    </message>
-    <message>
-        <source>Load (Load a previously saved game)</source>
-        <translation>Cargar (carga unha partida gardada)</translation>
-    </message>
-</context>
-<context>
-    <name>QAction</name>
-    <message>
-        <source>Kick</source>
-        <translation>Botar</translation>
-    </message>
-    <message>
-        <source>Info</source>
-        <translation>Información</translation>
-    </message>
-    <message>
-        <source>Start</source>
-        <translation>Iniciar</translation>
-    </message>
-    <message>
-        <source>Restrict Joins</source>
-        <translation>Restrinxir a entrada</translation>
-    </message>
-    <message>
-        <source>Restrict Team Additions</source>
-        <translation>Restrinxir o engadido de equipos</translation>
-    </message>
-    <message>
-        <source>Ban</source>
-        <translation>Expulsar</translation>
-    </message>
-</context>
-<context>
-    <name>QCheckBox</name>
-    <message>
-        <source>Check for updates at startup</source>
-        <translation>Comprobar se hai actualizacións ao iniciar</translation>
-    </message>
-    <message>
-        <source>Fullscreen</source>
-        <translation>Partidas a pantalla completa</translation>
-    </message>
-    <message>
-        <source>Frontend fullscreen</source>
-        <translation>Interface a pantalla completa</translation>
-    </message>
-    <message>
-        <source>Enable sound</source>
-        <translation>Activar os sons</translation>
-    </message>
-    <message>
-        <source>Enable music</source>
-        <translation>Activar a música</translation>
-    </message>
-    <message>
-        <source>Show FPS</source>
-        <translation>Amosar as FPS</translation>
-    </message>
-    <message>
-        <source>Alternative damage show</source>
-        <translation>Gráficos de dano alternativos</translation>
-    </message>
-    <message>
-        <source>Append date and time to record file name</source>
-        <translation>Engadir a data e maila hora ao nome dos ficheiros de gravación</translation>
-    </message>
-    <message>
-        <source>Frontend effects (requires restart)</source>
-        <translation>Efectos na interface (hai que reiniciar)</translation>
-    </message>
-    <message>
-        <source>Reduced quality</source>
-        <translation>Baixa calidade</translation>
-    </message>
-</context>
-<context>
-    <name>QComboBox</name>
-    <message>
-        <source>generated map...</source>
-        <translation>Mapa xerado...</translation>
-    </message>
-    <message>
-        <source>Human</source>
-        <translation>Xogador</translation>
-    </message>
-    <message>
-        <source>Level</source>
-        <translation>Nivel</translation>
-    </message>
-</context>
-<context>
-    <name>QGroupBox</name>
-    <message>
-        <source>Team Members</source>
-        <translation>Membros do equipo</translation>
-    </message>
-    <message>
-        <source>Team</source>
-        <translation>Equipo</translation>
-    </message>
-    <message>
-        <source>Fort</source>
-        <translation>Forte</translation>
-    </message>
-    <message>
-        <source>Key binds</source>
-        <translation>Controis</translation>
-    </message>
-    <message>
-        <source>Teams</source>
-        <translation>Equipos</translation>
-    </message>
-    <message>
-        <source>Weapons</source>
-        <translation>Armamento</translation>
-    </message>
-    <message>
-        <source>Audio/Graphic options</source>
-        <translation>Configuración audiovisual</translation>
-    </message>
-    <message>
-        <source>Net game</source>
-        <translation>Partida na rede</translation>
-    </message>
-    <message>
-        <source>Playing teams</source>
-        <translation>Equipos xogando</translation>
-    </message>
-    <message>
-        <source>Game Modifiers</source>
-        <translation>Modificadores da partida</translation>
-    </message>
-    <message>
-        <source>Basic Settings</source>
-        <translation>Configuración básica</translation>
-    </message>
-</context>
-<context>
-    <name>QLabel</name>
-    <message>
-        <source>Mines Time</source>
-        <translation>Temporizador das minas</translation>
-    </message>
-    <message>
-        <source>Mines</source>
-        <translation>Minas</translation>
-    </message>
-    <message>
-        <source>Version</source>
-        <translation>Versión</translation>
-    </message>
-    <message>
-        <source>This program is distributed under the GNU General Public License</source>
-        <translation>Esta aplicación distribúese baixo a GNU General Public License</translation>
-    </message>
-    <message>
-        <source>Developers:</source>
-        <translation>Desenvolvedores:</translation>
-    </message>
-    <message>
-        <source>Art:</source>
-        <translation>Gráficos:</translation>
-    </message>
-    <message>
-        <source>Sounds:</source>
-        <translation>Sons:</translation>
-    </message>
-    <message>
-        <source>Translations:</source>
-        <translation>Traducións:</translation>
-    </message>
-    <message>
-        <source>Special thanks:</source>
-        <translation>Un especial agradecemento a:</translation>
-    </message>
-    <message>
-        <source>Weapons</source>
-        <translation>Armamento</translation>
-    </message>
-    <message>
-        <source>Host:</source>
-        <translation>Anfitrión:</translation>
-    </message>
-    <message>
-        <source>Port:</source>
-        <translation>Porto:</translation>
-    </message>
-    <message>
-        <source>Net nick</source>
-        <translation>Alcume</translation>
-    </message>
-    <message>
-        <source>Resolution</source>
-        <translation>Resolución</translation>
-    </message>
-    <message>
-        <source>FPS limit</source>
-        <translation>Límite de FPS</translation>
-    </message>
-    <message>
-        <source>Server name:</source>
-        <translation>Nome do servidor:</translation>
-    </message>
-    <message>
-        <source>Server port:</source>
-        <translation>Porto do servidor:</translation>
-    </message>
-    <message>
-        <source>Initial sound volume</source>
-        <translation>Volume inicial</translation>
-    </message>
-    <message>
-        <source>Damage Modifier</source>
-        <translation>Modificador de dano</translation>
-    </message>
-    <message>
-        <source>Turn Time</source>
-        <translation>Tempo por rolda</translation>
-    </message>
-    <message>
-        <source>Initial Health</source>
-        <translation>Saúde inicial</translation>
-    </message>
-    <message>
-        <source>Sudden Death Timeout</source>
-        <translation>Conta atrás ata a morte súbita</translation>
-    </message>
-    <message>
-        <source>Scheme Name:</source>
-        <translation>Nome do modo:</translation>
-    </message>
-    <message>
-        <source>Crate Drops</source>
-        <translation>Caída de caixas</translation>
-    </message>
-    <message>
-        <source>Game scheme</source>
-        <translation>Modo de xogo</translation>
-    </message>
-</context>
-<context>
-    <name>QLineEdit</name>
-    <message>
-        <source>unnamed</source>
-        <translation>sen nome</translation>
-    </message>
-</context>
-<context>
-    <name>QMainWindow</name>
-    <message>
-        <source>Hedgewars %1</source>
-        <translation>Hedgewars %1</translation>
-    </message>
-</context>
-<context>
-    <name>QMessageBox</name>
-    <message>
-        <source>Network</source>
-        <translation>Rede</translation>
-    </message>
-    <message>
-        <source>Connection to server is lost</source>
-        <translation>Perdeuse a conexión co servidor</translation>
-    </message>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>Failed to open data directory:
-%1
-Please check your installation</source>
-        <translation>Non se puido abrir o directorio dos datos:
- %1
-Verifica a instalación</translation>
-    </message>
-    <message>
-        <source>Weapons</source>
-        <translation>Armamento</translation>
-    </message>
-    <message>
-        <source>Can not edit default weapon set</source>
-        <translation>Non se pode editar o armamento por defecto</translation>
-    </message>
-    <message>
-        <source>Can not delete default weapon set</source>
-        <translation>Non se pode borrar o armamento por defecto</translation>
-    </message>
-    <message>
-        <source>Really delete this weapon set?</source>
-        <translation>Seguro que queres borrar este armamento?</translation>
-    </message>
-</context>
-<context>
-    <name>QObject</name>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>Cannot create directory %1</source>
-        <translation>Non se puido crear o directorio %1</translation>
-    </message>
-    <message>
-        <source>OK</source>
-        <translation>Aceptar</translation>
-    </message>
-    <message>
-        <source>Nickname</source>
-        <translation>Alcume</translation>
-    </message>
-    <message>
-        <source>Please enter your nickname</source>
-        <translation>Introduce o teu alcume</translation>
-    </message>
-</context>
-<context>
-    <name>QPushButton</name>
-    <message>
-        <source>default</source>
-        <translation>por defecto</translation>
-    </message>
-    <message>
-        <source>OK</source>
-        <translation>Aceptar</translation>
-    </message>
-    <message>
-        <source>Cancel</source>
-        <translation>Cancelar</translation>
-    </message>
-    <message>
-        <source>Start server</source>
-        <translation>Iniciar un servidor</translation>
-    </message>
-    <message>
-        <source>Connect</source>
-        <translation>Conectar</translation>
-    </message>
-    <message>
-        <source>Update</source>
-        <translation>Actualizar</translation>
-    </message>
-    <message>
-        <source>Specify</source>
-        <translation>Especificar</translation>
-    </message>
-    <message>
-        <source>Start</source>
-        <translation>Iniciar</translation>
-    </message>
-    <message>
-        <source>Go!</source>
-        <translation>Dálle!</translation>
-    </message>
-    <message>
-        <source>Play demo</source>
-        <translation>Reproducir a demostración</translation>
-    </message>
-    <message>
-        <source>Rename</source>
-        <translation>Cambiar o nome</translation>
-    </message>
-    <message>
-        <source>Delete</source>
-        <translation>Borrar</translation>
-    </message>
-    <message>
-        <source>Load</source>
-        <translation>Cargar</translation>
-    </message>
-    <message>
-        <source>Setup</source>
-        <translation>Configuración</translation>
-    </message>
-    <message>
-        <source>Ready</source>
-        <translation>Preparado</translation>
-    </message>
-</context>
-<context>
-    <name>QTableWidget</name>
-    <message>
-        <source>Room Name</source>
-        <translation>Nome da sala</translation>
-    </message>
-    <message>
-        <source>C</source>
-        <translation>C</translation>
-    </message>
-    <message>
-        <source>T</source>
-        <translation>T</translation>
-    </message>
-    <message>
-        <source>Owner</source>
-        <translation>Dono</translation>
-    </message>
-    <message>
-        <source>Map</source>
-        <translation>Mapa</translation>
-    </message>
-    <message>
-        <source>Rules</source>
-        <translation>Regras</translation>
-    </message>
-    <message>
-        <source>Weapons</source>
-        <translation>Armamento</translation>
-    </message>
-</context>
-<context>
-    <name>SelWeaponWidget</name>
-    <message>
-        <source>Weapon set</source>
-        <translation>Armamento</translation>
-    </message>
-    <message>
-        <source>Probabilities</source>
-        <translation>Probabilidades</translation>
-    </message>
-</context>
-<context>
-    <name>TCPBase</name>
-    <message>
-        <source>Error</source>
-        <translation>Erro</translation>
-    </message>
-    <message>
-        <source>Unable to start the server: %1.</source>
-        <translation>Non se puido iniciar o servidor: %1.</translation>
-    </message>
-    <message>
-        <source>Unable to run engine: %1 (</source>
-        <translation>Non se puido executar o motor: %1 (</translation>
-    </message>
-</context>
-<context>
-    <name>ToggleButtonWidget</name>
-    <message>
-        <source>Vampirism</source>
-        <translation>Vampirismo</translation>
-    </message>
-    <message>
-        <source>Karma</source>
-        <translation>Karma</translation>
-    </message>
-    <message>
-        <source>Artillery</source>
-        <translation>Artillería</translation>
-    </message>
-    <message>
-        <source>Fort Mode</source>
-        <translation>Modo fortaleza</translation>
-    </message>
-    <message>
-        <source>Divide Teams</source>
-        <translation>Equipos divididos</translation>
-    </message>
-    <message>
-        <source>Solid Land</source>
-        <translation>Terreo indestructible</translation>
-    </message>
-    <message>
-        <source>Add Border</source>
-        <translation>Con bordos</translation>
-    </message>
-    <message>
-        <source>Low Gravity</source>
-        <translation>Baixa gravidade</translation>
-    </message>
-    <message>
-        <source>Laser Sight</source>
-        <translation>Mira láser</translation>
-    </message>
-    <message>
-        <source>Invulnerable</source>
-        <translation>Invulnerable</translation>
-    </message>
-    <message>
-        <source>Add Mines</source>
-        <translation>Engadir minas</translation>
-    </message>
-</context>
-<context>
-    <name>binds</name>
-    <message>
-        <source>up</source>
-        <translation>arriba</translation>
-    </message>
-    <message>
-        <source>left</source>
-        <translation>esquerda</translation>
-    </message>
-    <message>
-        <source>right</source>
-        <translation>dereita</translation>
-    </message>
-    <message>
-        <source>down</source>
-        <translation>abaixo</translation>
-    </message>
-    <message>
-        <source>attack</source>
-        <translation>atacar</translation>
-    </message>
-    <message>
-        <source>precise aim</source>
-        <translation>apuntar con precisión</translation>
-    </message>
-    <message>
-        <source>put</source>
-        <translation>poñer</translation>
-    </message>
-    <message>
-        <source>switch</source>
-        <translation>cambiar</translation>
-    </message>
-    <message>
-        <source>find hedgehog</source>
-        <translation>atopar ourizo</translation>
-    </message>
-    <message>
-        <source>ammo menu</source>
-        <translation>menú de armas</translation>
-    </message>
-    <message>
-        <source>slot 1</source>
-        <translation>1ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 2</source>
-        <translation>2ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 3</source>
-        <translation>3ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 4</source>
-        <translation>4ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 5</source>
-        <translation>5ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 6</source>
-        <translation>6ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 7</source>
-        <translation>7ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 8</source>
-        <translation>8ª ranura</translation>
-    </message>
-    <message>
-        <source>slot 9</source>
-        <translation>9ª ranura</translation>
-    </message>
-    <message>
-        <source>timer 1 sec</source>
-        <translation>temporizador a 1 segundo</translation>
-    </message>
-    <message>
-        <source>timer 2 sec</source>
-        <translation>temporizador a 2 segundos</translation>
-    </message>
-    <message>
-        <source>timer 3 sec</source>
-        <translation>temporizador a 3 segundos</translation>
-    </message>
-    <message>
-        <source>timer 4 sec</source>
-        <translation>temporizador a 4 segundos</translation>
-    </message>
-    <message>
-        <source>timer 5 sec</source>
-        <translation>temporizador a 5 segundos</translation>
-    </message>
-    <message>
-        <source>chat</source>
-        <translation>conversa</translation>
-    </message>
-    <message>
-        <source>chat history</source>
-        <translation>historial de conversa</translation>
-    </message>
-    <message>
-        <source>pause</source>
-        <translation>pausa</translation>
-    </message>
-    <message>
-        <source>confirmation</source>
-        <translation>confirmación</translation>
-    </message>
-    <message>
-        <source>volume down</source>
-        <translation>baixar o volume</translation>
-    </message>
-    <message>
-        <source>volume up</source>
-        <translation>subir o volume</translation>
-    </message>
-    <message>
-        <source>change mode</source>
-        <translation>cambiar o modo</translation>
-    </message>
-    <message>
-        <source>capture</source>
-        <translation>capturar</translation>
-    </message>
-    <message>
-        <source>hedgehogs
-info</source>
-        <translation>información
-dos ourizos</translation>
-    </message>
-    <message>
-        <source>quit</source>
-        <translation>saír</translation>
-    </message>
-    <message>
-        <source>zoom in</source>
-        <translation>achegar</translation>
-    </message>
-    <message>
-        <source>zoom out</source>
-        <translation>afastar</translation>
-    </message>
-    <message>
-        <source>reset zoom</source>
-        <translation>distancia inicial</translation>
-    </message>
-    <message>
-        <source>long jump</source>
-        <translation>salto cara adiante</translation>
-    </message>
-    <message>
-        <source>high jump</source>
-        <translation>salto cara arriba</translation>
-    </message>
-</context>
-<context>
-    <name>binds (categories)</name>
-    <message>
-        <source>Basic controls</source>
-        <translation>Controis básicos</translation>
-    </message>
-    <message>
-        <source>Weapon controls</source>
-        <translation>Controis das armas</translation>
-    </message>
-    <message>
-        <source>Camera and cursor controls</source>
-        <translation>Controis da cámara e mailo cursor</translation>
-    </message>
-    <message>
-        <source>Other</source>
-        <translation>Outros</translation>
-    </message>
-</context>
-<context>
-    <name>binds (descriptions)</name>
-    <message>
-        <source>Move your hogs and aim:</source>
-        <translation>Move os teus ourizos e apunta:</translation>
-    </message>
-    <message>
-        <source>Traverse gaps and obstacles by jumping:</source>
-        <translation>Supera os obstáculos saltando:</translation>
-    </message>
-    <message>
-        <source>Fire your selected weapon or trigger an utility item:</source>
-        <translation>Dispara a arma seleccionada ou activa unha ferramenta:</translation>
-    </message>
-    <message>
-        <source>Pick a weapon or a target location under the cursor:</source>
-        <translation>Recolle un arma ou a situación dun obxectivo onde o cursor:</translation>
-    </message>
-    <message>
-        <source>Switch your currently active hog (if possible):</source>
-        <translation>Cambia de ourizo (se se pode):</translation>
-    </message>
-    <message>
-        <source>Pick a weapon or utility item:</source>
-        <translation>Recolle unha arma ou ferramenta:</translation>
-    </message>
-    <message>
-        <source>Set the timer on bombs and timed weapons:</source>
-        <translation>Establece o temporizador para as armas que o teñan:</translation>
-    </message>
-    <message>
-        <source>Move the camera to the active hog:</source>
-        <translation>Move a cámara ao ourizo activo:</translation>
-    </message>
-    <message>
-        <source>Move the cursor or camera without using the mouse:</source>
-        <translation>Move o cursor ou a cámara sen usar o rato:</translation>
-    </message>
-    <message>
-        <source>Modify the camera&apos;s zoom level:</source>
-        <translation>Cambia a distancia da cámara:</translation>
-    </message>
-    <message>
-        <source>Talk to your team or all participants:</source>
-        <translation>Fala co teu equipo ou con todos:</translation>
-    </message>
-    <message>
-        <source>Pause, continue or leave your game:</source>
-        <translation>Pausa, continúa ou sal da túa partida:</translation>
-    </message>
-    <message>
-        <source>Modify the game&apos;s volume while playing:</source>
-        <translation>Cambia o volume do xogo durante unha partida:</translation>
-    </message>
-    <message>
-        <source>Toggle fullscreen mode:</source>
-        <translation>Cambiar a pantalla completa:</translation>
-    </message>
-    <message>
-        <source>Take a screenshot:</source>
-        <translation>Facer unha captura de pantalla:</translation>
-    </message>
-    <message>
-        <source>Toggle labels above hedgehogs:</source>
-        <translation>Cambiar as etiquetas sobre os ourizos:</translation>
-    </message>
-</context>
-<context>
-    <name>binds (keys)</name>
-    <message>
-        <source>Axis</source>
-        <translation>Eixo</translation>
-    </message>
-    <message>
-        <source>(Up)</source>
-        <translation>(Arriba)</translation>
-    </message>
-    <message>
-        <source>(Down)</source>
-        <translation>(Abaixo)</translation>
-    </message>
-    <message>
-        <source>Hat</source>
-        <translation>Sombreiro</translation>
-    </message>
-    <message>
-        <source>(Left)</source>
-        <translation>(Esquerda)</translation>
-    </message>
-    <message>
-        <source>(Right)</source>
-        <translation>(Dereita)</translation>
-    </message>
-    <message>
-        <source>Button</source>
-        <translation>Botón</translation>
-    </message>
-    <message>
-        <source>Keyboard</source>
-        <translation>Teclado</translation>
-    </message>
-    <message>
-        <source>Mouse: Left button</source>
-        <translation>Rato: botón esquerdo</translation>
-    </message>
-    <message>
-        <source>Mouse: Middle button</source>
-        <translation>Rato: botón central</translation>
-    </message>
-    <message>
-        <source>Mouse: Right button</source>
-        <translation>Rato: botón dereito</translation>
-    </message>
-    <message>
-        <source>Mouse: Wheel up</source>
-        <translation>Rato: roda cara arriba</translation>
-    </message>
-    <message>
-        <source>Mouse: Wheel down</source>
-        <translation>Rato: roda cara abaixo</translation>
-    </message>
-    <message>
-        <source>Backspace</source>
-        <translation>Retroceso</translation>
-    </message>
-    <message>
-        <source>Tab</source>
-        <translation>Tabulador</translation>
-    </message>
-    <message>
-        <source>Clear</source>
-        <translation>Borrado</translation>
-    </message>
-    <message>
-        <source>Return</source>
-        <translation>Retorno</translation>
-    </message>
-    <message>
-        <source>Pause</source>
-        <translation>Pausa</translation>
-    </message>
-    <message>
-        <source>Escape</source>
-        <translation>Escape</translation>
-    </message>
-    <message>
-        <source>Space</source>
-        <translation>Espazo</translation>
-    </message>
-    <message>
-        <source>Delete</source>
-        <translation>Borrar</translation>
-    </message>
-    <message>
-        <source>Numpad 0</source>
-        <translation>Teclado numérico: 0</translation>
-    </message>
-    <message>
-        <source>Numpad 1</source>
-        <translation>Teclado numérico: 1</translation>
-    </message>
-    <message>
-        <source>Numpad 2</source>
-        <translation>Teclado numérico: 2</translation>
-    </message>
-    <message>
-        <source>Numpad 3</source>
-        <translation>Teclado numérico: 3</translation>
-    </message>
-    <message>
-        <source>Numpad 4</source>
-        <translation>Teclado numérico: 4</translation>
-    </message>
-    <message>
-        <source>Numpad 5</source>
-        <translation>Teclado numérico: 5</translation>
-    </message>
-    <message>
-        <source>Numpad 6</source>
-        <translation>Teclado numérico: 6</translation>
-    </message>
-    <message>
-        <source>Numpad 7</source>
-        <translation>Teclado numérico: 7</translation>
-    </message>
-    <message>
-        <source>Numpad 8</source>
-        <translation>Teclado numérico: 8</translation>
-    </message>
-    <message>
-        <source>Numpad 9</source>
-        <translation>Teclado numérico: 9</translation>
-    </message>
-    <message>
-        <source>Numpad .</source>
-        <translation>Teclado numérico: .</translation>
-    </message>
-    <message>
-        <source>Numpad /</source>
-        <translation>Teclado numérico: /</translation>
-    </message>
-    <message>
-        <source>Numpad *</source>
-        <translation>Teclado numérico: *</translation>
-    </message>
-    <message>
-        <source>Numpad -</source>
-        <translation>Teclado numérico: -</translation>
-    </message>
-    <message>
-        <source>Numpad +</source>
-        <translation>Teclado numérico: +</translation>
-    </message>
-    <message>
-        <source>Enter</source>
-        <translation>Intro</translation>
-    </message>
-    <message>
-        <source>Equals</source>
-        <translation>Igual</translation>
-    </message>
-    <message>
-        <source>Up</source>
-        <translation>Arriba</translation>
-    </message>
-    <message>
-        <source>Down</source>
-        <translation>Abaixo</translation>
-    </message>
-    <message>
-        <source>Right</source>
-        <translation>Dereita</translation>
-    </message>
-    <message>
-        <source>Left</source>
-        <translation>Esquerda</translation>
-    </message>
-    <message>
-        <source>Insert</source>
-        <translation>Inserir</translation>
-    </message>
-    <message>
-        <source>Home</source>
-        <translation>Inicio</translation>
-    </message>
-    <message>
-        <source>End</source>
-        <translation>Fin</translation>
-    </message>
-    <message>
-        <source>Page up</source>
-        <translation>Re Páx</translation>
-    </message>
-    <message>
-        <source>Page down</source>
-        <translation>Av Páx</translation>
-    </message>
-    <message>
-        <source>Num lock</source>
-        <translation>Bloq Num</translation>
-    </message>
-    <message>
-        <source>Caps lock</source>
-        <translation>Bloq Maiús</translation>
-    </message>
-    <message>
-        <source>Scroll lock</source>
-        <translation>Bloq Despr</translation>
-    </message>
-    <message>
-        <source>Right shift</source>
-        <translation>Maiús dereito</translation>
-    </message>
-    <message>
-        <source>Left shift</source>
-        <translation>Maiús esquerdo</translation>
-    </message>
-    <message>
-        <source>Right ctrl</source>
-        <translation>Ctrl dereito</translation>
-    </message>
-    <message>
-        <source>Left ctrl</source>
-        <translation>Ctrl esquerdo</translation>
-    </message>
-    <message>
-        <source>Right alt</source>
-        <translation>Alt dereito</translation>
-    </message>
-    <message>
-        <source>Left alt</source>
-        <translation>Alt esquerdo</translation>
-    </message>
-    <message>
-        <source>Right meta</source>
-        <translation>Meta dereito</translation>
-    </message>
-    <message>
-        <source>Left meta</source>
-        <translation>Meta esquerdo</translation>
-    </message>
-    <message>
-        <source>A button</source>
-        <translation>Botón A</translation>
-    </message>
-    <message>
-        <source>B button</source>
-        <translation>Botón B</translation>
-    </message>
-    <message>
-        <source>X button</source>
-        <translation>Botón X</translation>
-    </message>
-    <message>
-        <source>Y button</source>
-        <translation>Botón Y</translation>
-    </message>
-    <message>
-        <source>LB button</source>
-        <translation>Botón LB</translation>
-    </message>
-    <message>
-        <source>RB button</source>
-        <translation>Botón RB</translation>
-    </message>
-    <message>
-        <source>Back button</source>
-        <translation>Botón de volver</translation>
-    </message>
-    <message>
-        <source>Start button</source>
-        <translation>Botón de inicio</translation>
-    </message>
-    <message>
-        <source>Left stick</source>
-        <translation>Stick esquerdo</translation>
-    </message>
-    <message>
-        <source>Right stick</source>
-        <translation>Stick dereito</translation>
-    </message>
-    <message>
-        <source>Left stick (Right)</source>
-        <translation>Stick esquerdo (Dereita)</translation>
-    </message>
-    <message>
-        <source>Left stick (Left)</source>
-        <translation>Stick esquerdo (Esquerda)</translation>
-    </message>
-    <message>
-        <source>Left stick (Down)</source>
-        <translation>Stick esquerdo (Abaixo)</translation>
-    </message>
-    <message>
-        <source>Left stick (Up)</source>
-        <translation>Stick esquerdo (Arriba)</translation>
-    </message>
-    <message>
-        <source>Left trigger</source>
-        <translation>Gatillo esquerdo</translation>
-    </message>
-    <message>
-        <source>Right trigger</source>
-        <translation>Gatillo dereito</translation>
-    </message>
-    <message>
-        <source>Right stick (Down)</source>
-        <translation>Stick dereito (Abaixo)</translation>
-    </message>
-    <message>
-        <source>Right stick (Up)</source>
-        <translation>Stick dereito (Arriba)</translation>
-    </message>
-    <message>
-        <source>Right stick (Right)</source>
-        <translation>Stick dereito (Dereita)</translation>
-    </message>
-    <message>
-        <source>Right stick (Left)</source>
-        <translation>Stick dereito (Esquerda)</translation>
-    </message>
-    <message>
-        <source>DPad</source>
-        <translation>Mando</translation>
-    </message>
-</context>
-</TS>
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="gl_ES">
+<context>
+    <name>AbstractPage</name>
+    <message>
+        <source>Go back</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AmmoSchemeModel</name>
+    <message>
+        <source>new</source>
+        <translation>novo</translation>
+    </message>
+    <message>
+        <source>copy of</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FreqSpinBox</name>
+    <message>
+        <source>Never</source>
+        <translation>Nunca</translation>
+    </message>
+    <message numerus="yes">
+        <source>Every %1 turn</source>
+        <translation>
+            <numerusform>Cada rolda</numerusform>
+            <numerusform>Cada %1 roldas</numerusform>
+        </translation>
+    </message>
+</context>
+<context>
+    <name>GameCFGWidget</name>
+    <message>
+        <source>Edit weapons</source>
+        <translation>Editar os armamentos</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>Illegal ammo scheme</source>
+        <translation type="obsolete">Non se permite ese armamento</translation>
+    </message>
+    <message>
+        <source>Edit schemes</source>
+        <translation>Editar os modos de xogo</translation>
+    </message>
+    <message>
+        <source>Game Options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>When this option is enabled selecting a game scheme will auto-select a weapon</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWAskQuitDialog</name>
+    <message>
+        <source>Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWChatWidget</name>
+    <message>
+        <source>%1 has been removed from your ignore list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 has been added to your ignore list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 has been removed from your friends list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 has been added to your friends list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Stylesheet imported from %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Couldn&apos;t read %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>StyleSheet discarded</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>StyleSheet saved to %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Failed to save StyleSheet to %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 is not a valid command!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWForm</name>
+    <message>
+        <source>new</source>
+        <translation type="obsolete">novo</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="obsolete">Aceptar</translation>
+    </message>
+    <message>
+        <source>Unable to start the server</source>
+        <translation type="obsolete">Non se puido iniciar o servidor</translation>
+    </message>
+    <message>
+        <source>Cannot save record to file %1</source>
+        <translation>Non se pode gardar a gravación no ficheiro %1</translation>
+    </message>
+    <message>
+        <source>Please select record from the list above</source>
+        <translation type="obsolete">Selecciona unha gravación da seguinte lista</translation>
+    </message>
+    <message>
+        <source>DefaultTeam</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Game aborted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Your nickname %1 is
+registered on Hedgewars.org
+Please provide your password below
+or pick another nickname in game config:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No password supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation type="unfinished">Alcume</translation>
+    </message>
+    <message>
+        <source>Someone already uses your nickname %1 on the server.
+Please pick another nickname:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No nickname supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars Demo File</source>
+        <comment>File Types</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars Save File</source>
+        <comment>File Types</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demo name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demo name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWGame</name>
+    <message>
+        <source>Error reading training config file</source>
+        <translation type="obsolete">Houbo un erro ao ler o ficheiro de configuración do adestramento</translation>
+    </message>
+    <message>
+        <source>en.txt</source>
+        <translation>gl.txt</translation>
+    </message>
+    <message>
+        <source>Cannot open demofile %1</source>
+        <translation>Non se pode abrir a demostración %1</translation>
+    </message>
+</context>
+<context>
+    <name>HWMapContainer</name>
+    <message>
+        <source>Map</source>
+        <translation>Mapa</translation>
+    </message>
+    <message>
+        <source>Themes</source>
+        <translation>Temas visuais</translation>
+    </message>
+    <message>
+        <source>Filter</source>
+        <translation>Filtro</translation>
+    </message>
+    <message>
+        <source>All</source>
+        <translation>Todos</translation>
+    </message>
+    <message>
+        <source>Small</source>
+        <translation>Pequeno</translation>
+    </message>
+    <message>
+        <source>Medium</source>
+        <translation>Mediano</translation>
+    </message>
+    <message>
+        <source>Large</source>
+        <translation>Grande</translation>
+    </message>
+    <message>
+        <source>Cavern</source>
+        <translation>Caverna</translation>
+    </message>
+    <message>
+        <source>Wacky</source>
+        <translation>Absurdo</translation>
+    </message>
+    <message>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Small tunnels</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Medium tunnels</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Large tunnels</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Small floating islands</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Medium floating islands</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Large floating islands</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Seed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWNetServersModel</name>
+    <message>
+        <source>Title</source>
+        <translation>Nome</translation>
+    </message>
+    <message>
+        <source>IP</source>
+        <translation>IP</translation>
+    </message>
+    <message>
+        <source>Port</source>
+        <translation>Porto</translation>
+    </message>
+</context>
+<context>
+    <name>HWNewNet</name>
+    <message>
+        <source>The host was not found. Please check the host name and port settings.</source>
+        <translation>Non se atopou o anfitrión. Comproba o nome e mailo porto do anfitrión.</translation>
+    </message>
+    <message>
+        <source>Connection refused</source>
+        <translation>Rexeitouse a conexión</translation>
+    </message>
+    <message>
+        <source>Room destroyed</source>
+        <translation>Destruiuse a sala</translation>
+    </message>
+    <message>
+        <source>Quit reason: </source>
+        <translation>Motivo da expulsión:</translation>
+    </message>
+    <message>
+        <source>You got kicked</source>
+        <translation>Botáronte</translation>
+    </message>
+    <message>
+        <source>Password</source>
+        <translation type="obsolete">Contrasinal</translation>
+    </message>
+    <message>
+        <source>Your nickname %1 is
+registered on Hedgewars.org
+Please provide your password
+or pick another nickname:</source>
+        <translation type="obsolete">O teu alcume, «%1»
+está rexistrado en Hedgewars.org
+Introduce o contrasinal ou
+escolle outro alcume:</translation>
+    </message>
+    <message>
+        <source>%1 *** %2 has joined the room</source>
+        <translation>%1 *** %2 entrou na sala</translation>
+    </message>
+    <message>
+        <source>%1 *** %2 has joined</source>
+        <translation>%1 *** %2 uniuse</translation>
+    </message>
+    <message>
+        <source>%1 *** %2 has left (%3)</source>
+        <translation>%1 *** %2 marchou (%3)</translation>
+    </message>
+    <message>
+        <source>%1 *** %2 has left</source>
+        <translation>%1 *** %2 marchou</translation>
+    </message>
+    <message>
+        <source>User quit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remote host has closed connection</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The server is too old. Disconnecting now.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWPasswordDialog</name>
+    <message>
+        <source>Password</source>
+        <translation type="unfinished">Contrasinal</translation>
+    </message>
+</context>
+<context>
+    <name>HWUploadVideoDialog</name>
+    <message>
+        <source>Upload video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>KB</name>
+    <message>
+        <source>SDL_ttf returned error while rendering text, most propably it is related to the bug in freetype2. It&apos;s recommended to update your freetype lib.</source>
+        <translation>SDL_ttf devolveu un erro ao renderizar o texto, seguramente sexa por mor do erro de freetype2. Cómpre que actualices a túa biblioteca freetype.</translation>
+    </message>
+</context>
+<context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageAdmin</name>
+    <message>
+        <source>Server message:</source>
+        <translation type="obsolete">Mensaxe do servidor:</translation>
+    </message>
+    <message>
+        <source>Set message</source>
+        <translation type="obsolete">Establecer a mensaxe</translation>
+    </message>
+    <message>
+        <source>Clear Accounts Cache</source>
+        <translation>Borrar a caché das contas</translation>
+    </message>
+    <message>
+        <source>Fetch data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server message for latest version:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Server message for previous versions:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Latest version protocol number:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>MOTD preview:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set data</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageConnecting</name>
+    <message>
+        <source>Connecting...</source>
+        <translation>Conectando...</translation>
+    </message>
+</context>
+<context>
+    <name>PageDrawMap</name>
+    <message>
+        <source>Eraser</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Undo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished">Borrado</translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation type="unfinished">Cargar</translation>
+    </message>
+    <message>
+        <source>Save</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load drawn map</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Drawn Maps</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Save drawn map</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageEditTeam</name>
+    <message>
+        <source>General</source>
+        <translation>Xeral</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation>Avanzado</translation>
+    </message>
+</context>
+<context>
+    <name>PageGameStats</name>
+    <message>
+        <source>&lt;p&gt;The best shot award was won by &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; pts.&lt;/p&gt;</source>
+        <translation type="obsolete">&lt;p&gt;O mellor tirador foi &lt;b&gt;%1&lt;/b&gt;, con &lt;b&gt;%2&lt;/b&gt; puntos.&lt;/p&gt;</translation>
+    </message>
+    <message numerus="yes">
+        <source>&lt;p&gt;The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.&lt;/p&gt;</source>
+        <translation type="obsolete">
+            <numerusform>&lt;p&gt;O mellor asasino é &lt;b&gt;%1&lt;/b&gt;, con &lt;b&gt;%2&lt;/b&gt; vítima nunha rolda.&lt;/p&gt;</numerusform>
+            <numerusform>&lt;p&gt;O mellor asasino é &lt;b&gt;%1&lt;/b&gt;, con &lt;b&gt;%2&lt;/b&gt; vítimas nunha rolda.&lt;/p&gt;</numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>&lt;p&gt;A total of &lt;b&gt;%1&lt;/b&gt; hedgehog(s) were killed during this round.&lt;/p&gt;</source>
+        <translation type="obsolete">
+            <numerusform>&lt;p&gt;Nesta rolda morrereu &lt;b&gt;un&lt;/b&gt; ourizo.&lt;/p&gt;</numerusform>
+            <numerusform>&lt;p&gt;Nesta rolda morreron &lt;b&gt;%1&lt;/b&gt; ourizos.&lt;/p&gt;</numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Details</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Health graph</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Ranking</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The best shot award was won by &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; pts.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>A total of &lt;b&gt;%1&lt;/b&gt; hedgehog(s) were killed during this round.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>(%1 kill)</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>&lt;b&gt;%1&lt;/b&gt; thought it&apos;s good to shoot his own hedgehogs with &lt;b&gt;%2&lt;/b&gt; pts.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>&lt;b&gt;%1&lt;/b&gt; killed &lt;b&gt;%2&lt;/b&gt; of his own hedgehogs.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>&lt;b&gt;%1&lt;/b&gt; was scared and skipped turn &lt;b&gt;%2&lt;/b&gt; times.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+</context>
+<context>
+    <name>PageInGame</name>
+    <message>
+        <source>In game...</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageInfo</name>
+    <message>
+        <source>Open the snapshot folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageMain</name>
+    <message>
+        <source>Local Game (Play a game on a single computer)</source>
+        <translation type="obsolete">Partida local (xoga unha partida nun só computador)</translation>
+    </message>
+    <message>
+        <source>Network Game (Play a game across a network)</source>
+        <translation type="obsolete">Partida na rede (xoga unha partida na rede)</translation>
+    </message>
+    <message>
+        <source>Local Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game on a single computer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game across a network</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read about who is behind the Hedgewars Project</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Downloadable Content</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Access the user created content downloadable from our website</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Exit game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manage videos recorded from game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit game preferences</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they&apos;ll win or lose together.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>If you&apos;re unsure what to do and don&apos;t want to waste ammo, skip one round. But don&apos;t let too much time pass as there will be Sudden Death!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Want to save ropes? Release the rope in mid air and then shoot again. As long as you don&apos;t touch the ground you&apos;ll reuse your rope without wasting ammo!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>If you&apos;d like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You&apos;re bored of default gameplay? Try one of the missions - they&apos;ll offer different gameplay depending on the one you picked.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>By default the game will always record the last game played as a demo. Select &apos;Local Game&apos; and pick the &apos;Demos&apos; button on the lower right corner to play or manage them.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. If you&apos;ve got problems, ask on our forums but please don&apos;t expect 24/7 support!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Always remember you&apos;re able to set up your own games in local and network/online play. You&apos;re not restricted to the &apos;Simple Game&apos; option.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Connect one or more gamepads before starting the game to be able to assign their controls to your teams.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Create an account on %1 to keep others from using your most favourite nickname while playing on the official server.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>While playing you should give yourself a short break at least once an hour.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>If your graphics card isn&apos;t able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>If your graphics card isn&apos;t able to provide hardware accelerated OpenGL, try to update the associated drivers.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>We&apos;re open to suggestions and constructive feedback. If you don&apos;t like something or got a great idea, let us know!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Especially while playing online be polite and always remember there might be some minors playing with or against you as well!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Special game modes such as &apos;Vampirism&apos; or &apos;Karma&apos; allow you to develop completely new tactics. Try them in a custom game!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You should never install Hedgewars on computers you don&apos;t own (school, university, work, etc.). Please ask the responsible person instead!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars can be perfect for short games during breaks. Just ensure you don&apos;t add too many hedgehogs or use an huge map. Reducing time and health might help as well.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No hedgehogs were harmed in making this game.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Some weapons require special strategies or just lots of training, so don&apos;t give up on a particular tool if you miss an enemy once.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Most weapons won&apos;t work once they touch the water. The Homing Bee as well as the Cake are exceptions to this.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Piano Strike is the most damaging air strike. You&apos;ll lose the hedgehog performing it, so there&apos;s a huge downside as well.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>If you&apos;re stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Cake&apos;s maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The Flame Thrower is a weapon but it can be used for tunnel digging as well.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Want to know who&apos;s behind the game? Click on the Hedgewars logo in the main menu to see the credits.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Like Hedgewars? Become a fan on %1 or follow us on %2!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Feel free to draw your own graves, hats, flags or even maps and themes! But note that you&apos;ll have to share them somewhere to use them online.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Keep your video card drivers up to date to avoid issues playing the game.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You&apos;re able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You can find your Hedgewars configuration files under &quot;My Documents\Hedgewars&quot;. Create backups or take the files with you, but don&apos;t edit them by hand.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You can find your Hedgewars configuration files under &quot;Library/Application Support/Hedgewars&quot; in your home directory. Create backups or take the files with you, but don&apos;t edit them by hand.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You can find your Hedgewars configuration files under &quot;.hedgewars&quot; in your home directory. Create backups or take the files with you, but don&apos;t edit them by hand.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageMultiplayer</name>
+    <message>
+        <source>Start</source>
+        <translation>Iniciar</translation>
+    </message>
+</context>
+<context>
+    <name>PageNet</name>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>Please select server from the list above</source>
+        <translation type="obsolete">Selecciona un servidor da seguinte lista</translation>
+    </message>
+</context>
+<context>
+    <name>PageNetGame</name>
+    <message>
+        <source>Control</source>
+        <translation>Control</translation>
+    </message>
+</context>
+<context>
+    <name>PageNetType</name>
+    <message>
+        <source>LAN game</source>
+        <translation>Partida na rede local</translation>
+    </message>
+    <message>
+        <source>Official server</source>
+        <translation>Servidor oficial</translation>
+    </message>
+    <message>
+        <source>Join or host your own game server in a Local Area Network.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Join hundreds of players online!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageOptions</name>
+    <message>
+        <source>New team</source>
+        <translation>Novo equipo</translation>
+    </message>
+    <message>
+        <source>Edit team</source>
+        <translation>Editar o equipo</translation>
+    </message>
+    <message>
+        <source>Weapons set</source>
+        <translation type="obsolete">Armamento</translation>
+    </message>
+    <message>
+        <source>Edit</source>
+        <translation type="obsolete">Editar</translation>
+    </message>
+    <message>
+        <source>General</source>
+        <translation type="unfinished">Xeral</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished">Avanzado</translation>
+    </message>
+    <message>
+        <source>Delete team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You can&apos;t edit teams from team selection. Go back to main menu to add, edit or delete teams.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>New scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>New weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Reset to default colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy host</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy port</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>System proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Socks5 proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HTTP proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PagePlayDemo</name>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="obsolete">Aceptar</translation>
+    </message>
+    <message>
+        <source>Rename dialog</source>
+        <translation>Diálogo de cambio de nome</translation>
+    </message>
+    <message>
+        <source>Enter new file name:</source>
+        <translation>Introduce un novo nome para o ficheiro:</translation>
+    </message>
+    <message>
+        <source>Cannot rename to</source>
+        <translation type="obsolete">Non se pode cambiar o nome a</translation>
+    </message>
+    <message>
+        <source>Cannot delete file</source>
+        <translation type="obsolete">Non se pode borrar o ficheiro</translation>
+    </message>
+    <message>
+        <source>Please select record from the list</source>
+        <translation type="obsolete">Selecciona unha gravación da lista</translation>
+    </message>
+</context>
+<context>
+    <name>PageRoomsList</name>
+    <message>
+        <source>Create</source>
+        <translation>Crear</translation>
+    </message>
+    <message>
+        <source>Join</source>
+        <translation>Entrar</translation>
+    </message>
+    <message>
+        <source>Refresh</source>
+        <translation type="obsolete">Actualizar</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="obsolete">Aceptar</translation>
+    </message>
+    <message>
+        <source>Admin features</source>
+        <translation>Administración</translation>
+    </message>
+    <message>
+        <source>Room Name:</source>
+        <translation>Nome da sala:</translation>
+    </message>
+    <message>
+        <source>This game is in lobby.
+You may join and start playing once the game starts.</source>
+        <translation type="obsolete">Aínda non comezou a partida.
+Podes entrar e empezar a xogar cando comece.</translation>
+    </message>
+    <message>
+        <source>This game is in progress.
+You may join and spectate now but you&apos;ll have to wait for the game to end to start playing.</source>
+        <translation type="obsolete">A partida estase xogando.
+Poder entrar a ver, pero terás que agardar a que remate para xogar ti.</translation>
+    </message>
+    <message>
+        <source>%1 is the host. He may adjust settings and start the game.</source>
+        <translation type="obsolete">%1 é o anfitrión. Pode configurar e iniciar a partida.</translation>
+    </message>
+    <message>
+        <source>Random Map</source>
+        <translation type="obsolete">Mapa ao chou</translation>
+    </message>
+    <message>
+        <source>Games may be played on precreated or randomized maps.</source>
+        <translation type="obsolete">Pódese xogar en mapas elaborados ou mapas xerados ao chou.</translation>
+    </message>
+    <message>
+        <source>The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</source>
+        <translation type="obsolete">O modo de xogo establece as opcións xerais tales coma &quot;tempo por rolda&quot;, &quot;morte súbita&quot; ou &quot;vampirismo&quot;.</translation>
+    </message>
+    <message>
+        <source>The Weapon Scheme defines available weapons and their ammunition count.</source>
+        <translation type="obsolete">O armamento establece as armas dispoñibles e a cantidade de munición para cada unha.</translation>
+    </message>
+    <message numerus="yes">
+        <source>There are %1 clients connected to this room.</source>
+        <translation type="obsolete">
+            <numerusform>Hai un cliente conectado a esta sala.</numerusform>
+            <numerusform>Hai %1 clientes conectados a esta sala.</numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <source>There are %1 teams participating in this room.</source>
+        <translation type="obsolete">
+            <numerusform>Hai un equipo participando nesta sala.</numerusform>
+            <numerusform>Hai %1 equipos participando nesta sala.</numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Please enter room name</source>
+        <translation type="obsolete">Introduce o nome da sala</translation>
+    </message>
+    <message>
+        <source>Please select room from the list</source>
+        <translation type="obsolete">Selecciona unha sala da lista</translation>
+    </message>
+    <message>
+        <source>Rules:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Search:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation type="unfinished">Borrado</translation>
+    </message>
+    <message numerus="yes">
+        <source>%1 players online</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+</context>
+<context>
+    <name>PageScheme</name>
+    <message>
+        <source>Defend your fort and destroy the opponents, two team colours max!</source>
+        <translation>Defende o teu forte e elimina os inimigos, máximo dous bandos!</translation>
+    </message>
+    <message>
+        <source>Teams will start on opposite sides of the terrain, two team colours max!</source>
+        <translation>Os bandos comezarán en lados opostos da superficie, máximo dous bandos!</translation>
+    </message>
+    <message>
+        <source>Land can not be destroyed!</source>
+        <translation>Non se pode destruír o terreo!</translation>
+    </message>
+    <message>
+        <source>Add an indestructable border around the terrain</source>
+        <translation type="obsolete">Engade un bordo indestructible arredor do terreo</translation>
+    </message>
+    <message>
+        <source>Lower gravity</source>
+        <translation>Baixa gravidade</translation>
+    </message>
+    <message>
+        <source>Assisted aiming with laser sight</source>
+        <translation>Mira láser</translation>
+    </message>
+    <message>
+        <source>All hogs have a personal forcefield</source>
+        <translation>Todos os ourizos teñen un escudo protector</translation>
+    </message>
+    <message>
+        <source>Enable random mines</source>
+        <translation type="obsolete">Activar as minas esparexidas</translation>
+    </message>
+    <message>
+        <source>Gain 80% of the damage you do back in health</source>
+        <translation>Gañar o 80% do daño inflixido en vida</translation>
+    </message>
+    <message>
+        <source>Share your opponents pain, share their damage</source>
+        <translation>Acompañar aos inimigos no sentimento e no dano</translation>
+    </message>
+    <message>
+        <source>Your hogs are unable to move, put your artillery skills to the test</source>
+        <translation>Os ourizos non se poden mover, pon a probas a túa faceta de artilleiro</translation>
+    </message>
+    <message>
+        <source>Random</source>
+        <translation>Ao chou</translation>
+    </message>
+    <message>
+        <source>Seconds</source>
+        <translation>segundos</translation>
+    </message>
+    <message>
+        <source>New</source>
+        <translation>Novo</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Borrar</translation>
+    </message>
+    <message>
+        <source>Add an indestructible border around the terrain</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All (living) hedgehogs are fully restored at the end of turn</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Order of play is random instead of in room order.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play with a King. If he dies, your side dies.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Take turns placing your hedgehogs before the start of play.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Ammo is shared between all teams that share a colour.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disable girders when generating random maps.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disable land objects when generating random maps.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>AI respawns on death.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Attacking does not end your turn.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons are reset to starting values each turn.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Each hedgehog has its own ammo. It does not share with the team.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>You will not have to worry about wind anymore.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Wind will affect almost everything.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Teams in each clan take successive turns sharing their turn time.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add an indestructible border along the bottom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageSelectWeapon</name>
+    <message>
+        <source>Default</source>
+        <translation>Por defecto</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Borrar</translation>
+    </message>
+    <message>
+        <source>New</source>
+        <translation type="unfinished">Novo</translation>
+    </message>
+    <message>
+        <source>Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageSinglePlayer</name>
+    <message>
+        <source>Simple Game (a quick game against the computer, settings are chosen for you)</source>
+        <translation type="obsolete">Partida simple (unha partida rápida xa configurada contra a intelixencia artificial)</translation>
+    </message>
+    <message>
+        <source>Multiplayer (play a hotseat game against your friends, or AI teams)</source>
+        <translation type="obsolete">Partida colectiva (xoga no teu computador contra os teus amigos ou contra a intelixencia artificial)</translation>
+    </message>
+    <message>
+        <source>Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT</source>
+        <translation type="obsolete">Adestramento (practica as túas habilidades nunha serie de misións de adestramento). EN DESENVOLVEMENTO</translation>
+    </message>
+    <message>
+        <source>Demos (Watch recorded demos)</source>
+        <translation type="obsolete">Demostracións (reproduce demostracións gravadas)</translation>
+    </message>
+    <message>
+        <source>Load (Load a previously saved game)</source>
+        <translation type="obsolete">Cargar (carga unha partida gardada)</translation>
+    </message>
+    <message>
+        <source>Simple Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a quick game against the computer with random settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Multiplayer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a hotseat game against your friends, or AI teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Campaign Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Training Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Practice your skills in a range of training missions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Watch recorded demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation type="unfinished">Cargar</translation>
+    </message>
+    <message>
+        <source>Load a previously saved game</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageTraining</name>
+    <message>
+        <source>Pick the mission or training to play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Start fighting</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No description available</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Select a mission!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageVideos</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>%1 bytes</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>(in progress...)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Date: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>encoding</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QAction</name>
+    <message>
+        <source>Kick</source>
+        <translation>Botar</translation>
+    </message>
+    <message>
+        <source>Info</source>
+        <translation>Información</translation>
+    </message>
+    <message>
+        <source>Start</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Restrict Joins</source>
+        <translation>Restrinxir a entrada</translation>
+    </message>
+    <message>
+        <source>Restrict Team Additions</source>
+        <translation>Restrinxir o engadido de equipos</translation>
+    </message>
+    <message>
+        <source>Ban</source>
+        <translation>Expulsar</translation>
+    </message>
+    <message>
+        <source>Update</source>
+        <translation type="unfinished">Actualizar</translation>
+    </message>
+    <message>
+        <source>Follow</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Ignore</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add friend</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unignore</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Remove friend</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QCheckBox</name>
+    <message>
+        <source>Check for updates at startup</source>
+        <translation>Comprobar se hai actualizacións ao iniciar</translation>
+    </message>
+    <message>
+        <source>Fullscreen</source>
+        <translation>Partidas a pantalla completa</translation>
+    </message>
+    <message>
+        <source>Frontend fullscreen</source>
+        <translation>Interface a pantalla completa</translation>
+    </message>
+    <message>
+        <source>Enable sound</source>
+        <translation>Activar os sons</translation>
+    </message>
+    <message>
+        <source>Enable music</source>
+        <translation>Activar a música</translation>
+    </message>
+    <message>
+        <source>Show FPS</source>
+        <translation>Amosar as FPS</translation>
+    </message>
+    <message>
+        <source>Alternative damage show</source>
+        <translation>Gráficos de dano alternativos</translation>
+    </message>
+    <message>
+        <source>Append date and time to record file name</source>
+        <translation>Engadir a data e maila hora ao nome dos ficheiros de gravación</translation>
+    </message>
+    <message>
+        <source>Frontend effects (requires restart)</source>
+        <translation type="obsolete">Efectos na interface (hai que reiniciar)</translation>
+    </message>
+    <message>
+        <source>Reduced quality</source>
+        <translation type="obsolete">Baixa calidade</translation>
+    </message>
+    <message>
+        <source>Save password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Save account name and password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video is private</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Frontend effects</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable frontend sounds</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Enable frontend music</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Show ammo menu tooltips</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Record audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Use game resolution</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QComboBox</name>
+    <message>
+        <source>generated map...</source>
+        <translation>Mapa xerado...</translation>
+    </message>
+    <message>
+        <source>Human</source>
+        <translation>Xogador</translation>
+    </message>
+    <message>
+        <source>Level</source>
+        <translation>Nivel</translation>
+    </message>
+    <message>
+        <source>generated maze...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>hand drawn map...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Mission</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Community</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>(System default)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Cyan</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cyan/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Blue</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Blue/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Green</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Green/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Side-by-side</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Top-Bottom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Wiggle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Cyan grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cyan/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Blue grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Blue/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Red/Green grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Green/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Any</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>In lobby</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>In progress</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QGroupBox</name>
+    <message>
+        <source>Team Members</source>
+        <translation>Membros do equipo</translation>
+    </message>
+    <message>
+        <source>Team</source>
+        <translation type="obsolete">Equipo</translation>
+    </message>
+    <message>
+        <source>Fort</source>
+        <translation>Forte</translation>
+    </message>
+    <message>
+        <source>Key binds</source>
+        <translation>Controis</translation>
+    </message>
+    <message>
+        <source>Teams</source>
+        <translation>Equipos</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="obsolete">Armamento</translation>
+    </message>
+    <message>
+        <source>Audio/Graphic options</source>
+        <translation>Configuración audiovisual</translation>
+    </message>
+    <message>
+        <source>Net game</source>
+        <translation>Partida na rede</translation>
+    </message>
+    <message>
+        <source>Playing teams</source>
+        <translation>Equipos xogando</translation>
+    </message>
+    <message>
+        <source>Game Modifiers</source>
+        <translation>Modificadores da partida</translation>
+    </message>
+    <message>
+        <source>Basic Settings</source>
+        <translation>Configuración básica</translation>
+    </message>
+    <message>
+        <source>Team Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Schemes and Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Misc</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Custom colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Miscellaneous</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video recording options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QLabel</name>
+    <message>
+        <source>Mines Time</source>
+        <translation>Temporizador das minas</translation>
+    </message>
+    <message>
+        <source>Mines</source>
+        <translation>Minas</translation>
+    </message>
+    <message>
+        <source>Version</source>
+        <translation>Versión</translation>
+    </message>
+    <message>
+        <source>This program is distributed under the GNU General Public License</source>
+        <translation type="obsolete">Esta aplicación distribúese baixo a GNU General Public License</translation>
+    </message>
+    <message>
+        <source>Developers:</source>
+        <translation>Desenvolvedores:</translation>
+    </message>
+    <message>
+        <source>Art:</source>
+        <translation>Gráficos:</translation>
+    </message>
+    <message>
+        <source>Sounds:</source>
+        <translation>Sons:</translation>
+    </message>
+    <message>
+        <source>Translations:</source>
+        <translation>Traducións:</translation>
+    </message>
+    <message>
+        <source>Special thanks:</source>
+        <translation>Un especial agradecemento a:</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation>Armamento</translation>
+    </message>
+    <message>
+        <source>Host:</source>
+        <translation>Anfitrión:</translation>
+    </message>
+    <message>
+        <source>Port:</source>
+        <translation>Porto:</translation>
+    </message>
+    <message>
+        <source>Net nick</source>
+        <translation type="obsolete">Alcume</translation>
+    </message>
+    <message>
+        <source>Resolution</source>
+        <translation>Resolución</translation>
+    </message>
+    <message>
+        <source>FPS limit</source>
+        <translation>Límite de FPS</translation>
+    </message>
+    <message>
+        <source>Server name:</source>
+        <translation>Nome do servidor:</translation>
+    </message>
+    <message>
+        <source>Server port:</source>
+        <translation>Porto do servidor:</translation>
+    </message>
+    <message>
+        <source>Initial sound volume</source>
+        <translation>Volume inicial</translation>
+    </message>
+    <message>
+        <source>Damage Modifier</source>
+        <translation>Modificador de dano</translation>
+    </message>
+    <message>
+        <source>Turn Time</source>
+        <translation>Tempo por rolda</translation>
+    </message>
+    <message>
+        <source>Initial Health</source>
+        <translation>Saúde inicial</translation>
+    </message>
+    <message>
+        <source>Sudden Death Timeout</source>
+        <translation>Conta atrás ata a morte súbita</translation>
+    </message>
+    <message>
+        <source>Scheme Name:</source>
+        <translation>Nome do modo:</translation>
+    </message>
+    <message>
+        <source>Crate Drops</source>
+        <translation>Caída de caixas</translation>
+    </message>
+    <message>
+        <source>Game scheme</source>
+        <translation>Modo de xogo</translation>
+    </message>
+    <message>
+        <source>There are videos that are currently being processed.
+Exiting now will abort them.
+Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please provide either the YouTube account name or the email address associated with the Google Account.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Account name (or email): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video title: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video description: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tags (comma separated): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Grave</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Flag</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Voice</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Summary   </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tip: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This development build is &apos;work in progress&apos; and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Locale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation type="unfinished">Alcume</translation>
+    </message>
+    <message>
+        <source>Quality</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Stereo rendering</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sudden Death Water Rise</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Sudden Death Health Decrease</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>% Rope Length</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>% Health Crates</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Health in Crates</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>% Dud Mines</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Explosives</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>% Get Away Time</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Format</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Framerate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Bitrate (Kbps)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>This program is distributed under the GNU General Public License v2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Style</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QLineEdit</name>
+    <message>
+        <source>unnamed</source>
+        <translation>sen nome</translation>
+    </message>
+    <message>
+        <source>hedgehog %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>anonymous</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QMainWindow</name>
+    <message>
+        <source>Hedgewars %1</source>
+        <translation>Hedgewars %1</translation>
+    </message>
+</context>
+<context>
+    <name>QMessageBox</name>
+    <message>
+        <source>Network</source>
+        <translation type="obsolete">Rede</translation>
+    </message>
+    <message>
+        <source>Connection to server is lost</source>
+        <translation>Perdeuse a conexión co servidor</translation>
+    </message>
+    <message>
+        <source>Error</source>
+        <translation>Erro</translation>
+    </message>
+    <message>
+        <source>Failed to open data directory:
+%1
+Please check your installation</source>
+        <translation type="obsolete">Non se puido abrir o directorio dos datos:
+ %1
+Verifica a instalación</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="obsolete">Armamento</translation>
+    </message>
+    <message>
+        <source>Can not edit default weapon set</source>
+        <translation type="obsolete">Non se pode editar o armamento por defecto</translation>
+    </message>
+    <message>
+        <source>Can not delete default weapon set</source>
+        <translation type="obsolete">Non se pode borrar o armamento por defecto</translation>
+    </message>
+    <message>
+        <source>Really delete this weapon set?</source>
+        <translation type="obsolete">Seguro que queres borrar este armamento?</translation>
+    </message>
+    <message>
+        <source>Teams - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the team &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default scheme &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a record from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Success</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All file associations have been set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File association failed.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please fill out all fields</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully posted the issue on hedgewars.googlecode.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error during authentication at google.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Main - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot create directory %1</source>
+        <translation type="unfinished">Non se puido crear o directorio %1</translation>
+    </message>
+    <message>
+        <source>Failed to open data directory:
+%1
+
+Please check your installation!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>TCP - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start the server: %1.</source>
+        <translation type="unfinished">Non se puido iniciar o servidor: %1.</translation>
+    </message>
+    <message>
+        <source>Unable to run engine at </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error code: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while authenticating at google.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Login or password is incorrect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video upload - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while sending metadata to youtube.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Netgame - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a server from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter room name</source>
+        <translation type="unfinished">Introduce o nome da sala</translation>
+    </message>
+    <message>
+        <source>Record Play - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select record from the list</source>
+        <translation type="unfinished">Selecciona unha gravación da lista</translation>
+    </message>
+    <message>
+        <source>Cannot rename to </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete file </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Room Name - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select room from the list</source>
+        <translation type="unfinished">Selecciona unha sala da lista</translation>
+    </message>
+    <message>
+        <source>Room Name - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The game you are trying to join has started.
+Do you still want to join the room?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Schemes - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Schemes - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the game scheme &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the video &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>Do you really want to remove %1 file(s)?</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Do you really want to cancel uploading %1?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for writing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for reading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot use the ammo &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>Cannot create directory %1</source>
+        <translation type="obsolete">Non se puido crear o directorio %1</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation type="obsolete">Aceptar</translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation>Alcume</translation>
+    </message>
+    <message>
+        <source>Please enter your nickname</source>
+        <translation>Introduce o teu alcume</translation>
+    </message>
+</context>
+<context>
+    <name>QPushButton</name>
+    <message>
+        <source>default</source>
+        <translation>por defecto</translation>
+    </message>
+    <message>
+        <source>OK</source>
+        <translation>Aceptar</translation>
+    </message>
+    <message>
+        <source>Cancel</source>
+        <translation>Cancelar</translation>
+    </message>
+    <message>
+        <source>Start server</source>
+        <translation>Iniciar un servidor</translation>
+    </message>
+    <message>
+        <source>Connect</source>
+        <translation>Conectar</translation>
+    </message>
+    <message>
+        <source>Update</source>
+        <translation>Actualizar</translation>
+    </message>
+    <message>
+        <source>Specify</source>
+        <translation>Especificar</translation>
+    </message>
+    <message>
+        <source>Start</source>
+        <translation>Iniciar</translation>
+    </message>
+    <message>
+        <source>Go!</source>
+        <translation>Dálle!</translation>
+    </message>
+    <message>
+        <source>Play demo</source>
+        <translation>Reproducir a demostración</translation>
+    </message>
+    <message>
+        <source>Rename</source>
+        <translation>Cambiar o nome</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Borrar</translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation>Cargar</translation>
+    </message>
+    <message>
+        <source>Setup</source>
+        <translation>Configuración</translation>
+    </message>
+    <message>
+        <source>Ready</source>
+        <translation>Preparado</translation>
+    </message>
+    <message>
+        <source>More info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Random Team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Associate file extensions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set default options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open videos directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload to YouTube</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>more</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QTableWidget</name>
+    <message>
+        <source>Room Name</source>
+        <translation type="obsolete">Nome da sala</translation>
+    </message>
+    <message>
+        <source>C</source>
+        <translation type="obsolete">C</translation>
+    </message>
+    <message>
+        <source>T</source>
+        <translation type="obsolete">T</translation>
+    </message>
+    <message>
+        <source>Owner</source>
+        <translation type="obsolete">Dono</translation>
+    </message>
+    <message>
+        <source>Map</source>
+        <translation type="obsolete">Mapa</translation>
+    </message>
+    <message>
+        <source>Rules</source>
+        <translation type="obsolete">Regras</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="obsolete">Armamento</translation>
+    </message>
+</context>
+<context>
+    <name>RoomsListModel</name>
+    <message>
+        <source>In progress</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Room Name</source>
+        <translation type="unfinished">Nome da sala</translation>
+    </message>
+    <message>
+        <source>C</source>
+        <translation type="unfinished">C</translation>
+    </message>
+    <message>
+        <source>T</source>
+        <translation type="unfinished">T</translation>
+    </message>
+    <message>
+        <source>Owner</source>
+        <translation type="unfinished">Dono</translation>
+    </message>
+    <message>
+        <source>Map</source>
+        <translation type="unfinished">Mapa</translation>
+    </message>
+    <message>
+        <source>Rules</source>
+        <translation type="unfinished">Regras</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="unfinished">Armamento</translation>
+    </message>
+    <message>
+        <source>Random Map</source>
+        <translation type="unfinished">Mapa ao chou</translation>
+    </message>
+    <message>
+        <source>Random Maze</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hand-drawn</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SelWeaponWidget</name>
+    <message>
+        <source>Weapon set</source>
+        <translation>Armamento</translation>
+    </message>
+    <message>
+        <source>Probabilities</source>
+        <translation>Probabilidades</translation>
+    </message>
+    <message>
+        <source>Ammo in boxes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delays</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>new</source>
+        <translation type="unfinished">novo</translation>
+    </message>
+    <message>
+        <source>copy of</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TCPBase</name>
+    <message>
+        <source>Error</source>
+        <translation type="obsolete">Erro</translation>
+    </message>
+    <message>
+        <source>Unable to start the server: %1.</source>
+        <translation type="obsolete">Non se puido iniciar o servidor: %1.</translation>
+    </message>
+    <message>
+        <source>Unable to run engine: %1 (</source>
+        <translation type="obsolete">Non se puido executar o motor: %1 (</translation>
+    </message>
+</context>
+<context>
+    <name>ToggleButtonWidget</name>
+    <message>
+        <source>Vampirism</source>
+        <translation>Vampirismo</translation>
+    </message>
+    <message>
+        <source>Karma</source>
+        <translation>Karma</translation>
+    </message>
+    <message>
+        <source>Artillery</source>
+        <translation>Artillería</translation>
+    </message>
+    <message>
+        <source>Fort Mode</source>
+        <translation>Modo fortaleza</translation>
+    </message>
+    <message>
+        <source>Divide Teams</source>
+        <translation>Equipos divididos</translation>
+    </message>
+    <message>
+        <source>Solid Land</source>
+        <translation>Terreo indestructible</translation>
+    </message>
+    <message>
+        <source>Add Border</source>
+        <translation>Con bordos</translation>
+    </message>
+    <message>
+        <source>Low Gravity</source>
+        <translation>Baixa gravidade</translation>
+    </message>
+    <message>
+        <source>Laser Sight</source>
+        <translation>Mira láser</translation>
+    </message>
+    <message>
+        <source>Invulnerable</source>
+        <translation>Invulnerable</translation>
+    </message>
+    <message>
+        <source>Add Mines</source>
+        <translation type="obsolete">Engadir minas</translation>
+    </message>
+    <message>
+        <source>Reset Health</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Random Order</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>King</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Place Hedgehogs</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Clan Shares Ammo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disable Girders</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disable Land Objects</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>AI Survival Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unlimited Attacks</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Reset Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Per Hedgehog Ammo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Disable Wind</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>More Wind</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tag Team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Add Bottom Border</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds</name>
+    <message>
+        <source>up</source>
+        <translation>arriba</translation>
+    </message>
+    <message>
+        <source>left</source>
+        <translation>esquerda</translation>
+    </message>
+    <message>
+        <source>right</source>
+        <translation>dereita</translation>
+    </message>
+    <message>
+        <source>down</source>
+        <translation>abaixo</translation>
+    </message>
+    <message>
+        <source>attack</source>
+        <translation>atacar</translation>
+    </message>
+    <message>
+        <source>precise aim</source>
+        <translation>apuntar con precisión</translation>
+    </message>
+    <message>
+        <source>put</source>
+        <translation>poñer</translation>
+    </message>
+    <message>
+        <source>switch</source>
+        <translation>cambiar</translation>
+    </message>
+    <message>
+        <source>find hedgehog</source>
+        <translation>atopar ourizo</translation>
+    </message>
+    <message>
+        <source>ammo menu</source>
+        <translation>menú de armas</translation>
+    </message>
+    <message>
+        <source>slot 1</source>
+        <translation>1ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 2</source>
+        <translation>2ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 3</source>
+        <translation>3ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 4</source>
+        <translation>4ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 5</source>
+        <translation>5ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 6</source>
+        <translation>6ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 7</source>
+        <translation>7ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 8</source>
+        <translation>8ª ranura</translation>
+    </message>
+    <message>
+        <source>slot 9</source>
+        <translation>9ª ranura</translation>
+    </message>
+    <message>
+        <source>timer 1 sec</source>
+        <translation>temporizador a 1 segundo</translation>
+    </message>
+    <message>
+        <source>timer 2 sec</source>
+        <translation>temporizador a 2 segundos</translation>
+    </message>
+    <message>
+        <source>timer 3 sec</source>
+        <translation>temporizador a 3 segundos</translation>
+    </message>
+    <message>
+        <source>timer 4 sec</source>
+        <translation>temporizador a 4 segundos</translation>
+    </message>
+    <message>
+        <source>timer 5 sec</source>
+        <translation>temporizador a 5 segundos</translation>
+    </message>
+    <message>
+        <source>chat</source>
+        <translation>conversa</translation>
+    </message>
+    <message>
+        <source>chat history</source>
+        <translation>historial de conversa</translation>
+    </message>
+    <message>
+        <source>pause</source>
+        <translation>pausa</translation>
+    </message>
+    <message>
+        <source>confirmation</source>
+        <translation>confirmación</translation>
+    </message>
+    <message>
+        <source>volume down</source>
+        <translation>baixar o volume</translation>
+    </message>
+    <message>
+        <source>volume up</source>
+        <translation>subir o volume</translation>
+    </message>
+    <message>
+        <source>change mode</source>
+        <translation>cambiar o modo</translation>
+    </message>
+    <message>
+        <source>capture</source>
+        <translation>capturar</translation>
+    </message>
+    <message>
+        <source>hedgehogs
+info</source>
+        <translation>información
+dos ourizos</translation>
+    </message>
+    <message>
+        <source>quit</source>
+        <translation>saír</translation>
+    </message>
+    <message>
+        <source>zoom in</source>
+        <translation>achegar</translation>
+    </message>
+    <message>
+        <source>zoom out</source>
+        <translation>afastar</translation>
+    </message>
+    <message>
+        <source>reset zoom</source>
+        <translation>distancia inicial</translation>
+    </message>
+    <message>
+        <source>long jump</source>
+        <translation>salto cara adiante</translation>
+    </message>
+    <message>
+        <source>high jump</source>
+        <translation>salto cara arriba</translation>
+    </message>
+    <message>
+        <source>slot 10</source>
+        <translation type="unfinished">10ª ranura</translation>
+    </message>
+    <message>
+        <source>mute audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>record</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds (categories)</name>
+    <message>
+        <source>Basic controls</source>
+        <translation>Controis básicos</translation>
+    </message>
+    <message>
+        <source>Weapon controls</source>
+        <translation>Controis das armas</translation>
+    </message>
+    <message>
+        <source>Camera and cursor controls</source>
+        <translation>Controis da cámara e mailo cursor</translation>
+    </message>
+    <message>
+        <source>Other</source>
+        <translation>Outros</translation>
+    </message>
+</context>
+<context>
+    <name>binds (descriptions)</name>
+    <message>
+        <source>Move your hogs and aim:</source>
+        <translation>Move os teus ourizos e apunta:</translation>
+    </message>
+    <message>
+        <source>Traverse gaps and obstacles by jumping:</source>
+        <translation>Supera os obstáculos saltando:</translation>
+    </message>
+    <message>
+        <source>Fire your selected weapon or trigger an utility item:</source>
+        <translation>Dispara a arma seleccionada ou activa unha ferramenta:</translation>
+    </message>
+    <message>
+        <source>Pick a weapon or a target location under the cursor:</source>
+        <translation>Recolle un arma ou a situación dun obxectivo onde o cursor:</translation>
+    </message>
+    <message>
+        <source>Switch your currently active hog (if possible):</source>
+        <translation>Cambia de ourizo (se se pode):</translation>
+    </message>
+    <message>
+        <source>Pick a weapon or utility item:</source>
+        <translation>Recolle unha arma ou ferramenta:</translation>
+    </message>
+    <message>
+        <source>Set the timer on bombs and timed weapons:</source>
+        <translation>Establece o temporizador para as armas que o teñan:</translation>
+    </message>
+    <message>
+        <source>Move the camera to the active hog:</source>
+        <translation>Move a cámara ao ourizo activo:</translation>
+    </message>
+    <message>
+        <source>Move the cursor or camera without using the mouse:</source>
+        <translation>Move o cursor ou a cámara sen usar o rato:</translation>
+    </message>
+    <message>
+        <source>Modify the camera&apos;s zoom level:</source>
+        <translation>Cambia a distancia da cámara:</translation>
+    </message>
+    <message>
+        <source>Talk to your team or all participants:</source>
+        <translation>Fala co teu equipo ou con todos:</translation>
+    </message>
+    <message>
+        <source>Pause, continue or leave your game:</source>
+        <translation>Pausa, continúa ou sal da túa partida:</translation>
+    </message>
+    <message>
+        <source>Modify the game&apos;s volume while playing:</source>
+        <translation>Cambia o volume do xogo durante unha partida:</translation>
+    </message>
+    <message>
+        <source>Toggle fullscreen mode:</source>
+        <translation>Cambiar a pantalla completa:</translation>
+    </message>
+    <message>
+        <source>Take a screenshot:</source>
+        <translation>Facer unha captura de pantalla:</translation>
+    </message>
+    <message>
+        <source>Toggle labels above hedgehogs:</source>
+        <translation>Cambiar as etiquetas sobre os ourizos:</translation>
+    </message>
+    <message>
+        <source>Record video:</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds (keys)</name>
+    <message>
+        <source>Axis</source>
+        <translation>Eixo</translation>
+    </message>
+    <message>
+        <source>(Up)</source>
+        <translation>(Arriba)</translation>
+    </message>
+    <message>
+        <source>(Down)</source>
+        <translation>(Abaixo)</translation>
+    </message>
+    <message>
+        <source>Hat</source>
+        <translation>Sombreiro</translation>
+    </message>
+    <message>
+        <source>(Left)</source>
+        <translation>(Esquerda)</translation>
+    </message>
+    <message>
+        <source>(Right)</source>
+        <translation>(Dereita)</translation>
+    </message>
+    <message>
+        <source>Button</source>
+        <translation>Botón</translation>
+    </message>
+    <message>
+        <source>Keyboard</source>
+        <translation>Teclado</translation>
+    </message>
+    <message>
+        <source>Mouse: Left button</source>
+        <translation>Rato: botón esquerdo</translation>
+    </message>
+    <message>
+        <source>Mouse: Middle button</source>
+        <translation>Rato: botón central</translation>
+    </message>
+    <message>
+        <source>Mouse: Right button</source>
+        <translation>Rato: botón dereito</translation>
+    </message>
+    <message>
+        <source>Mouse: Wheel up</source>
+        <translation>Rato: roda cara arriba</translation>
+    </message>
+    <message>
+        <source>Mouse: Wheel down</source>
+        <translation>Rato: roda cara abaixo</translation>
+    </message>
+    <message>
+        <source>Backspace</source>
+        <translation>Retroceso</translation>
+    </message>
+    <message>
+        <source>Tab</source>
+        <translation>Tabulador</translation>
+    </message>
+    <message>
+        <source>Clear</source>
+        <translation>Borrado</translation>
+    </message>
+    <message>
+        <source>Return</source>
+        <translation>Retorno</translation>
+    </message>
+    <message>
+        <source>Pause</source>
+        <translation>Pausa</translation>
+    </message>
+    <message>
+        <source>Escape</source>
+        <translation>Escape</translation>
+    </message>
+    <message>
+        <source>Space</source>
+        <translation>Espazo</translation>
+    </message>
+    <message>
+        <source>Delete</source>
+        <translation>Borrar</translation>
+    </message>
+    <message>
+        <source>Numpad 0</source>
+        <translation>Teclado numérico: 0</translation>
+    </message>
+    <message>
+        <source>Numpad 1</source>
+        <translation>Teclado numérico: 1</translation>
+    </message>
+    <message>
+        <source>Numpad 2</source>
+        <translation>Teclado numérico: 2</translation>
+    </message>
+    <message>
+        <source>Numpad 3</source>
+        <translation>Teclado numérico: 3</translation>
+    </message>
+    <message>
+        <source>Numpad 4</source>
+        <translation>Teclado numérico: 4</translation>
+    </message>
+    <message>
+        <source>Numpad 5</source>
+        <translation>Teclado numérico: 5</translation>
+    </message>
+    <message>
+        <source>Numpad 6</source>
+        <translation>Teclado numérico: 6</translation>
+    </message>
+    <message>
+        <source>Numpad 7</source>
+        <translation>Teclado numérico: 7</translation>
+    </message>
+    <message>
+        <source>Numpad 8</source>
+        <translation>Teclado numérico: 8</translation>
+    </message>
+    <message>
+        <source>Numpad 9</source>
+        <translation>Teclado numérico: 9</translation>
+    </message>
+    <message>
+        <source>Numpad .</source>
+        <translation>Teclado numérico: .</translation>
+    </message>
+    <message>
+        <source>Numpad /</source>
+        <translation>Teclado numérico: /</translation>
+    </message>
+    <message>
+        <source>Numpad *</source>
+        <translation>Teclado numérico: *</translation>
+    </message>
+    <message>
+        <source>Numpad -</source>
+        <translation>Teclado numérico: -</translation>
+    </message>
+    <message>
+        <source>Numpad +</source>
+        <translation>Teclado numérico: +</translation>
+    </message>
+    <message>
+        <source>Enter</source>
+        <translation>Intro</translation>
+    </message>
+    <message>
+        <source>Equals</source>
+        <translation>Igual</translation>
+    </message>
+    <message>
+        <source>Up</source>
+        <translation>Arriba</translation>
+    </message>
+    <message>
+        <source>Down</source>
+        <translation>Abaixo</translation>
+    </message>
+    <message>
+        <source>Right</source>
+        <translation>Dereita</translation>
+    </message>
+    <message>
+        <source>Left</source>
+        <translation>Esquerda</translation>
+    </message>
+    <message>
+        <source>Insert</source>
+        <translation>Inserir</translation>
+    </message>
+    <message>
+        <source>Home</source>
+        <translation>Inicio</translation>
+    </message>
+    <message>
+        <source>End</source>
+        <translation>Fin</translation>
+    </message>
+    <message>
+        <source>Page up</source>
+        <translation>Re Páx</translation>
+    </message>
+    <message>
+        <source>Page down</source>
+        <translation>Av Páx</translation>
+    </message>
+    <message>
+        <source>Num lock</source>
+        <translation>Bloq Num</translation>
+    </message>
+    <message>
+        <source>Caps lock</source>
+        <translation>Bloq Maiús</translation>
+    </message>
+    <message>
+        <source>Scroll lock</source>
+        <translation>Bloq Despr</translation>
+    </message>
+    <message>
+        <source>Right shift</source>
+        <translation>Maiús dereito</translation>
+    </message>
+    <message>
+        <source>Left shift</source>
+        <translation>Maiús esquerdo</translation>
+    </message>
+    <message>
+        <source>Right ctrl</source>
+        <translation>Ctrl dereito</translation>
+    </message>
+    <message>
+        <source>Left ctrl</source>
+        <translation>Ctrl esquerdo</translation>
+    </message>
+    <message>
+        <source>Right alt</source>
+        <translation>Alt dereito</translation>
+    </message>
+    <message>
+        <source>Left alt</source>
+        <translation>Alt esquerdo</translation>
+    </message>
+    <message>
+        <source>Right meta</source>
+        <translation>Meta dereito</translation>
+    </message>
+    <message>
+        <source>Left meta</source>
+        <translation>Meta esquerdo</translation>
+    </message>
+    <message>
+        <source>A button</source>
+        <translation>Botón A</translation>
+    </message>
+    <message>
+        <source>B button</source>
+        <translation>Botón B</translation>
+    </message>
+    <message>
+        <source>X button</source>
+        <translation>Botón X</translation>
+    </message>
+    <message>
+        <source>Y button</source>
+        <translation>Botón Y</translation>
+    </message>
+    <message>
+        <source>LB button</source>
+        <translation>Botón LB</translation>
+    </message>
+    <message>
+        <source>RB button</source>
+        <translation>Botón RB</translation>
+    </message>
+    <message>
+        <source>Back button</source>
+        <translation>Botón de volver</translation>
+    </message>
+    <message>
+        <source>Start button</source>
+        <translation>Botón de inicio</translation>
+    </message>
+    <message>
+        <source>Left stick</source>
+        <translation>Stick esquerdo</translation>
+    </message>
+    <message>
+        <source>Right stick</source>
+        <translation>Stick dereito</translation>
+    </message>
+    <message>
+        <source>Left stick (Right)</source>
+        <translation>Stick esquerdo (Dereita)</translation>
+    </message>
+    <message>
+        <source>Left stick (Left)</source>
+        <translation>Stick esquerdo (Esquerda)</translation>
+    </message>
+    <message>
+        <source>Left stick (Down)</source>
+        <translation>Stick esquerdo (Abaixo)</translation>
+    </message>
+    <message>
+        <source>Left stick (Up)</source>
+        <translation>Stick esquerdo (Arriba)</translation>
+    </message>
+    <message>
+        <source>Left trigger</source>
+        <translation>Gatillo esquerdo</translation>
+    </message>
+    <message>
+        <source>Right trigger</source>
+        <translation>Gatillo dereito</translation>
+    </message>
+    <message>
+        <source>Right stick (Down)</source>
+        <translation>Stick dereito (Abaixo)</translation>
+    </message>
+    <message>
+        <source>Right stick (Up)</source>
+        <translation>Stick dereito (Arriba)</translation>
+    </message>
+    <message>
+        <source>Right stick (Right)</source>
+        <translation>Stick dereito (Dereita)</translation>
+    </message>
+    <message>
+        <source>Right stick (Left)</source>
+        <translation>Stick dereito (Esquerda)</translation>
+    </message>
+    <message>
+        <source>DPad</source>
+        <translation>Mando</translation>
+    </message>
+</context>
+</TS>
--- a/share/hedgewars/Data/Locale/hedgewars_hu.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_hu.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -340,7 +340,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -821,14 +821,6 @@
         <source>Control</source>
         <translation>Irányítás</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2136,6 +2128,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_it.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_it.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,23 +344,43 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished">Durata: %1m %2s</translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished">Video: %1x%2, </translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished">%1 fps, </translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished">Audio:</translation>
+    </message>
+</context>
+<context>
     <name>LibavIteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
-        <translation>Durata: %1m %2s</translation>
+        <translation type="obsolete">Durata: %1m %2s</translation>
     </message>
     <message>
         <source>Video: %1x%2, </source>
-        <translation>Video: %1x%2, </translation>
+        <translation type="obsolete">Video: %1x%2, </translation>
     </message>
     <message>
         <source>%1 fps, </source>
-        <translation>%1 fps, </translation>
+        <translation type="obsolete">%1 fps, </translation>
     </message>
     <message>
         <source>Audio: </source>
-        <translation>Audio:</translation>
+        <translation type="obsolete">Audio:</translation>
     </message>
 </context>
 <context>
@@ -833,11 +853,11 @@
     </message>
     <message>
         <source>DLC</source>
-        <translation>DLC</translation>
+        <translation type="obsolete">DLC</translation>
     </message>
     <message>
         <source>Downloadable Content</source>
-        <translation>Contenuti Scaricabili</translation>
+        <translation type="obsolete">Contenuti Scaricabili</translation>
     </message>
 </context>
 <context>
@@ -2152,6 +2172,26 @@
         <source>Cancel uploading</source>
         <translation>Sospendi caricamento</translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_ja.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_ja.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -825,14 +825,6 @@
         <source>Control</source>
         <translation>コントロール</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2140,6 +2132,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_ko.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_ko.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -340,7 +340,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -821,14 +821,6 @@
         <source>Control</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2136,6 +2128,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_lt.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_lt.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -131,18 +131,18 @@
 <context>
     <name>HWForm</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="463"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="465"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="460"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="462"/>
         <source>DefaultTeam</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="569"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="566"/>
         <source>Game aborted</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="981"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="978"/>
         <source>Your nickname %1 is
 registered on Hedgewars.org
 Please provide your password below
@@ -150,51 +150,51 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="985"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="982"/>
         <source>No password supplied.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1011"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1008"/>
         <source>Nickname</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1015"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1012"/>
         <source>No nickname supplied.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1011"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1008"/>
         <source>Someone already uses your nickname %1 on the server.
 Please pick another nickname:</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1430"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1717"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1432"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1719"/>
         <source>Cannot save record to file %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1660"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1662"/>
         <source>Hedgewars Demo File</source>
         <comment>File Types</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1661"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1663"/>
         <source>Hedgewars Save File</source>
         <comment>File Types</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1709"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1711"/>
         <source>Demo name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1709"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1711"/>
         <source>Demo name:</source>
         <translation type="unfinished"></translation>
     </message>
@@ -202,13 +202,13 @@
 <context>
     <name>HWGame</name>
     <message>
-        <location filename="../../../../QTfrontend/game.cpp" line="350"/>
+        <location filename="../../../../QTfrontend/game.cpp" line="333"/>
         <location filename="../../../../QTfrontend/net/recorder.cpp" line="118"/>
         <source>en.txt</source>
         <translation>lt.txt</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/game.cpp" line="361"/>
+        <location filename="../../../../QTfrontend/game.cpp" line="344"/>
         <source>Cannot open demofile %1</source>
         <translation type="unfinished"></translation>
     </message>
@@ -385,7 +385,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1285"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1282"/>
         <source>Quit reason: </source>
         <translation type="unfinished"></translation>
     </message>
@@ -420,25 +420,25 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
-    <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="282"/>
+    <name>LibavInteraction</name>
+    <message>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="281"/>
         <source>Duration: %1m %2s
 </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="294"/>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="293"/>
         <source>Video: %1x%2, </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="298"/>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="297"/>
         <source>%1 fps, </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="302"/>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="301"/>
         <source>Audio: </source>
         <translation type="unfinished"></translation>
     </message>
@@ -1008,17 +1008,7 @@
 <context>
     <name>PageNetGame</name>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="65"/>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="66"/>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="87"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="84"/>
         <source>Control</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1480,17 +1470,17 @@
 <context>
     <name>PageVideos</name>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="233"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="234"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="234"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="235"/>
         <source>Size</source>
         <translation type="unfinished"></translation>
     </message>
     <message numerus="yes">
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="492"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="498"/>
         <source>%1 bytes</source>
         <translation type="unfinished">
             <numerusform></numerusform>
@@ -1499,27 +1489,27 @@
         </translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="742"/>
         <source>(in progress...)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="740"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="746"/>
         <source>Date: </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="741"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="747"/>
         <source>Size: </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="955"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="966"/>
         <source>encoding</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="957"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="968"/>
         <source>uploading</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1569,22 +1559,22 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="82"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="79"/>
         <source>Update</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="112"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="107"/>
         <source>Restrict Joins</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="114"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="109"/>
         <source>Restrict Team Additions</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="90"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="87"/>
         <source>Start</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1901,12 +1891,12 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="230"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="231"/>
         <source>Videos</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="265"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="267"/>
         <source>Description</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1929,22 +1919,22 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="90"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="94"/>
         <source>Art:</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="108"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="112"/>
         <source>Sounds:</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="118"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="122"/>
         <source>Translations:</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="142"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="146"/>
         <source>Special thanks:</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2216,7 +2206,7 @@
 <context>
     <name>QLineEdit</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="882"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="879"/>
         <source>unnamed</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2243,77 +2233,77 @@
 <context>
     <name>QMessageBox</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="904"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="901"/>
         <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="388"/>
         <source>Teams - Are you sure?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="905"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="902"/>
         <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="389"/>
         <source>Do you really want to delete the team &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="921"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="918"/>
         <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="525"/>
         <source>Cannot delete default scheme &apos;%1&apos;!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="947"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="944"/>
         <source>Please select a record from the list</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1241"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1238"/>
         <source>Unable to start server</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1285"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1282"/>
         <source>Connection to server is lost</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1392"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1394"/>
         <source>Hedgewars - Error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1692"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1783"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1694"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1785"/>
         <source>Hedgewars - Success</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1693"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1695"/>
         <source>All file associations have been set</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1784"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1786"/>
         <source>Successfully posted the issue on hedgewars.googlecode.com</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1796"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1809"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1798"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1811"/>
         <source>Error during authentication at google.com</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1812"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1814"/>
         <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1698"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1700"/>
         <source>File association failed.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1734"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1736"/>
         <source>Please fill out all fields</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2392,7 +2382,7 @@
     </message>
     <message>
         <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="113"/>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="162"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="157"/>
         <source>Netgame - Error</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2402,7 +2392,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="163"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="158"/>
         <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="431"/>
         <source>Please enter room name</source>
         <translation type="unfinished"></translation>
@@ -2469,19 +2459,19 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="844"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="868"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1093"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="850"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="879"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1104"/>
         <source>Videos - Are you sure?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="845"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="851"/>
         <source>Do you really want to delete the video &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
     <message numerus="yes">
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="869"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="880"/>
         <source>Do you really want to remove %1 file(s)?</source>
         <translation type="unfinished">
             <numerusform></numerusform>
@@ -2490,7 +2480,7 @@
         </translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1094"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1105"/>
         <source>Do you really want to cancel uploading %1?</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2511,28 +2501,28 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="199"/>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="254"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="229"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="266"/>
         <source>Weapons - Warning</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="200"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="230"/>
         <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="255"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="267"/>
         <source>Cannot delete default weapon set &apos;%1&apos;!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="263"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="275"/>
         <source>Weapons - Are you sure?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="264"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="276"/>
         <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2540,12 +2530,12 @@
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1203"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1200"/>
         <source>Nickname</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1204"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1201"/>
         <source>Please enter your nickname</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2565,7 +2555,7 @@
     </message>
     <message>
         <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="57"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="729"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="735"/>
         <source>Cancel</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2612,7 +2602,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="75"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="72"/>
         <source>Ready</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2639,8 +2629,8 @@
     </message>
     <message>
         <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="53"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="300"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="729"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="303"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="735"/>
         <source>Delete</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2660,23 +2650,48 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="252"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="220"/>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="253"/>
         <source>Open videos directory</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="297"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="254"/>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="299"/>
         <source>Play</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="303"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="730"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="301"/>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="305"/>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="307"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
         <source>Upload to YouTube</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="730"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="309"/>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2762,14 +2777,14 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="277"/>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="282"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="289"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="294"/>
         <source>new</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="313"/>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="318"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="325"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="330"/>
         <source>copy of</source>
         <translation type="unfinished"></translation>
     </message>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/hedgewars/Data/Locale/hedgewars_ms.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -0,0 +1,3629 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="ms_MY">
+<context>
+    <name>AbstractPage</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/AbstractPage.cpp" line="51"/>
+        <source>Go back</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>AmmoSchemeModel</name>
+    <message>
+        <location filename="../../../../QTfrontend/model/ammoSchemeModel.cpp" line="673"/>
+        <source>new</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/ammoSchemeModel.cpp" line="679"/>
+        <source>copy of</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>FreqSpinBox</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/FreqSpinBox.cpp" line="36"/>
+        <source>Never</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/widget/FreqSpinBox.cpp" line="38"/>
+        <source>Every %1 turn</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+</context>
+<context>
+    <name>GameCFGWidget</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="54"/>
+        <source>Game Options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="79"/>
+        <source>Edit schemes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="94"/>
+        <source>Edit weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="102"/>
+        <source>When this option is enabled selecting a game scheme will auto-select a weapon</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWAskQuitDialog</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/ask_quit.cpp" line="33"/>
+        <source>Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWChatWidget</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="627"/>
+        <source>%1 has been removed from your ignore list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="637"/>
+        <source>%1 has been added to your ignore list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="667"/>
+        <source>%1 has been removed from your friends list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="676"/>
+        <source>%1 has been added to your friends list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="742"/>
+        <source>Stylesheet imported from %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="743"/>
+        <source>Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="751"/>
+        <source>Couldn&apos;t read %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="759"/>
+        <source>StyleSheet discarded</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="784"/>
+        <source>StyleSheet saved to %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="787"/>
+        <source>Failed to save StyleSheet to %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="807"/>
+        <source>%1 is not a valid command!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWForm</name>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="460"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="462"/>
+        <source>DefaultTeam</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="566"/>
+        <source>Game aborted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="978"/>
+        <source>Your nickname %1 is
+registered on Hedgewars.org
+Please provide your password below
+or pick another nickname in game config:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="982"/>
+        <source>No password supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1008"/>
+        <source>Nickname</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1008"/>
+        <source>Someone already uses your nickname %1 on the server.
+Please pick another nickname:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1012"/>
+        <source>No nickname supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1432"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1719"/>
+        <source>Cannot save record to file %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1662"/>
+        <source>Hedgewars Demo File</source>
+        <comment>File Types</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1663"/>
+        <source>Hedgewars Save File</source>
+        <comment>File Types</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1711"/>
+        <source>Demo name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1711"/>
+        <source>Demo name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWGame</name>
+    <message>
+        <location filename="../../../../QTfrontend/game.cpp" line="333"/>
+        <location filename="../../../../QTfrontend/net/recorder.cpp" line="118"/>
+        <source>en.txt</source>
+        <translation>ms.txt</translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/game.cpp" line="344"/>
+        <source>Cannot open demofile %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWMapContainer</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="82"/>
+        <source>Map</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="85"/>
+        <source>Filter</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="89"/>
+        <source>All</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="90"/>
+        <source>Small</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="91"/>
+        <source>Medium</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="92"/>
+        <source>Large</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="93"/>
+        <source>Cavern</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="94"/>
+        <source>Wacky</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="99"/>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="103"/>
+        <source>Small tunnels</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="104"/>
+        <source>Medium tunnels</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="105"/>
+        <source>Large tunnels</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="106"/>
+        <source>Small floating islands</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="107"/>
+        <source>Medium floating islands</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="108"/>
+        <source>Large floating islands</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="118"/>
+        <source>Themes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="162"/>
+        <source>Seed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="555"/>
+        <source>Set</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWNetServersModel</name>
+    <message>
+        <location filename="../../../../QTfrontend/model/netserverslist.cpp" line="46"/>
+        <source>Title</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/netserverslist.cpp" line="48"/>
+        <source>IP</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/netserverslist.cpp" line="50"/>
+        <source>Port</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWNewNet</name>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1282"/>
+        <source>Quit reason: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="71"/>
+        <source>User quit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="212"/>
+        <source>Remote host has closed connection</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="215"/>
+        <source>The host was not found. Please check the host name and port settings.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="218"/>
+        <source>Connection refused</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="276"/>
+        <source>The server is too old. Disconnecting now.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="447"/>
+        <source>You got kicked</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="471"/>
+        <source>%1 *** %2 has joined</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="518"/>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="739"/>
+        <source>%1 *** %2 has left</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="520"/>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="741"/>
+        <source>%1 *** %2 has left (%3)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="597"/>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="724"/>
+        <source>%1 *** %2 has joined the room</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/newnetclient.cpp" line="648"/>
+        <source>Room destroyed</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWPasswordDialog</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_password.cpp" line="30"/>
+        <source>Password</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWUploadVideoDialog</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="53"/>
+        <source>Upload video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="149"/>
+        <source>Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>KB</name>
+    <message>
+        <location filename="../../../../QTfrontend/KB.h" line="28"/>
+        <source>SDL_ttf returned error while rendering text, most propably it is related to the bug in freetype2. It&apos;s recommended to update your freetype lib.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>LibavInteraction</name>
+    <message>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="281"/>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="293"/>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="297"/>
+        <source>%1 fps, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="301"/>
+        <source>Audio: </source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageAdmin</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="34"/>
+        <source>Fetch data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="38"/>
+        <source>Server message for latest version:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="46"/>
+        <source>Server message for previous versions:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="54"/>
+        <source>Latest version protocol number:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="62"/>
+        <source>MOTD preview:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="71"/>
+        <source>Clear Accounts Cache</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageadmin.cpp" line="74"/>
+        <source>Set data</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageConnecting</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageconnecting.cpp" line="29"/>
+        <source>Connecting...</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageDrawMap</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="32"/>
+        <source>Eraser</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="34"/>
+        <source>Undo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="35"/>
+        <source>Clear</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="36"/>
+        <source>Load</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="37"/>
+        <source>Save</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="61"/>
+        <source>Load drawn map</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="61"/>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="69"/>
+        <source>Drawn Maps</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="61"/>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="69"/>
+        <source>All files</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagedrawmap.cpp" line="69"/>
+        <source>Save drawn map</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageEditTeam</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="45"/>
+        <source>General</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="46"/>
+        <source>Advanced</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageGameStats</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="56"/>
+        <source>Details</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="70"/>
+        <source>Health graph</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="87"/>
+        <source>Ranking</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="173"/>
+        <source>The best shot award was won by &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; pts.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="181"/>
+        <source>The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="188"/>
+        <source>A total of &lt;b&gt;%1&lt;/b&gt; hedgehog(s) were killed during this round.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="252"/>
+        <source>(%1 kill)</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="263"/>
+        <source>&lt;b&gt;%1&lt;/b&gt; thought it&apos;s good to shoot his own hedgehogs with &lt;b&gt;%2&lt;/b&gt; pts.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="271"/>
+        <source>&lt;b&gt;%1&lt;/b&gt; killed &lt;b&gt;%2&lt;/b&gt; of his own hedgehogs.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagegamestats.cpp" line="279"/>
+        <source>&lt;b&gt;%1&lt;/b&gt; was scared and skipped turn &lt;b&gt;%2&lt;/b&gt; times.</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+</context>
+<context>
+    <name>PageInGame</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageingame.cpp" line="29"/>
+        <source>In game...</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageInfo</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageinfo.cpp" line="44"/>
+        <source>Open the snapshot folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageMain</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="45"/>
+        <source>Local Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="46"/>
+        <source>Play a game on a single computer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="50"/>
+        <source>Network Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="51"/>
+        <source>Play a game across a network</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="58"/>
+        <source>Read about who is behind the Hedgewars Project</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="63"/>
+        <source>Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="67"/>
+        <source>Downloadable Content</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="69"/>
+        <source>Access the user created content downloadable from our website</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="89"/>
+        <source>Exit game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="93"/>
+        <source>Manage videos recorded from game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="97"/>
+        <source>Edit game preferences</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="128"/>
+        <source>Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they&apos;ll win or lose together.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="129"/>
+        <source>Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="130"/>
+        <source>If you&apos;re unsure what to do and don&apos;t want to waste ammo, skip one round. But don&apos;t let too much time pass as there will be Sudden Death!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="131"/>
+        <source>Want to save ropes? Release the rope in mid air and then shoot again. As long as you don&apos;t touch the ground you&apos;ll reuse your rope without wasting ammo!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="132"/>
+        <source>If you&apos;d like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="133"/>
+        <source>You&apos;re bored of default gameplay? Try one of the missions - they&apos;ll offer different gameplay depending on the one you picked.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="134"/>
+        <source>By default the game will always record the last game played as a demo. Select &apos;Local Game&apos; and pick the &apos;Demos&apos; button on the lower right corner to play or manage them.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="135"/>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. If you&apos;ve got problems, ask on our forums but please don&apos;t expect 24/7 support!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="136"/>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="137"/>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="138"/>
+        <source>Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="139"/>
+        <source>From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="140"/>
+        <source>Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="141"/>
+        <source>Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="142"/>
+        <source>Always remember you&apos;re able to set up your own games in local and network/online play. You&apos;re not restricted to the &apos;Simple Game&apos; option.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="143"/>
+        <source>Connect one or more gamepads before starting the game to be able to assign their controls to your teams.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="144"/>
+        <source>Create an account on %1 to keep others from using your most favourite nickname while playing on the official server.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="145"/>
+        <source>While playing you should give yourself a short break at least once an hour.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="146"/>
+        <source>If your graphics card isn&apos;t able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="147"/>
+        <source>If your graphics card isn&apos;t able to provide hardware accelerated OpenGL, try to update the associated drivers.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="148"/>
+        <source>We&apos;re open to suggestions and constructive feedback. If you don&apos;t like something or got a great idea, let us know!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="149"/>
+        <source>Especially while playing online be polite and always remember there might be some minors playing with or against you as well!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="150"/>
+        <source>Special game modes such as &apos;Vampirism&apos; or &apos;Karma&apos; allow you to develop completely new tactics. Try them in a custom game!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="151"/>
+        <source>The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="152"/>
+        <source>You should never install Hedgewars on computers you don&apos;t own (school, university, work, etc.). Please ask the responsible person instead!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="153"/>
+        <source>Hedgewars can be perfect for short games during breaks. Just ensure you don&apos;t add too many hedgehogs or use an huge map. Reducing time and health might help as well.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="154"/>
+        <source>No hedgehogs were harmed in making this game.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="155"/>
+        <source>There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="156"/>
+        <source>Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="157"/>
+        <source>Some weapons require special strategies or just lots of training, so don&apos;t give up on a particular tool if you miss an enemy once.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="158"/>
+        <source>Most weapons won&apos;t work once they touch the water. The Homing Bee as well as the Cake are exceptions to this.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="159"/>
+        <source>The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="160"/>
+        <source>The Piano Strike is the most damaging air strike. You&apos;ll lose the hedgehog performing it, so there&apos;s a huge downside as well.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="161"/>
+        <source>The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="162"/>
+        <source>Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="163"/>
+        <source>The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="164"/>
+        <source>If you&apos;re stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="165"/>
+        <source>The Cake&apos;s maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="166"/>
+        <source>The Flame Thrower is a weapon but it can be used for tunnel digging as well.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="167"/>
+        <source>Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="168"/>
+        <source>Want to know who&apos;s behind the game? Click on the Hedgewars logo in the main menu to see the credits.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="169"/>
+        <source>Like Hedgewars? Become a fan on %1 or follow us on %2!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="170"/>
+        <source>Feel free to draw your own graves, hats, flags or even maps and themes! But note that you&apos;ll have to share them somewhere to use them online.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="171"/>
+        <source>Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice!</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="175"/>
+        <source>Keep your video card drivers up to date to avoid issues playing the game.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="176"/>
+        <source>You&apos;re able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="178"/>
+        <source>You can find your Hedgewars configuration files under &quot;My Documents\Hedgewars&quot;. Create backups or take the files with you, but don&apos;t edit them by hand.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="180"/>
+        <source>You can find your Hedgewars configuration files under &quot;Library/Application Support/Hedgewars&quot; in your home directory. Create backups or take the files with you, but don&apos;t edit them by hand.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="182"/>
+        <source>You can find your Hedgewars configuration files under &quot;.hedgewars&quot; in your home directory. Create backups or take the files with you, but don&apos;t edit them by hand.</source>
+        <comment>Tips</comment>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageMultiplayer</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemultiplayer.cpp" line="55"/>
+        <source>Start</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageNetGame</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="84"/>
+        <source>Control</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageNetType</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenettype.cpp" line="35"/>
+        <source>LAN game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenettype.cpp" line="36"/>
+        <source>Join or host your own game server in a Local Area Network.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenettype.cpp" line="37"/>
+        <source>Official server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenettype.cpp" line="38"/>
+        <source>Join hundreds of players online!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageOptions</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="50"/>
+        <source>General</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="51"/>
+        <source>Advanced</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="77"/>
+        <source>New team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="85"/>
+        <source>Edit team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="93"/>
+        <source>Delete team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="101"/>
+        <source>You can&apos;t edit teams from team selection. Go back to main menu to add, edit or delete teams.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="127"/>
+        <source>New scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="134"/>
+        <source>Edit scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="141"/>
+        <source>Delete scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="155"/>
+        <source>New weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="162"/>
+        <source>Edit weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="169"/>
+        <source>Delete weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="405"/>
+        <source>Reset to default colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="454"/>
+        <source>Proxy host</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="455"/>
+        <source>Proxy port</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="456"/>
+        <source>Proxy login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="457"/>
+        <source>Proxy password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="468"/>
+        <source>No proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="469"/>
+        <source>System proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="470"/>
+        <source>Socks5 proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="471"/>
+        <source>HTTP proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PagePlayDemo</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="137"/>
+        <source>Rename dialog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="137"/>
+        <source>Enter new file name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageRoomsList</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="44"/>
+        <source>Room Name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="71"/>
+        <source>Rules:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="79"/>
+        <source>Weapons:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="87"/>
+        <source>Search:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="102"/>
+        <source>Create</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="103"/>
+        <source>Join</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="104"/>
+        <source>Clear</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="129"/>
+        <source>Admin features</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="492"/>
+        <source>%1 players online</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+</context>
+<context>
+    <name>PageScheme</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="72"/>
+        <source>Defend your fort and destroy the opponents, two team colours max!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="77"/>
+        <source>Teams will start on opposite sides of the terrain, two team colours max!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="82"/>
+        <source>Land can not be destroyed!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="87"/>
+        <source>Add an indestructible border around the terrain</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="92"/>
+        <source>Lower gravity</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="97"/>
+        <source>Assisted aiming with laser sight</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="102"/>
+        <source>All hogs have a personal forcefield</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="107"/>
+        <source>All (living) hedgehogs are fully restored at the end of turn</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="112"/>
+        <source>Gain 80% of the damage you do back in health</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="117"/>
+        <source>Share your opponents pain, share their damage</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="122"/>
+        <source>Your hogs are unable to move, put your artillery skills to the test</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="127"/>
+        <source>Order of play is random instead of in room order.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="132"/>
+        <source>Play with a King. If he dies, your side dies.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="137"/>
+        <source>Take turns placing your hedgehogs before the start of play.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="142"/>
+        <source>Ammo is shared between all teams that share a colour.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="147"/>
+        <source>Disable girders when generating random maps.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="152"/>
+        <source>Disable land objects when generating random maps.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="157"/>
+        <source>AI respawns on death.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="162"/>
+        <source>Attacking does not end your turn.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="167"/>
+        <source>Weapons are reset to starting values each turn.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="172"/>
+        <source>Each hedgehog has its own ammo. It does not share with the team.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="177"/>
+        <source>You will not have to worry about wind anymore.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="182"/>
+        <source>Wind will affect almost everything.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="187"/>
+        <source>Teams in each clan take successive turns sharing their turn time.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="192"/>
+        <source>Add an indestructible border along the bottom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="350"/>
+        <source>Random</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="351"/>
+        <source>Seconds</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="427"/>
+        <source>Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="428"/>
+        <source>New</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="429"/>
+        <source>Delete</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageSelectWeapon</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageselectweapon.cpp" line="46"/>
+        <source>New</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageselectweapon.cpp" line="47"/>
+        <source>Default</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageselectweapon.cpp" line="50"/>
+        <source>Copy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageselectweapon.cpp" line="51"/>
+        <source>Delete</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageSinglePlayer</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="39"/>
+        <source>Simple Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="40"/>
+        <source>Play a quick game against the computer with random settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="43"/>
+        <source>Multiplayer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="44"/>
+        <source>Play a hotseat game against your friends, or AI teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="49"/>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="50"/>
+        <source>Campaign Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="54"/>
+        <source>Training Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="55"/>
+        <source>Practice your skills in a range of training missions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="66"/>
+        <source>Demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="67"/>
+        <source>Watch recorded demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="70"/>
+        <source>Load</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagesingleplayer.cpp" line="71"/>
+        <source>Load a previously saved game</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageTraining</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagetraining.cpp" line="78"/>
+        <source>Pick the mission or training to play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagetraining.cpp" line="93"/>
+        <source>Start fighting</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagetraining.cpp" line="211"/>
+        <source>No description available</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagetraining.cpp" line="219"/>
+        <source>Select a mission!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageVideos</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="234"/>
+        <source>Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="235"/>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="498"/>
+        <source>%1 bytes</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="742"/>
+        <source>(in progress...)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="746"/>
+        <source>Date: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="747"/>
+        <source>Size: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="966"/>
+        <source>encoding</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="968"/>
+        <source>uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QAction</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="79"/>
+        <source>Update</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="87"/>
+        <source>Start</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="107"/>
+        <source>Restrict Joins</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="109"/>
+        <source>Restrict Team Additions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="248"/>
+        <source>Info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="252"/>
+        <source>Kick</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="256"/>
+        <source>Ban</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="260"/>
+        <source>Follow</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="264"/>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="865"/>
+        <source>Ignore</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="268"/>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="877"/>
+        <source>Add friend</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="860"/>
+        <source>Unignore</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/chatwidget.cpp" line="872"/>
+        <source>Remove friend</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QCheckBox</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_password.cpp" line="43"/>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="231"/>
+        <source>Save password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="95"/>
+        <source>Save account name and password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="131"/>
+        <source>Video is private</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="241"/>
+        <source>Check for updates at startup</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="261"/>
+        <source>Frontend fullscreen</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="265"/>
+        <source>Frontend effects</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="269"/>
+        <source>Enable frontend sounds</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="273"/>
+        <source>Enable frontend music</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="291"/>
+        <source>Fullscreen</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="349"/>
+        <source>Enable sound</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="353"/>
+        <source>Enable music</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="365"/>
+        <source>Alternative damage show</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="424"/>
+        <source>Show FPS</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="431"/>
+        <source>Show ammo menu tooltips</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="436"/>
+        <source>Append date and time to record file name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="151"/>
+        <source>Record audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="192"/>
+        <source>Use game resolution</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QComboBox</name>
+    <message>
+        <location filename="../../../../QTfrontend/model/MapModel.cpp" line="50"/>
+        <source>generated map...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/MapModel.cpp" line="52"/>
+        <source>generated maze...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/MapModel.cpp" line="54"/>
+        <source>hand drawn map...</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/MapModel.cpp" line="116"/>
+        <source>Mission</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="115"/>
+        <source>Human</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="119"/>
+        <source>Level</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="323"/>
+        <source>Community</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="199"/>
+        <source>(System default)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="312"/>
+        <source>Disabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="313"/>
+        <source>Red/Cyan</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="314"/>
+        <source>Cyan/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="315"/>
+        <source>Red/Blue</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="316"/>
+        <source>Blue/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="317"/>
+        <source>Red/Green</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="318"/>
+        <source>Green/Red</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="319"/>
+        <source>Side-by-side</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="320"/>
+        <source>Top-Bottom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="321"/>
+        <source>Wiggle</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="322"/>
+        <source>Red/Cyan grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="323"/>
+        <source>Cyan/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="324"/>
+        <source>Red/Blue grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="325"/>
+        <source>Blue/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="326"/>
+        <source>Red/Green grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="327"/>
+        <source>Green/Red grayscale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="111"/>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="112"/>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="176"/>
+        <source>Any</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="113"/>
+        <source>In lobby</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="114"/>
+        <source>In progress</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QGroupBox</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="60"/>
+        <source>Team Members</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="89"/>
+        <source>Team Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="143"/>
+        <source>Fort</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="162"/>
+        <source>Key binds</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="40"/>
+        <source>Net game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="69"/>
+        <source>Teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="116"/>
+        <source>Schemes and Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="184"/>
+        <source>Misc</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="253"/>
+        <source>Audio/Graphic options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="381"/>
+        <source>Custom colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="412"/>
+        <source>Miscellaneous</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="448"/>
+        <source>Proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="48"/>
+        <source>Game Modifiers</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="49"/>
+        <source>Basic Settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="120"/>
+        <source>Video recording options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="231"/>
+        <source>Videos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="267"/>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/teamselect.cpp" line="253"/>
+        <source>Playing teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QLabel</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/ask_quit.cpp" line="38"/>
+        <source>There are videos that are currently being processed.
+Exiting now will abort them.
+Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="32"/>
+        <source>Host:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="36"/>
+        <source>Port:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="74"/>
+        <source>Please provide either the YouTube account name or the email address associated with the Google Account.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="80"/>
+        <source>Account name (or email): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="87"/>
+        <source>Password: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="105"/>
+        <source>Video title: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="114"/>
+        <source>Video description: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="121"/>
+        <source>Tags (comma separated): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="93"/>
+        <source>Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="96"/>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="99"/>
+        <source>Grave</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="102"/>
+        <source>Flag</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="105"/>
+        <source>Voice</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagefeedback.cpp" line="45"/>
+        <source>Summary   </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagefeedback.cpp" line="52"/>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="116"/>
+        <source>Tip: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemain.cpp" line="120"/>
+        <source>This development build is &apos;work in progress&apos; and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetserver.cpp" line="51"/>
+        <source>Server name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetserver.cpp" line="58"/>
+        <source>Server port:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="120"/>
+        <source>Game scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="148"/>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="86"/>
+        <source>Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="189"/>
+        <source>Locale</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="221"/>
+        <source>Nickname</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="283"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="172"/>
+        <source>Resolution</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="295"/>
+        <source>Quality</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="308"/>
+        <source>Stereo rendering</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="340"/>
+        <source>Initial sound volume</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="418"/>
+        <source>FPS limit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="200"/>
+        <source>Damage Modifier</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="214"/>
+        <source>Turn Time</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="228"/>
+        <source>Initial Health</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="242"/>
+        <source>Sudden Death Timeout</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="256"/>
+        <source>Sudden Death Water Rise</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="270"/>
+        <source>Sudden Death Health Decrease</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="284"/>
+        <source>% Rope Length</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="298"/>
+        <source>Crate Drops</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="311"/>
+        <source>% Health Crates</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="325"/>
+        <source>Health in Crates</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="339"/>
+        <source>Mines Time</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="355"/>
+        <source>Mines</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="369"/>
+        <source>% Dud Mines</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="383"/>
+        <source>Explosives</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="397"/>
+        <source>% Get Away Time</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="411"/>
+        <source>Scheme Name:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="125"/>
+        <source>Format</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="142"/>
+        <source>Audio codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="163"/>
+        <source>Video codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="197"/>
+        <source>Framerate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="208"/>
+        <source>Bitrate (Kbps)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="53"/>
+        <source>Version</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="55"/>
+        <source>This program is distributed under the GNU General Public License v2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="70"/>
+        <source>Developers:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="94"/>
+        <source>Art:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="112"/>
+        <source>Sounds:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="122"/>
+        <source>Translations:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="146"/>
+        <source>Special thanks:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="55"/>
+        <source>Style</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="74"/>
+        <source>Scheme</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QLineEdit</name>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="879"/>
+        <source>unnamed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/team.cpp" line="42"/>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="335"/>
+        <source>hedgehog %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="226"/>
+        <source>anonymous</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QMainWindow</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui_hwform.cpp" line="59"/>
+        <source>Hedgewars %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QMessageBox</name>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="901"/>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="388"/>
+        <source>Teams - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="902"/>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="389"/>
+        <source>Do you really want to delete the team &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="918"/>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="525"/>
+        <source>Cannot delete default scheme &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="944"/>
+        <source>Please select a record from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1238"/>
+        <source>Unable to start server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1282"/>
+        <source>Connection to server is lost</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1394"/>
+        <source>Hedgewars - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1694"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1785"/>
+        <source>Hedgewars - Success</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1695"/>
+        <source>All file associations have been set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1700"/>
+        <source>File association failed.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1736"/>
+        <source>Please fill out all fields</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1786"/>
+        <source>Successfully posted the issue on hedgewars.googlecode.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1798"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1811"/>
+        <source>Error during authentication at google.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1814"/>
+        <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/main.cpp" line="96"/>
+        <location filename="../../../../QTfrontend/main.cpp" line="212"/>
+        <source>Main - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/main.cpp" line="97"/>
+        <source>Cannot create directory %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/main.cpp" line="213"/>
+        <source>Failed to open data directory:
+%1
+
+Please check your installation!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/tcpBase.cpp" line="50"/>
+        <location filename="../../../../QTfrontend/net/tcpBase.cpp" line="122"/>
+        <source>TCP - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/tcpBase.cpp" line="51"/>
+        <source>Unable to start the server: %1.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/tcpBase.cpp" line="123"/>
+        <source>Unable to run engine at </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/net/tcpBase.cpp" line="124"/>
+        <source>Error code: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="232"/>
+        <source>Error while authenticating at google.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="234"/>
+        <source>Login or password is incorrect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="240"/>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="302"/>
+        <source>Video upload - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/upload_video.cpp" line="297"/>
+        <source>Error while sending metadata to youtube.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="113"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="157"/>
+        <source>Netgame - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="114"/>
+        <source>Please select a server from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="158"/>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="431"/>
+        <source>Please enter room name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="125"/>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="152"/>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="169"/>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="184"/>
+        <source>Record Play - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="126"/>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="170"/>
+        <source>Please select record from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="153"/>
+        <source>Cannot rename to </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="185"/>
+        <source>Cannot delete file </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="430"/>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="445"/>
+        <source>Room Name - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="446"/>
+        <source>Please select room from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="479"/>
+        <source>Room Name - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="480"/>
+        <source>The game you are trying to join has started.
+Do you still want to join the room?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="524"/>
+        <source>Schemes - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="533"/>
+        <source>Schemes - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="534"/>
+        <source>Do you really want to delete the game scheme &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="850"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="879"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1104"/>
+        <source>Videos - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="851"/>
+        <source>Do you really want to delete the video &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="880"/>
+        <source>Do you really want to remove %1 file(s)?</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1105"/>
+        <source>Do you really want to cancel uploading %1?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/drawmapwidget.cpp" line="101"/>
+        <location filename="../../../../QTfrontend/ui/widget/drawmapwidget.cpp" line="121"/>
+        <source>File error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/drawmapwidget.cpp" line="102"/>
+        <source>Cannot open &apos;%1&apos; for writing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/drawmapwidget.cpp" line="122"/>
+        <source>Cannot open &apos;%1&apos; for reading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="276"/>
+        <source>Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/gamecfgwidget.cpp" line="277"/>
+        <source>Cannot use the ammo &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="229"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="266"/>
+        <source>Weapons - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="230"/>
+        <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="267"/>
+        <source>Cannot delete default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="275"/>
+        <source>Weapons - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="276"/>
+        <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1200"/>
+        <source>Nickname</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1201"/>
+        <source>Please enter your nickname</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>QPushButton</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/ask_quit.cpp" line="50"/>
+        <source>More info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="48"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetserver.cpp" line="67"/>
+        <source>default</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="52"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="57"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="735"/>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagecampaign.cpp" line="44"/>
+        <location filename="../../../../QTfrontend/ui/page/pagetraining.cpp" line="92"/>
+        <source>Go!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="84"/>
+        <source>Random Team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagemultiplayer.cpp" line="40"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="51"/>
+        <source>Setup</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="49"/>
+        <source>Connect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="58"/>
+        <source>Update</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="63"/>
+        <source>Specify</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="73"/>
+        <source>Start server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="72"/>
+        <source>Ready</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagenetserver.cpp" line="77"/>
+        <source>Start</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageoptions.cpp" line="440"/>
+        <source>Associate file extensions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="45"/>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="87"/>
+        <source>Play demo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="49"/>
+        <source>Rename</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="53"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="303"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="735"/>
+        <source>Delete</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="93"/>
+        <source>Load</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="219"/>
+        <source>Set default options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="220"/>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="253"/>
+        <source>Open videos directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="254"/>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="299"/>
+        <source>Play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="301"/>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="305"/>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="307"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
+        <source>Upload to YouTube</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="309"/>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
+        <source>Cancel uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/mapContainer.cpp" line="170"/>
+        <source>more</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>RoomsListModel</name>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="37"/>
+        <source>In progress</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="38"/>
+        <source>Room Name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="39"/>
+        <source>C</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="40"/>
+        <source>T</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="41"/>
+        <source>Owner</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="42"/>
+        <source>Map</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="43"/>
+        <source>Rules</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="44"/>
+        <source>Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="131"/>
+        <source>Random Map</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="132"/>
+        <source>Random Maze</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/model/roomslistmodel.cpp" line="133"/>
+        <source>Hand-drawn</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>SelWeaponWidget</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="119"/>
+        <source>Weapon set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="120"/>
+        <source>Probabilities</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="121"/>
+        <source>Ammo in boxes</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="122"/>
+        <source>Delays</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="289"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="294"/>
+        <source>new</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="325"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="330"/>
+        <source>copy of</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>ToggleButtonWidget</name>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="71"/>
+        <source>Fort Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="76"/>
+        <source>Divide Teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="81"/>
+        <source>Solid Land</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="86"/>
+        <source>Add Border</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="91"/>
+        <source>Low Gravity</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="96"/>
+        <source>Laser Sight</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="101"/>
+        <source>Invulnerable</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="106"/>
+        <source>Reset Health</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="111"/>
+        <source>Vampirism</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="116"/>
+        <source>Karma</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="121"/>
+        <source>Artillery</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="126"/>
+        <source>Random Order</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="131"/>
+        <source>King</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="136"/>
+        <source>Place Hedgehogs</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="141"/>
+        <source>Clan Shares Ammo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="146"/>
+        <source>Disable Girders</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="151"/>
+        <source>Disable Land Objects</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="156"/>
+        <source>AI Survival Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="161"/>
+        <source>Unlimited Attacks</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="166"/>
+        <source>Reset Weapons</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="171"/>
+        <source>Per Hedgehog Ammo</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="176"/>
+        <source>Disable Wind</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="181"/>
+        <source>More Wind</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="186"/>
+        <source>Tag Team</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="191"/>
+        <source>Add Bottom Border</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds</name>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="23"/>
+        <location filename="../../../../QTfrontend/binds.cpp" line="50"/>
+        <source>up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="24"/>
+        <location filename="../../../../QTfrontend/binds.cpp" line="51"/>
+        <source>left</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="25"/>
+        <location filename="../../../../QTfrontend/binds.cpp" line="52"/>
+        <source>right</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="26"/>
+        <location filename="../../../../QTfrontend/binds.cpp" line="53"/>
+        <source>down</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="27"/>
+        <source>precise aim</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="28"/>
+        <source>long jump</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="29"/>
+        <source>high jump</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="30"/>
+        <source>attack</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="31"/>
+        <source>put</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="32"/>
+        <source>switch</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="33"/>
+        <source>ammo menu</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="34"/>
+        <source>slot 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="35"/>
+        <source>slot 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="36"/>
+        <source>slot 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="37"/>
+        <source>slot 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="38"/>
+        <source>slot 5</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="39"/>
+        <source>slot 6</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="40"/>
+        <source>slot 7</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="41"/>
+        <source>slot 8</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="42"/>
+        <source>slot 9</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="43"/>
+        <source>slot 10</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="44"/>
+        <source>timer 1 sec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="45"/>
+        <source>timer 2 sec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="46"/>
+        <source>timer 3 sec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="47"/>
+        <source>timer 4 sec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="48"/>
+        <source>timer 5 sec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="49"/>
+        <source>find hedgehog</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="55"/>
+        <source>zoom in</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="56"/>
+        <source>zoom out</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="57"/>
+        <source>reset zoom</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="58"/>
+        <source>chat</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="59"/>
+        <source>chat history</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="60"/>
+        <source>pause</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="61"/>
+        <source>quit</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="62"/>
+        <source>confirmation</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="63"/>
+        <source>volume down</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="64"/>
+        <source>volume up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="65"/>
+        <source>mute audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="66"/>
+        <source>change mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="67"/>
+        <source>capture</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="68"/>
+        <source>hedgehogs
+info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="69"/>
+        <source>record</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds (categories)</name>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="23"/>
+        <source>Basic controls</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="33"/>
+        <source>Weapon controls</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="49"/>
+        <source>Camera and cursor controls</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="58"/>
+        <source>Other</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds (descriptions)</name>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="23"/>
+        <source>Move your hogs and aim:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="28"/>
+        <source>Traverse gaps and obstacles by jumping:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="30"/>
+        <source>Fire your selected weapon or trigger an utility item:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="31"/>
+        <source>Pick a weapon or a target location under the cursor:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="32"/>
+        <source>Switch your currently active hog (if possible):</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="33"/>
+        <source>Pick a weapon or utility item:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="44"/>
+        <source>Set the timer on bombs and timed weapons:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="49"/>
+        <source>Move the camera to the active hog:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="50"/>
+        <source>Move the cursor or camera without using the mouse:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="55"/>
+        <source>Modify the camera&apos;s zoom level:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="58"/>
+        <source>Talk to your team or all participants:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="60"/>
+        <source>Pause, continue or leave your game:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="63"/>
+        <source>Modify the game&apos;s volume while playing:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="66"/>
+        <source>Toggle fullscreen mode:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="67"/>
+        <source>Take a screenshot:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="68"/>
+        <source>Toggle labels above hedgehogs:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/binds.cpp" line="69"/>
+        <source>Record video:</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>binds (keys)</name>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="21"/>
+        <source>Mouse: Left button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="22"/>
+        <source>Mouse: Middle button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="23"/>
+        <source>Mouse: Right button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="24"/>
+        <source>Mouse: Wheel up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="25"/>
+        <source>Mouse: Wheel down</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="26"/>
+        <source>Backspace</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="27"/>
+        <source>Tab</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="28"/>
+        <source>Clear</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="29"/>
+        <source>Return</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="30"/>
+        <source>Pause</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="31"/>
+        <source>Escape</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="32"/>
+        <source>Space</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="96"/>
+        <source>Delete</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="97"/>
+        <source>Numpad 0</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="98"/>
+        <source>Numpad 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="99"/>
+        <source>Numpad 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="100"/>
+        <source>Numpad 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="101"/>
+        <source>Numpad 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="102"/>
+        <source>Numpad 5</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="103"/>
+        <source>Numpad 6</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="104"/>
+        <source>Numpad 7</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="105"/>
+        <source>Numpad 8</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="106"/>
+        <source>Numpad 9</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="107"/>
+        <source>Numpad .</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="108"/>
+        <source>Numpad /</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="109"/>
+        <source>Numpad *</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="110"/>
+        <source>Numpad -</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="111"/>
+        <source>Numpad +</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="112"/>
+        <source>Enter</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="113"/>
+        <source>Equals</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="114"/>
+        <source>Up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="115"/>
+        <source>Down</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="116"/>
+        <source>Right</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="117"/>
+        <source>Left</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="118"/>
+        <source>Insert</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="119"/>
+        <source>Home</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="120"/>
+        <source>End</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="121"/>
+        <source>Page up</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="122"/>
+        <source>Page down</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="138"/>
+        <source>Num lock</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="139"/>
+        <source>Caps lock</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="140"/>
+        <source>Scroll lock</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="141"/>
+        <source>Right shift</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="142"/>
+        <source>Left shift</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="143"/>
+        <source>Right ctrl</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="144"/>
+        <source>Left ctrl</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="145"/>
+        <source>Right alt</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="146"/>
+        <source>Left alt</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="147"/>
+        <source>Right meta</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="148"/>
+        <source>Left meta</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="155"/>
+        <source>A button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="156"/>
+        <source>B button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="157"/>
+        <source>X button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="158"/>
+        <source>Y button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="159"/>
+        <source>LB button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="160"/>
+        <source>RB button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="161"/>
+        <source>Back button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="162"/>
+        <source>Start button</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="163"/>
+        <source>Left stick</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="164"/>
+        <source>Right stick</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="171"/>
+        <source>Left stick (Right)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="172"/>
+        <source>Left stick (Left)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="173"/>
+        <source>Left stick (Down)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="174"/>
+        <source>Left stick (Up)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="175"/>
+        <source>Left trigger</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="176"/>
+        <source>Right trigger</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="177"/>
+        <source>Right stick (Down)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="178"/>
+        <source>Right stick (Up)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="179"/>
+        <source>Right stick (Right)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="180"/>
+        <source>Right stick (Left)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/sdlkeys.h" line="182"/>
+        <source>DPad</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/DataManager.cpp" line="193"/>
+        <source>Keyboard</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="129"/>
+        <source>Axis</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="133"/>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="148"/>
+        <source>(Up)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="137"/>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="152"/>
+        <source>(Down)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="144"/>
+        <source>Hat</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="156"/>
+        <source>(Left)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="160"/>
+        <source>(Right)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/util/SDLInteraction.cpp" line="168"/>
+        <source>Button</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+</TS>
--- a/share/hedgewars/Data/Locale/hedgewars_nl.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_nl.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -341,7 +341,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -828,14 +828,6 @@
         <source>Control</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2146,6 +2138,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_pl.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_pl.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -346,23 +346,43 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished">Długość: %1m %2s </translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished">Wideo: %1x%2, </translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished">%1 kl/s, </translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished">Audio: </translation>
+    </message>
+</context>
+<context>
     <name>LibavIteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
-        <translation>Długość: %1m %2s </translation>
+        <translation type="obsolete">Długość: %1m %2s </translation>
     </message>
     <message>
         <source>Video: %1x%2, </source>
-        <translation>Wideo: %1x%2, </translation>
+        <translation type="obsolete">Wideo: %1x%2, </translation>
     </message>
     <message>
         <source>%1 fps, </source>
-        <translation>%1 kl/s, </translation>
+        <translation type="obsolete">%1 kl/s, </translation>
     </message>
     <message>
         <source>Audio: </source>
-        <translation>Audio: </translation>
+        <translation type="obsolete">Audio: </translation>
     </message>
 </context>
 <context>
@@ -841,11 +861,11 @@
     </message>
     <message>
         <source>DLC</source>
-        <translation>DLC</translation>
+        <translation type="obsolete">DLC</translation>
     </message>
     <message>
         <source>Downloadable Content</source>
-        <translation>Dodatki</translation>
+        <translation type="obsolete">Dodatki</translation>
     </message>
 </context>
 <context>
@@ -2167,6 +2187,26 @@
         <source>Cancel uploading</source>
         <translation>Anuluj wysyłanie</translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_pt_BR.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_pt_BR.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -345,7 +345,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -833,14 +833,6 @@
         <source>Control</source>
         <translation>Controle</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2152,6 +2144,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_pt_PT.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_pt_PT.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -345,22 +345,42 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
-    <message>
-        <source>Duration: %1m %2s</source>
-        <translation>Duração: %1m %2s</translation>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <source>Video: %1x%2, </source>
-        <translation>Vídeo:  %1x%2, </translation>
+        <translation type="unfinished">Vídeo:  %1x%2, </translation>
     </message>
     <message>
         <source>%1 fps, </source>
-        <translation>%1 fps, </translation>
+        <translation type="unfinished">%1 fps, </translation>
     </message>
     <message>
         <source>Audio: </source>
-        <translation>Audio: </translation>
+        <translation type="unfinished">Audio: </translation>
+    </message>
+</context>
+<context>
+    <name>LibavIteraction</name>
+    <message>
+        <source>Duration: %1m %2s</source>
+        <translation type="obsolete">Duração: %1m %2s</translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="obsolete">Vídeo:  %1x%2, </translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="obsolete">%1 fps, </translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="obsolete">Audio: </translation>
     </message>
 </context>
 <context>
@@ -833,11 +853,11 @@
     </message>
     <message>
         <source>DLC</source>
-        <translation>DLC</translation>
+        <translation type="obsolete">DLC</translation>
     </message>
     <message>
         <source>Downloadable Content</source>
-        <translation>Conteúdo Transferível</translation>
+        <translation type="obsolete">Conteúdo Transferível</translation>
     </message>
 </context>
 <context>
@@ -2157,6 +2177,26 @@
         <source>Cancel uploading</source>
         <translation>Cancelar o upload</translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_ro.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_ro.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -2,6 +2,13 @@
 <!DOCTYPE TS>
 <TS version="2.0" language="ro">
 <context>
+    <name>AbstractPage</name>
+    <message>
+        <source>Go back</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>AmmoSchemeModel</name>
     <message>
         <source>new</source>
@@ -13,21 +20,6 @@
     </message>
 </context>
 <context>
-    <name>DrawMapWidget</name>
-    <message>
-        <source>File error</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Cannot open file &apos;%1&apos; for writing</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Cannot read file &apos;%1&apos;</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
-<context>
     <name>FreqSpinBox</name>
     <message>
         <source>Never</source>
@@ -38,6 +30,7 @@
         <translation>
             <numerusform>Each turn</numerusform>
             <numerusform>Every %1 turns</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
 </context>
@@ -49,11 +42,11 @@
     </message>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>Illegal ammo scheme</source>
-        <translation>Illegal ammo scheme</translation>
+        <translation type="obsolete">Illegal ammo scheme</translation>
     </message>
     <message>
         <source>Edit schemes</source>
@@ -69,6 +62,13 @@
     </message>
 </context>
 <context>
+    <name>HWAskQuitDialog</name>
+    <message>
+        <source>Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>HWChatWidget</name>
     <message>
         <source>%1 *** %2 has been removed from your ignore list</source>
@@ -130,10 +130,6 @@
         <source>%1 is not a valid command!</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <source>Kicking %1 ...</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>HWForm</name>
@@ -143,15 +139,15 @@
     </message>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Unable to start the server</source>
-        <translation>Unable to start the server</translation>
+        <translation type="obsolete">Unable to start the server</translation>
     </message>
     <message>
         <source>Cannot save record to file %1</source>
@@ -159,7 +155,7 @@
     </message>
     <message>
         <source>Please select record from the list above</source>
-        <translation>Please select record from the list above</translation>
+        <translation type="obsolete">Please select record from the list above</translation>
     </message>
     <message>
         <source>DefaultTeam</source>
@@ -189,7 +185,7 @@
     </message>
     <message>
         <source>Password</source>
-        <translation type="unfinished">Password</translation>
+        <translation type="obsolete">Password</translation>
     </message>
     <message>
         <source>Your nickname %1 is
@@ -210,16 +206,14 @@
         <translation type="unfinished">Nickname</translation>
     </message>
     <message>
-        <source>Some one already uses
- your nickname %1
-on the server.
+        <source>No nickname supplied.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Someone already uses your nickname %1 on the server.
 Please pick another nickname:</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <source>No nickname supplied.</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>HWGame</name>
@@ -392,6 +386,32 @@
         <source>User quit</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Remote host has closed connection</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The server is too old. Disconnecting now.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>HWPasswordDialog</name>
+    <message>
+        <source>Password</source>
+        <translation type="unfinished">Password</translation>
+    </message>
+</context>
+<context>
+    <name>HWUploadVideoDialog</name>
+    <message>
+        <source>Upload video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>KB</name>
@@ -401,6 +421,26 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageAdmin</name>
     <message>
         <source>Server message:</source>
@@ -484,6 +524,10 @@
         <source>All files</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Eraser</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageEditTeam</name>
@@ -507,6 +551,7 @@
         <translation type="obsolete">
             <numerusform>&lt;p&gt;The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kill in a turn.&lt;/p&gt;</numerusform>
             <numerusform>&lt;p&gt;The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.&lt;/p&gt;</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -514,6 +559,7 @@
         <translation type="obsolete">
             <numerusform>&lt;p&gt;A total of &lt;b&gt;%1&lt;/b&gt; hedgehog was killed during this round.&lt;/p&gt;</numerusform>
             <numerusform>&lt;p&gt;A total of &lt;b&gt;%1&lt;/b&gt; hedgehogs were killed during this round.&lt;/p&gt;</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message>
@@ -537,6 +583,7 @@
         <translation>
             <numerusform>The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kill in a turn.</numerusform>
             <numerusform>The best killer is &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; kills in a turn.</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -544,6 +591,7 @@
         <translation>
             <numerusform>&lt;b&gt;%1&lt;/b&gt; hedgehog was killed during this round.</numerusform>
             <numerusform>A total of &lt;b&gt;%1&lt;/b&gt; hedgehogs were killed during this round.</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -551,6 +599,7 @@
         <translation>
             <numerusform>(%1 kill)</numerusform>
             <numerusform>(%1 kills)</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -558,6 +607,7 @@
         <translation type="unfinished">
             <numerusform></numerusform>
             <numerusform></numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -565,6 +615,7 @@
         <translation type="unfinished">
             <numerusform></numerusform>
             <numerusform></numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -572,6 +623,7 @@
         <translation>
             <numerusform>&lt;b&gt;%1&lt;/b&gt; was scared and skipped turn &lt;b&gt;%2&lt;/b&gt; time.</numerusform>
             <numerusform>&lt;b&gt;%1&lt;/b&gt; was scared and skipped turn &lt;b&gt;%2&lt;/b&gt; times.</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
 </context>
@@ -583,14 +635,21 @@
     </message>
 </context>
 <context>
+    <name>PageInfo</name>
+    <message>
+        <source>Open the snapshot folder</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>PageMain</name>
     <message>
         <source>Local Game (Play a game on a single computer)</source>
-        <translation>Local Game (Play a game on a single computer)</translation>
+        <translation type="obsolete">Local Game (Play a game on a single computer)</translation>
     </message>
     <message>
         <source>Network Game (Play a game across a network)</source>
-        <translation>Network Game (Play a game across a network)</translation>
+        <translation type="obsolete">Network Game (Play a game across a network)</translation>
     </message>
     <message>
         <source>Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they&apos;ll win or lose together.</source>
@@ -841,6 +900,46 @@
         <source>Downloadable Content</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Local Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game on a single computer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Network Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a game across a network</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Read about who is behind the Hedgewars Project</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Access the user created content downloadable from our website</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Exit game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Manage videos recorded from game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Edit game preferences</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageMultiplayer</name>
@@ -853,11 +952,11 @@
     <name>PageNet</name>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>Please select server from the list above</source>
-        <translation>Please select server from the list above</translation>
+        <translation type="obsolete">Please select server from the list above</translation>
     </message>
 </context>
 <context>
@@ -868,15 +967,15 @@
     </message>
     <message>
         <source>Error</source>
-        <translation type="unfinished">Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>Please enter room name</source>
-        <translation type="unfinished">Please enter room name</translation>
+        <translation type="obsolete">Please enter room name</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation type="unfinished">OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
 </context>
 <context>
@@ -889,6 +988,14 @@
         <source>Official server</source>
         <translation>Official server</translation>
     </message>
+    <message>
+        <source>Join or host your own game server in a Local Area Network.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Join hundreds of players online!</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PageOptions</name>
@@ -944,16 +1051,60 @@
         <source>Delete weapon set</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>General</source>
+        <translation type="unfinished">General</translation>
+    </message>
+    <message>
+        <source>Advanced</source>
+        <translation type="unfinished">Advanced</translation>
+    </message>
+    <message>
+        <source>Reset to default colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy host</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy port</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy login</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>No proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>System proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Socks5 proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HTTP proxy</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>PagePlayDemo</name>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Rename dialog</source>
@@ -965,15 +1116,15 @@
     </message>
     <message>
         <source>Cannot rename to</source>
-        <translation>Cannot rename to</translation>
+        <translation type="obsolete">Cannot rename to</translation>
     </message>
     <message>
         <source>Cannot delete file</source>
-        <translation>Cannot delete file</translation>
+        <translation type="obsolete">Cannot delete file</translation>
     </message>
     <message>
         <source>Please select record from the list</source>
-        <translation>Please select record from the list</translation>
+        <translation type="obsolete">Please select record from the list</translation>
     </message>
 </context>
 <context>
@@ -988,15 +1139,15 @@
     </message>
     <message>
         <source>Refresh</source>
-        <translation>Refresh</translation>
+        <translation type="obsolete">Refresh</translation>
     </message>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Admin features</source>
@@ -1009,60 +1160,58 @@
     <message>
         <source>This game is in lobby.
 You may join and start playing once the game starts.</source>
-        <translation>This game is in lobby.
+        <translation type="obsolete">This game is in lobby.
 You may join and start playing once the game starts.</translation>
     </message>
     <message>
         <source>This game is in progress.
 You may join and spectate now but you&apos;ll have to wait for the game to end to start playing.</source>
-        <translation>This game is in progress.
+        <translation type="obsolete">This game is in progress.
 You may join and spectate now but you&apos;ll have to wait for the game to end to start playing.</translation>
     </message>
     <message>
         <source>%1 is the host. He may adjust settings and start the game.</source>
-        <translation>%1 is the host. He may adjust settings and start the game.</translation>
+        <translation type="obsolete">%1 is the host. He may adjust settings and start the game.</translation>
     </message>
     <message>
         <source>Random Map</source>
-        <translation>Random Map</translation>
+        <translation type="obsolete">Random Map</translation>
     </message>
     <message>
         <source>Games may be played on precreated or randomized maps.</source>
-        <translation>Games may be played on precreated or randomized maps.</translation>
+        <translation type="obsolete">Games may be played on precreated or randomized maps.</translation>
     </message>
     <message>
         <source>The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</source>
-        <translation>The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</translation>
+        <translation type="obsolete">The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism.</translation>
     </message>
     <message>
         <source>The Weapon Scheme defines available weapons and their ammunition count.</source>
-        <translation>The Weapon Scheme defines available weapons and their ammunition count.</translation>
+        <translation type="obsolete">The Weapon Scheme defines available weapons and their ammunition count.</translation>
     </message>
     <message numerus="yes">
         <source>There are %1 clients connected to this room.</source>
-        <translation>
+        <translation type="obsolete">
             <numerusform>There is %1 client connected to this room.</numerusform>
             <numerusform>There are %1 clients connected to this room.</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
         <source>There are %1 teams participating in this room.</source>
-        <translation>
+        <translation type="obsolete">
             <numerusform>There is %1 team participating in this room.</numerusform>
             <numerusform>There are %1 teams participating in this room.</numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message>
         <source>Please enter room name</source>
-        <translation>Please enter room name</translation>
+        <translation type="obsolete">Please enter room name</translation>
     </message>
     <message>
         <source>Please select room from the list</source>
-        <translation>Please select room from the list</translation>
-    </message>
-    <message>
-        <source>Random Maze</source>
-        <translation type="unfinished"></translation>
+        <translation type="obsolete">Please select room from the list</translation>
     </message>
     <message>
         <source>Rules:</source>
@@ -1081,13 +1230,9 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Warning</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>The game you are trying to join has started.
 Do you still want to join the room?</source>
-        <translation>The game you are trying to join has started.
+        <translation type="obsolete">The game you are trying to join has started.
 Do you still want to join the room?</translation>
     </message>
     <message numerus="yes">
@@ -1095,6 +1240,7 @@
         <translation type="unfinished">
             <numerusform></numerusform>
             <numerusform></numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
 </context>
@@ -1252,26 +1398,66 @@
     <name>PageSinglePlayer</name>
     <message>
         <source>Simple Game (a quick game against the computer, settings are chosen for you)</source>
-        <translation>Simple Game (a quick game against the computer, settings are chosen for you)</translation>
+        <translation type="obsolete">Simple Game (a quick game against the computer, settings are chosen for you)</translation>
     </message>
     <message>
         <source>Multiplayer (play a hotseat game against your friends, or AI teams)</source>
-        <translation>Multiplayer (play a hotseat game against your friends, or AI teams)</translation>
+        <translation type="obsolete">Multiplayer (play a hotseat game against your friends, or AI teams)</translation>
     </message>
     <message>
         <source>Training Mode (Practice your skills in a range of training missions)</source>
-        <translation>Training Mode (Practice your skills in a range of training missions)</translation>
+        <translation type="obsolete">Training Mode (Practice your skills in a range of training missions)</translation>
     </message>
     <message>
         <source>Demos (Watch recorded demos)</source>
-        <translation>Demos (Watch recorded demos)</translation>
+        <translation type="obsolete">Demos (Watch recorded demos)</translation>
     </message>
     <message>
         <source>Load (Load a previously saved game)</source>
-        <translation>Load (Load a previously saved game)</translation>
-    </message>
-    <message>
-        <source>Campaign Mode (...)</source>
+        <translation type="obsolete">Load (Load a previously saved game)</translation>
+    </message>
+    <message>
+        <source>Simple Game</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a quick game against the computer with random settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Multiplayer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play a hotseat game against your friends, or AI teams</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Campaign Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Training Mode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Practice your skills in a range of training missions</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Watch recorded demos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Load</source>
+        <translation type="unfinished">Load</translation>
+    </message>
+    <message>
+        <source>Load a previously saved game</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -1285,6 +1471,53 @@
         <source>Select a mission!</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Pick the mission or training to play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Start fighting</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>PageVideos</name>
+    <message>
+        <source>Name</source>
+        <translation type="unfinished">Name</translation>
+    </message>
+    <message>
+        <source>Size</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>%1 bytes</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>(in progress...)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Date: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Size: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>encoding</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QAction</name>
@@ -1391,6 +1624,26 @@
         <source>Frontend effects</source>
         <translation>Frontend effects</translation>
     </message>
+    <message>
+        <source>Save password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Save account name and password</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video is private</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Record audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Use game resolution</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QComboBox</name>
@@ -1561,6 +1814,30 @@
         <source>Schemes and Weapons</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Custom colors</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Miscellaneous</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Proxy settings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video recording options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QLabel</name>
@@ -1614,7 +1891,7 @@
     </message>
     <message>
         <source>Net nick</source>
-        <translation>Net nick</translation>
+        <translation type="obsolete">Net nick</translation>
     </message>
     <message>
         <source>Resolution</source>
@@ -1694,7 +1971,7 @@
     </message>
     <message>
         <source>Restart game to apply</source>
-        <translation>Restart game to apply</translation>
+        <translation type="obsolete">Restart game to apply</translation>
     </message>
     <message>
         <source>Explosives</source>
@@ -1746,7 +2023,7 @@
     </message>
     <message>
         <source>Password</source>
-        <translation type="unfinished">Password</translation>
+        <translation type="obsolete">Password</translation>
     </message>
     <message>
         <source>% Get Away Time</source>
@@ -1756,6 +2033,68 @@
         <source>This program is distributed under the GNU General Public License v2</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>There are videos that are currently being processed.
+Exiting now will abort them.
+Do you really want to quit?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please provide either the YouTube account name or the email address associated with the Google Account.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Account name (or email): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Password: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video title: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video description: </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Tags (comma separated): </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Summary   </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Description</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Nickname</source>
+        <translation type="unfinished">Nickname</translation>
+    </message>
+    <message>
+        <source>Format</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Audio codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video codec</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Framerate</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Bitrate (Kbps)</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QLineEdit</name>
@@ -1767,6 +2106,10 @@
         <source>hedgehog %1</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>anonymous</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QMainWindow</name>
@@ -1779,7 +2122,7 @@
     <name>QMessageBox</name>
     <message>
         <source>Network</source>
-        <translation>Network</translation>
+        <translation type="obsolete">Network</translation>
     </message>
     <message>
         <source>Connection to server is lost</source>
@@ -1793,13 +2136,13 @@
         <source>Failed to open data directory:
 %1
 Please check your installation</source>
-        <translation>Failed to open data directory:
+        <translation type="obsolete">Failed to open data directory:
  %1
 Please check your installation</translation>
     </message>
     <message>
         <source>Weapons</source>
-        <translation>Weapons</translation>
+        <translation type="obsolete">Weapons</translation>
     </message>
     <message>
         <source>Can not edit default weapon set</source>
@@ -1811,15 +2154,7 @@
     </message>
     <message>
         <source>Really delete this weapon set?</source>
-        <translation>Really delete this weapon set?</translation>
-    </message>
-    <message>
-        <source>Can not overwrite default weapon set &apos;%1&apos;!</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>All file associations have been set.</source>
-        <translation type="unfinished"></translation>
+        <translation type="obsolete">Really delete this weapon set?</translation>
     </message>
     <message>
         <source>File association failed.</source>
@@ -1827,26 +2162,217 @@
     </message>
     <message>
         <source>Teams</source>
-        <translation type="unfinished">Teams</translation>
-    </message>
-    <message>
-        <source>Really delete this team?</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Schemes</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Can not delete default scheme &apos;%1&apos;!</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Really delete this game scheme?</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Can not delete default weapon set &apos;%1&apos;!</source>
+        <translation type="obsolete">Teams</translation>
+    </message>
+    <message>
+        <source>Teams - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the team &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default scheme &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a record from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start server</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hedgewars - Success</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>All file associations have been set</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please fill out all fields</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Successfully posted the issue on hedgewars.googlecode.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error during authentication at google.com</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Main - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot create directory %1</source>
+        <translation type="unfinished">Cannot create directory %1</translation>
+    </message>
+    <message>
+        <source>Failed to open data directory:
+%1
+
+Please check your installation!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>TCP - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Unable to start the server: %1.</source>
+        <translation type="unfinished">Unable to start the server: %1.</translation>
+    </message>
+    <message>
+        <source>Unable to run engine at </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error code: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while authenticating at google.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Login or password is incorrect</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Video upload - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Error while sending metadata to youtube.com:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Netgame - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select a server from the list</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please enter room name</source>
+        <translation type="unfinished">Please enter room name</translation>
+    </message>
+    <message>
+        <source>Record Play - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select record from the list</source>
+        <translation type="unfinished">Please select record from the list</translation>
+    </message>
+    <message>
+        <source>Cannot rename to </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete file </source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Room Name - Error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Please select room from the list</source>
+        <translation type="unfinished">Please select room from the list</translation>
+    </message>
+    <message>
+        <source>Room Name - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>The game you are trying to join has started.
+Do you still want to join the room?</source>
+        <translation type="unfinished">The game you are trying to join has started.
+Do you still want to join the room?</translation>
+    </message>
+    <message>
+        <source>Schemes - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Schemes - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the game scheme &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Videos - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the video &apos;%1&apos;?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message numerus="yes">
+        <source>Do you really want to remove %1 file(s)?</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Do you really want to cancel uploading %1?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>File error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for writing</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot open &apos;%1&apos; for reading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot use the ammo &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Warning</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cannot delete default weapon set &apos;%1&apos;!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Weapons - Are you sure?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
 </context>
@@ -1854,15 +2380,15 @@
     <name>QObject</name>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>Cannot create directory %1</source>
-        <translation>Cannot create directory %1</translation>
+        <translation type="obsolete">Cannot create directory %1</translation>
     </message>
     <message>
         <source>OK</source>
-        <translation>OK</translation>
+        <translation type="obsolete">OK</translation>
     </message>
     <message>
         <source>Nickname</source>
@@ -1947,36 +2473,127 @@
         <source>more</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>More info</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Set default options</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open videos directory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload to YouTube</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Cancel uploading</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>QTableWidget</name>
     <message>
         <source>Room Name</source>
-        <translation>Room Name</translation>
+        <translation type="obsolete">Room Name</translation>
     </message>
     <message>
         <source>C</source>
-        <translation>C</translation>
+        <translation type="obsolete">C</translation>
     </message>
     <message>
         <source>T</source>
-        <translation>T</translation>
+        <translation type="obsolete">T</translation>
     </message>
     <message>
         <source>Owner</source>
-        <translation>Owner</translation>
+        <translation type="obsolete">Owner</translation>
     </message>
     <message>
         <source>Map</source>
-        <translation>Map</translation>
+        <translation type="obsolete">Map</translation>
     </message>
     <message>
         <source>Rules</source>
-        <translation>Rules</translation>
+        <translation type="obsolete">Rules</translation>
     </message>
     <message>
         <source>Weapons</source>
-        <translation>Weapons</translation>
+        <translation type="obsolete">Weapons</translation>
+    </message>
+</context>
+<context>
+    <name>RoomsListModel</name>
+    <message>
+        <source>In progress</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Room Name</source>
+        <translation type="unfinished">Room Name</translation>
+    </message>
+    <message>
+        <source>C</source>
+        <translation type="unfinished">C</translation>
+    </message>
+    <message>
+        <source>T</source>
+        <translation type="unfinished">T</translation>
+    </message>
+    <message>
+        <source>Owner</source>
+        <translation type="unfinished">Owner</translation>
+    </message>
+    <message>
+        <source>Map</source>
+        <translation type="unfinished">Map</translation>
+    </message>
+    <message>
+        <source>Rules</source>
+        <translation type="unfinished">Rules</translation>
+    </message>
+    <message>
+        <source>Weapons</source>
+        <translation type="unfinished">Weapons</translation>
+    </message>
+    <message>
+        <source>Random Map</source>
+        <translation type="unfinished">Random Map</translation>
+    </message>
+    <message>
+        <source>Random Maze</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Hand-drawn</source>
+        <translation type="unfinished"></translation>
     </message>
 </context>
 <context>
@@ -2010,15 +2627,15 @@
     <name>TCPBase</name>
     <message>
         <source>Error</source>
-        <translation>Error</translation>
+        <translation type="obsolete">Error</translation>
     </message>
     <message>
         <source>Unable to start the server: %1.</source>
-        <translation>Unable to start the server: %1.</translation>
+        <translation type="obsolete">Unable to start the server: %1.</translation>
     </message>
     <message>
         <source>Unable to run engine: %1 (</source>
-        <translation>Unable to run engine: %1 (</translation>
+        <translation type="obsolete">Unable to run engine: %1 (</translation>
     </message>
 </context>
 <context>
@@ -2292,6 +2909,14 @@
         <source>slot 10</source>
         <translation>slot 10</translation>
     </message>
+    <message>
+        <source>mute audio</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>record</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds (categories)</name>
@@ -2378,6 +3003,10 @@
         <source>Toggle labels above hedgehogs:</source>
         <translation>Toggle labels above hedgehogs:</translation>
     </message>
+    <message>
+        <source>Record video:</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>binds (keys)</name>
--- a/share/hedgewars/Data/Locale/hedgewars_ru.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_ru.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -346,23 +346,43 @@
     </message>
 </context>
 <context>
+    <name>LibavInteraction</name>
+    <message>
+        <source>Duration: %1m %2s
+</source>
+        <translation type="unfinished">Длительность: %1мин %2сек</translation>
+    </message>
+    <message>
+        <source>Video: %1x%2, </source>
+        <translation type="unfinished">Видео: %1x%2, </translation>
+    </message>
+    <message>
+        <source>%1 fps, </source>
+        <translation type="unfinished">%1 кадров/сек,</translation>
+    </message>
+    <message>
+        <source>Audio: </source>
+        <translation type="unfinished">Аудио: </translation>
+    </message>
+</context>
+<context>
     <name>LibavIteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
-        <translation>Длительность: %1мин %2сек</translation>
+        <translation type="obsolete">Длительность: %1мин %2сек</translation>
     </message>
     <message>
         <source>Video: %1x%2, </source>
-        <translation>Видео: %1x%2, </translation>
+        <translation type="obsolete">Видео: %1x%2, </translation>
     </message>
     <message>
         <source>%1 fps, </source>
-        <translation>%1 кадров/сек,</translation>
+        <translation type="obsolete">%1 кадров/сек,</translation>
     </message>
     <message>
         <source>Audio: </source>
-        <translation>Аудио: </translation>
+        <translation type="obsolete">Аудио: </translation>
     </message>
 </context>
 <context>
@@ -839,14 +859,6 @@
         <source>Control</source>
         <translation>Управление</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2009,6 +2021,8 @@
         <source>Do you really want to remove %1 file(s)?</source>
         <translation type="unfinished">
             <numerusform></numerusform>
+            <numerusform></numerusform>
+            <numerusform></numerusform>
         </translation>
     </message>
     <message>
@@ -2161,6 +2175,26 @@
         <source>Cancel uploading</source>
         <translation>Отменить отправку</translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_sk.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_sk.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -347,7 +347,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -841,12 +841,8 @@
         <translation>Ovládanie</translation>
     </message>
     <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Downloadable Content</source>
-        <translation type="unfinished">Stiahnuteľný obsah</translation>
+        <translation type="obsolete">Stiahnuteľný obsah</translation>
     </message>
 </context>
 <context>
@@ -2163,6 +2159,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
@@ -2196,7 +2212,7 @@
     </message>
     <message>
         <source>Weapons</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">Výzbroj</translation>
     </message>
     <message>
         <source>Random Map</source>
--- a/share/hedgewars/Data/Locale/hedgewars_sv.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_sv.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -344,7 +344,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -832,12 +832,8 @@
         <translation>Kontroll</translation>
     </message>
     <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
         <source>Downloadable Content</source>
-        <translation type="unfinished">Nedladdningsbart innehåll</translation>
+        <translation type="obsolete">Nedladdningsbart innehåll</translation>
     </message>
 </context>
 <context>
@@ -2150,6 +2146,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_tr_TR.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_tr_TR.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -340,7 +340,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -821,14 +821,6 @@
         <source>Control</source>
         <translation>Kontrol</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2136,6 +2128,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_uk.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_uk.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -155,7 +155,7 @@
     </message>
     <message>
         <source>Nickname</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">Ім&apos;я</translation>
     </message>
     <message>
         <source>No nickname supplied.</source>
@@ -345,7 +345,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -838,14 +838,6 @@
         <source>Control</source>
         <translation>Керування</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -1780,7 +1772,7 @@
     </message>
     <message>
         <source>Nickname</source>
-        <translation type="unfinished"></translation>
+        <translation type="unfinished">Ім&apos;я</translation>
     </message>
     <message>
         <source>Format</source>
@@ -2160,6 +2152,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -129,18 +129,18 @@
 <context>
     <name>HWForm</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="463"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="465"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="460"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="462"/>
         <source>DefaultTeam</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="569"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="566"/>
         <source>Game aborted</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="981"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="978"/>
         <source>Your nickname %1 is
 registered on Hedgewars.org
 Please provide your password below
@@ -148,51 +148,51 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="985"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="982"/>
         <source>No password supplied.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1011"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1008"/>
         <source>Nickname</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1011"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1008"/>
         <source>Someone already uses your nickname %1 on the server.
 Please pick another nickname:</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1015"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1012"/>
         <source>No nickname supplied.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1660"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1662"/>
         <source>Hedgewars Demo File</source>
         <comment>File Types</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1661"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1663"/>
         <source>Hedgewars Save File</source>
         <comment>File Types</comment>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1709"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1711"/>
         <source>Demo name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1709"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1711"/>
         <source>Demo name:</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1430"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1717"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1432"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1719"/>
         <source>Cannot save record to file %1</source>
         <translation>无法录入文件 %1</translation>
     </message>
@@ -200,13 +200,13 @@
 <context>
     <name>HWGame</name>
     <message>
-        <location filename="../../../../QTfrontend/game.cpp" line="350"/>
+        <location filename="../../../../QTfrontend/game.cpp" line="333"/>
         <location filename="../../../../QTfrontend/net/recorder.cpp" line="118"/>
         <source>en.txt</source>
         <translation>zh_CN.txt</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/game.cpp" line="361"/>
+        <location filename="../../../../QTfrontend/game.cpp" line="344"/>
         <source>Cannot open demofile %1</source>
         <translation>DEMO %1 打不开</translation>
     </message>
@@ -373,7 +373,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1285"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1282"/>
         <source>Quit reason: </source>
         <translation>退出原因:</translation>
     </message>
@@ -418,25 +418,25 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
-    <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="282"/>
+    <name>LibavInteraction</name>
+    <message>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="281"/>
         <source>Duration: %1m %2s
 </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="294"/>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="293"/>
         <source>Video: %1x%2, </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="298"/>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="297"/>
         <source>%1 fps, </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/util/libav_iteraction.cpp" line="302"/>
+        <location filename="../../../../QTfrontend/util/LibavInteraction.cpp" line="301"/>
         <source>Audio: </source>
         <translation type="unfinished"></translation>
     </message>
@@ -994,17 +994,7 @@
 <context>
     <name>PageNetGame</name>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="65"/>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="66"/>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="87"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="84"/>
         <source>Control</source>
         <translation>Ctrl</translation>
     </message>
@@ -1464,44 +1454,44 @@
 <context>
     <name>PageVideos</name>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="233"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="234"/>
         <source>Name</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="234"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="235"/>
         <source>Size</source>
         <translation type="unfinished"></translation>
     </message>
     <message numerus="yes">
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="492"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="498"/>
         <source>%1 bytes</source>
         <translation type="unfinished">
             <numerusform></numerusform>
         </translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="742"/>
         <source>(in progress...)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="740"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="746"/>
         <source>Date: </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="741"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="747"/>
         <source>Size: </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="955"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="966"/>
         <source>encoding</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="957"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="968"/>
         <source>uploading</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1514,22 +1504,22 @@
         <translation>踢</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="82"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="79"/>
         <source>Update</source>
         <translation type="unfinished">更新</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="90"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="87"/>
         <source>Start</source>
         <translation>开始</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="112"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="107"/>
         <source>Restrict Joins</source>
         <translation>限制参与</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="114"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="109"/>
         <source>Restrict Team Additions</source>
         <translation>限制团队插件</translation>
     </message>
@@ -1883,12 +1873,12 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="230"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="231"/>
         <source>Videos</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="265"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="267"/>
         <source>Description</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1937,17 +1927,17 @@
         <translation>开发者:</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="90"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="94"/>
         <source>Art:</source>
         <translation>艺术:</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="118"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="122"/>
         <source>Translations:</source>
         <translation>翻译:</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="142"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="146"/>
         <source>Special thanks:</source>
         <translation>特别感谢:</translation>
     </message>
@@ -1983,7 +1973,7 @@
         <translation>版本</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="108"/>
+        <location filename="../../../../QTfrontend/ui/widget/about.cpp" line="112"/>
         <source>Sounds:</source>
         <translation>声音:</translation>
     </message>
@@ -2198,7 +2188,7 @@
 <context>
     <name>QLineEdit</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="882"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="879"/>
         <source>unnamed</source>
         <translation>无名</translation>
     </message>
@@ -2235,77 +2225,77 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="904"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="901"/>
         <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="388"/>
         <source>Teams - Are you sure?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="905"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="902"/>
         <location filename="../../../../QTfrontend/ui/page/pageeditteam.cpp" line="389"/>
         <source>Do you really want to delete the team &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="921"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="918"/>
         <location filename="../../../../QTfrontend/ui/page/pagescheme.cpp" line="525"/>
         <source>Cannot delete default scheme &apos;%1&apos;!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="947"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="944"/>
         <source>Please select a record from the list</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1241"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1238"/>
         <source>Unable to start server</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1285"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1282"/>
         <source>Connection to server is lost</source>
         <translation>服务器连接丢失</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1392"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1394"/>
         <source>Hedgewars - Error</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1692"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1783"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1694"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1785"/>
         <source>Hedgewars - Success</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1693"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1695"/>
         <source>All file associations have been set</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1784"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1786"/>
         <source>Successfully posted the issue on hedgewars.googlecode.com</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1796"/>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1809"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1798"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1811"/>
         <source>Error during authentication at google.com</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1812"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1814"/>
         <source>Error reporting the issue, please try again later (or visit hedgewars.googlecode.com directly)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1698"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1700"/>
         <source>File association failed.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1734"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1736"/>
         <source>Please fill out all fields</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2374,7 +2364,7 @@
     </message>
     <message>
         <location filename="../../../../QTfrontend/ui/page/pagenet.cpp" line="113"/>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="162"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="157"/>
         <source>Netgame - Error</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2384,7 +2374,7 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="163"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="158"/>
         <location filename="../../../../QTfrontend/ui/page/pageroomslist.cpp" line="431"/>
         <source>Please enter room name</source>
         <translation type="unfinished"></translation>
@@ -2451,26 +2441,26 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="844"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="868"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1093"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="850"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="879"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1104"/>
         <source>Videos - Are you sure?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="845"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="851"/>
         <source>Do you really want to delete the video &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
     <message numerus="yes">
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="869"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="880"/>
         <source>Do you really want to remove %1 file(s)?</source>
         <translation type="unfinished">
             <numerusform></numerusform>
         </translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1094"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="1105"/>
         <source>Do you really want to cancel uploading %1?</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2491,28 +2481,28 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="199"/>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="254"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="229"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="266"/>
         <source>Weapons - Warning</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="200"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="230"/>
         <source>Cannot overwrite default weapon set &apos;%1&apos;!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="255"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="267"/>
         <source>Cannot delete default weapon set &apos;%1&apos;!</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="263"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="275"/>
         <source>Weapons - Are you sure?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="264"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="276"/>
         <source>Do you really want to delete the weapon set &apos;%1&apos;?</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2520,12 +2510,12 @@
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1203"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1200"/>
         <source>Nickname</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/hwform.cpp" line="1204"/>
+        <location filename="../../../../QTfrontend/hwform.cpp" line="1201"/>
         <source>Please enter your nickname</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2598,19 +2588,19 @@
     </message>
     <message>
         <location filename="../../../../QTfrontend/ui/dialog/input_ip.cpp" line="57"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="729"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="735"/>
         <source>Cancel</source>
         <translation>取消</translation>
     </message>
     <message>
         <location filename="../../../../QTfrontend/ui/page/pageplayrecord.cpp" line="53"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="300"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="729"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="303"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="735"/>
         <source>Delete</source>
         <translation>删除</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="75"/>
+        <location filename="../../../../QTfrontend/ui/page/pagenetgame.cpp" line="72"/>
         <source>Ready</source>
         <translation>准备好了</translation>
     </message>
@@ -2635,23 +2625,48 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="252"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="220"/>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="253"/>
         <source>Open videos directory</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="297"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="254"/>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="299"/>
         <source>Play</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="303"/>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="730"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="301"/>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="305"/>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="307"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
         <source>Upload to YouTube</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="730"/>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="309"/>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../../../QTfrontend/ui/page/pagevideos.cpp" line="736"/>
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
@@ -2742,14 +2757,14 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="277"/>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="282"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="289"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="294"/>
         <source>new</source>
         <translation type="unfinished">新</translation>
     </message>
     <message>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="313"/>
-        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="318"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="325"/>
+        <location filename="../../../../QTfrontend/ui/widget/selectWeapon.cpp" line="330"/>
         <source>copy of</source>
         <translation type="unfinished"></translation>
     </message>
--- a/share/hedgewars/Data/Locale/hedgewars_zh_TW.ts	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/hedgewars_zh_TW.ts	Sun Nov 18 23:10:26 2012 +0400
@@ -340,7 +340,7 @@
     </message>
 </context>
 <context>
-    <name>LibavIteraction</name>
+    <name>LibavInteraction</name>
     <message>
         <source>Duration: %1m %2s
 </source>
@@ -821,14 +821,6 @@
         <source>Control</source>
         <translation>房間管理</translation>
     </message>
-    <message>
-        <source>DLC</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message>
-        <source>Downloadable Content</source>
-        <translation type="unfinished"></translation>
-    </message>
 </context>
 <context>
     <name>PageNetType</name>
@@ -2136,6 +2128,26 @@
         <source>Cancel uploading</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <source>Restore default coding parameters</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Open the video directory in your system</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Play this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Delete this video</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Upload this video to your Youtube account</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>RoomsListModel</name>
--- a/share/hedgewars/Data/Locale/it.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/it.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 	["Hooray!"] = "Hurrà!!!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/ko.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/ko.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 --      ["Hooray!"] = "",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/lt.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/lt.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
    ["Hooray!"] = "Hurah!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/pl.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/pl.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
     ["Hooray!"] = "Hurraaa!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/pt_BR.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/pt_BR.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 --      ["Hooray!"] = "",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/pt_PT.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/pt_PT.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 	["Hooray!"] = "Hurra!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/ro.txt	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/ro.txt	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-; English locale
+; Romanian locale
 
 00:00=Grenadă
 00:01=Bombă cu dispersie
--- a/share/hedgewars/Data/Locale/ru.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/ru.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
       ["Hmmm..."] = "Хммм...",
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
       ["Hooray!"] = "Ура!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/sk.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/sk.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
         ["Hooray!"] = "Hurá!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/stub.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/stub.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 --      ["Hooray!"] = "",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/sv.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/sv.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -332,7 +332,7 @@
 --      ["Hmmm...perhaps a little more time will help."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
 	["Hooray!"] = "Hurra!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/uk.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/uk.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -331,7 +331,7 @@
         ["Hmmm..."] = "Хмм...",
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
         ["Hooray!"] = "Урааа!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Locale/zh_CN.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Locale/zh_CN.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -331,7 +331,7 @@
       ["Hmmm..."] = "呃...",
 --      ["Hogminator"] = "", -- A_Classic_Fairytale:family
 --      ["Hogs in sight!"] = "", -- Continental_supplies
---      ["HOLY SHIT!"] = "", -- Mutant
+--      ["HOLY SHYTE!"] = "", -- Mutant
 --      ["Honest Lee"] = "", -- A_Classic_Fairytale:enemy
       ["Hooray!"] = "呼!",
 --      ["Hostage Situation"] = "", -- A_Classic_Fairytale:family
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Constants---------------------------------
 choiceAccepted = 1
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Map--------------------------------------
 local map = 
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 
 --------------------------------------------Constants------------------------------------
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Constants---------------------------------
 leaksNum = 1
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Map--------------------------------------
 local map = 
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Variables---------------------------------
 startDialogue = {}
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 --///////////////////////////////CONSTANTS///////////////////////////
 
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 
 -----------------------------Map--------------------------------------
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Constants---------------------------------
 startStage = 0
--- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Animate.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Animate.lua")
 
 -----------------------------Constants---------------------------------
 choiceAccept = 1
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -13,7 +13,7 @@
 -- about translations.
 -- We can use the function loc(text) to localize a string.
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 -- This variable will hold the number of destroyed targets.
 local score = 0
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil
 local scored = 0
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -13,7 +13,7 @@
 -- about translations.
 -- We can use the function loc(text) to localize a string.
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 -- This variable will hold the number of destroyed targets.
 local score = 0
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -7,8 +7,8 @@
 --I know there need to be more "tutorial" specefic messages, but I had a hard timer figuring out what to type / what would be the best technical description.
 
 
-loadfile( GetDataPath() .. "Scripts/Locale.lua" )()
-loadfile( GetDataPath() .. "Scripts/Utils.lua" )() -- For the gearIsInBox function, wrote my own, but decided it was a waste to include it
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Utils.lua") -- For the gearIsInBox function, wrote my own, but decided it was a waste to include it
 
 local Player = nil -- Pointer to hog created in: onGameInit
 local Target = nil -- Pointer to target hog
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -13,7 +13,7 @@
 -- about translations.
 -- We can use the function loc(text) to localize a string.
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 -- This variable will hold the number of destroyed targets.
 local score = 0
--- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -13,7 +13,7 @@
 -- about translations.
 -- We can use the function loc(text) to localize a string.
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 -- This variable will hold the number of destroyed targets.
 local score = 0
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Bamboo_Thicket.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Bamboo_Thicket.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil 
 local enemy = nil
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Dangerous_Ducklings.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Dangerous_Ducklings.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 
 local player = nil -- This variable will point to the hog's gear
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Diver.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Diver.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil -- This variable will point to the hog's gear
 local enemy = nil
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Newton_and_the_Hammock.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Newton_and_the_Hammock.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil 
 local enemy = nil
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_RCPlane_Challenge.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_RCPlane_Challenge.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil
 local RCGear = nil
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Rope_Knock_Challenge.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Rope_Knock_Challenge.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local hhs = {}
 local missionWon = nil
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Spooky_Tree.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Spooky_Tree.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 ---------------------------------------------------------------
 
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Teamwork.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Teamwork.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil -- This variable will point to the hog's gear
 local p2 = nil
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_That_Sinking_Feeling.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_That_Sinking_Feeling.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,6 +1,6 @@
 
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player
 local hh = {}
--- a/share/hedgewars/Data/Missions/Training/User_Mission_-_The_Great_Escape.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_The_Great_Escape.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,4 +1,4 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local player = nil
 local enemy = nil
--- a/share/hedgewars/Data/Missions/Training/portal.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Missions/Training/portal.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Utils.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Utils.lua")
 
 local MineArray = {}
 local player 
--- a/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,5 +1,5 @@
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer, amBaseballBat, amMortar, amCake, amSeduction, amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane, amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb, amFlamethrower, amSMine, amKamikaze }
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -75,7 +75,7 @@
 -----------------
 
 -- enable awesome translaction support so we can use loc() wherever we want
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 ---------------------------------------------------------------
 ----------lots of bad variables and things
--- a/share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -10,9 +10,9 @@
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 ]]
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Utils.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Utils.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 function int_sqrt(num)
 	temp=num
--- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -51,8 +51,8 @@
 -- added napalm (whoops) to list of possible weapons you can get
 -- hogs no longer recieve airstrike-related weps on border maps
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 local airWeapons = 	{amAirAttack, amMineStrike, amNapalm, amDrillStrike --[[,amPiano]]}
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -52,8 +52,8 @@
 
 --]]
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 --[[
     MUTANT SCRIPT
@@ -209,6 +209,7 @@
     checkScore()
     giveWeapons(CurrentHedgehog)
     drawCircles()
+    setAIHints()
     kill_reward= numhhs*10
 
     if CurrentHedgehog == mutant then
@@ -237,7 +238,7 @@
             AddCaption(loc("LUDICROUS KILL"))
             PlaySound(sndNutter)
         elseif killsCounter == 7 then
-            AddCaption(loc("HOLY SHIT!"))
+            AddCaption(loc("HOLY SHYTE!"))
             PlaySound(sndLaugh)
         elseif killsCounter > 8 then
             AddCaption(loc("INSANITY"))
@@ -399,6 +400,16 @@
     mutant=nil
 end
 
+function setAIHints()
+    for i = 0, #hhs do
+        if mutant == nil or hhs[i] == mutant or CurrentHedgehog == mutant then
+            SetGearAIHints(hhs[i], aihUsual)
+        else
+            SetGearAIHints(hhs[i], aihDoesntMatter)
+        end
+    end
+end
+
 function removeFeeder(gear)
 
     if gear~=nil then
--- a/share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -2,7 +2,7 @@
 -- NO JUMPING
 --------------------------------
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 local specialGear = nil
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -65,7 +65,7 @@
 -- SCRIPT BEGINS
 -----------------------------
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 ------------------
 -- Got Variables?
--- a/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,10 +1,10 @@
 -- Random Weapons, example for gameplay scripts
 
 -- Load the library for localisation ("loc" function)
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
 
 -- Load the gear tracker
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 -- List of available weapons
 local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun,
--- a/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -1,6 +1,6 @@
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 ---------------------------------------------------
 ---------------------------------------------------
--- a/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -52,8 +52,8 @@
 -- balance hog health, maybe
 -- add proper gameflag checking, maybe (so that we can throw in a .cfg and let the users break everything)
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 local numhhs = 0
 local hhs = {}
--- a/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -3,8 +3,8 @@
 -- v.0.7.1
 ------------------------------------
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
 
 local fMod = 1000000 -- use this for dev and .16+ games
 
--- a/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua	Sun Nov 18 23:09:29 2012 +0400
+++ b/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua	Sun Nov 18 23:10:26 2012 +0400
@@ -54,9 +54,9 @@
 -- GO PONIES, GO PONIES, GO!
 -----------------------------
 
-loadfile(GetDataPath() .. "Scripts/Locale.lua")()
-loadfile(GetDataPath() .. "Scripts/Tracker.lua")()
-loadfile(GetDataPath() .. "Scripts/Utils.lua")()
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/Tracker.lua")
+HedgewarsScriptLoad("/Scripts/Utils.lua")
 
 -- experimental menu stuff
 local menuIndex = 1
Binary file share/hedgewars/Data/Sounds/voices/Pirate/Firepunch2.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Pirate/Firepunch3.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Pirate/Firepunch4.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Pirate/Firepunch5.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Pirate/Firepunch6.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Robot/Firepunch2.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Robot/Firepunch3.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Robot/Firepunch4.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Robot/Firepunch5.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Robot/Firepunch6.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Singer/Firepunch2.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Singer/Firepunch3.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Singer/Firepunch4.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Singer/Firepunch5.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Singer/Firepunch6.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Surfer/Firepunch2.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Surfer/Firepunch3.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Surfer/Firepunch4.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Surfer/Firepunch5.ogg has changed
Binary file share/hedgewars/Data/Sounds/voices/Surfer/Firepunch6.ogg has changed