merge of tsleon's updated russian. I assume unc0rr will vet the phrasing
authornemo
Fri, 17 Jun 2011 11:58:27 -0400
changeset 5246 bc80445549e0
parent 5243 f2e31a7f953a (diff)
parent 5234 69ed8cb551ef (current diff)
child 5248 32465b4b4049
child 5249 d4447442c7d8
merge of tsleon's updated russian. I assume unc0rr will vet the phrasing
--- a/QTfrontend/SDLs.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/SDLs.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -164,9 +164,12 @@
 void SDLInteraction::StartMusic()
 {
     SDLMusicInit();
+    QFile tmpfile;
 
+    tmpfile.setFileName(cfgdir->absolutePath() + "/Data/Music/main_theme.ogg");
+    if (!tmpfile.exists()) tmpfile.setFileName(datadir->absolutePath() + "/Music/main_theme.ogg");
     if (music == NULL) {
-        music = Mix_LoadMUS((datadir->absolutePath() + "/Music/main_theme.ogg").toLocal8Bit().constData());
+        music = Mix_LoadMUS(QFileInfo(tmpfile).absoluteFilePath().toLocal8Bit().constData());
 
     }
     Mix_VolumeMusic(MIX_MAX_VOLUME - 28);
--- a/QTfrontend/chatwidget.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/chatwidget.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -122,15 +122,14 @@
     this->sdli = sdli;
     this->notify = notify;
     if(notify && gameSettings->value("frontend/sound", true).toBool()) {
-       QDir tmpdir;
-
-       tmpdir.cd(datadir->absolutePath());
-       tmpdir.cd("Sounds/voices");
-       sdli->SDLMusicInit();
-       sound[0] = Mix_LoadWAV(QString(tmpdir.absolutePath() + "/Classic/Hello.ogg").toLocal8Bit().constData());
-       sound[1] = Mix_LoadWAV(QString(tmpdir.absolutePath() + "/Default/Hello.ogg").toLocal8Bit().constData());
-       sound[2] = Mix_LoadWAV(QString(tmpdir.absolutePath() + "/Mobster/Hello.ogg").toLocal8Bit().constData());
-       sound[3] = Mix_LoadWAV(QString(tmpdir.absolutePath() + "/Russian/Hello.ogg").toLocal8Bit().constData());
+        QFile tmpfile;
+        sdli->SDLMusicInit();
+        for(int i=0;i<4;i++) {
+            tmpfile.setFileName(cfgdir->absolutePath() + "/Data/Sounds/voices/Classic/Hello.ogg");
+            if (tmpfile.exists()) sound[i] = Mix_LoadWAV(QFileInfo(tmpfile).absoluteFilePath().toLocal8Bit().constData());
+            else sound[i] = Mix_LoadWAV(QString(datadir->absolutePath() + 
+                "/Sounds/voices/Classic/Hello.ogg").toLocal8Bit().constData());
+        }
     }
 
     mainLayout.setSpacing(1);
--- a/QTfrontend/gamecfgwidget.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/gamecfgwidget.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -61,7 +61,9 @@
         QString script = (*scriptList)[i].remove(".lua", Qt::CaseInsensitive);
         QList<QVariant> scriptInfo;
         scriptInfo.push_back(script);
-        QFile scriptCfgFile(QString("%1/Scripts/Multiplayer/%2.cfg").arg(datadir->absolutePath()).arg(script));
+        QFile scriptCfgFile;
+        scriptCfgFile.setFileName(QString("%1/Data/Scripts/Multiplayer/%2.cfg").arg(cfgdir->absolutePath()).arg(script));
+        if (!scriptCfgFile.exists()) scriptCfgFile.setFileName(QString("%1/Scripts/Multiplayer/%2.cfg").arg(datadir->absolutePath()).arg(script));
         if (scriptCfgFile.exists() && scriptCfgFile.open(QFile::ReadOnly)) {
             QString scheme;
             QString weapons;
--- a/QTfrontend/gameuiconfig.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/gameuiconfig.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -44,7 +44,14 @@
     Form->ui.pageOptions->WeaponTooltip->setChecked(value("misc/weaponTooltips", true).toBool());
 
     int t = Form->ui.pageOptions->CBResolution->findText(value("video/resolution").toString());
-    Form->ui.pageOptions->CBResolution->setCurrentIndex((t < 0) ? 0 : t);
+    if (t < 0) {
+        if (Form->ui.pageOptions->CBResolution->count() > 1)
+            Form->ui.pageOptions->CBResolution->setCurrentIndex(1);
+        else 
+            Form->ui.pageOptions->CBResolution->setCurrentIndex(0);
+    }
+    else Form->ui.pageOptions->CBResolution->setCurrentIndex(t);
+    Form->ui.pageOptions->CBResolution->setCurrentIndex((t < 0) ? 1 : t);
     Form->ui.pageOptions->CBFullscreen->setChecked(value("video/fullscreen", false).toBool());
     bool ffscr=value("frontend/fullscreen", false).toBool();
     Form->ui.pageOptions->CBFrontendFullscreen->setChecked(ffscr);
--- a/QTfrontend/hats.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/hats.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -26,19 +26,46 @@
 HatsModel::HatsModel(QObject* parent) :
   QAbstractListModel(parent)
 {
-    QPixmap hhpix = QPixmap(datadir->absolutePath() + "/Graphics/Hedgehog/Idle.png").copy(0, 0, 32, 32);
+    QFile hhfile;
+    hhfile.setFileName(cfgdir->absolutePath() + "/Data/Graphics/Hedgehog/Idle.png");
+    if (!hhfile.exists()) hhfile.setFileName(datadir->absolutePath() + "/Graphics/Hedgehog/Idle.png");
+    QPixmap hhpix = QPixmap(QFileInfo(hhfile).absoluteFilePath()).copy(0, 0, 32, 32);
 
     QDir tmpdir;
-    tmpdir.cd(datadir->absolutePath());
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data");
     tmpdir.cd("Graphics");
     tmpdir.cd("Hats");
 
     tmpdir.setFilter(QDir::Files);
 
+    QStringList userhatsList = tmpdir.entryList(QStringList("*.png"));
+    for (QStringList::Iterator it = userhatsList.begin(); it != userhatsList.end(); ++it )
+    {
+        QString str = QString(*it).replace(QRegExp("^(.*)\\.png"), "\\1");
+        QPixmap pix(cfgdir->absolutePath() + "/Data/Graphics/Hats/" + str + ".png");
+
+        QPixmap tmppix(32, 37);
+        tmppix.fill(QColor(Qt::transparent));
+
+        QPainter painter(&tmppix);
+        painter.drawPixmap(QPoint(0, 5), hhpix);
+        painter.drawPixmap(QPoint(0, 0), pix.copy(0, 0, 32, 32));
+        if(pix.width() > 32)
+            painter.drawPixmap(QPoint(0, 0), pix.copy(32, 0, 32, 32));
+        painter.end();
+
+        hats.append(qMakePair(str, QIcon(tmppix)));
+    }
+
+    tmpdir.cd(datadir->absolutePath());
+    tmpdir.cd("Graphics");
+    tmpdir.cd("Hats");
 
     QStringList hatsList = tmpdir.entryList(QStringList("*.png"));
     for (QStringList::Iterator it = hatsList.begin(); it != hatsList.end(); ++it )
     {
+        if (userhatsList.contains(*it,Qt::CaseInsensitive)) continue;
         QString str = (*it).replace(QRegExp("^(.*)\\.png"), "\\1");
         QPixmap pix(datadir->absolutePath() + "/Graphics/Hats/" + str + ".png");
 
--- a/QTfrontend/hwform.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/hwform.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -1201,13 +1201,23 @@
     ui.pageCampaign->CBSelect->clear();
 
     QDir tmpdir;
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Missions/Campaign");
+    tmpdir.setFilter(QDir::Files);
+    QStringList userentries = tmpdir.entryList(QStringList("*#*.lua"));
+    //entries.sort();
+    for(int i = 0; (i < userentries.count()) && (i <= team.CampaignProgress); i++)
+        ui.pageCampaign->CBSelect->addItem(QString(userentries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2").replace("_", " "), QString(userentries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1"));
+
     tmpdir.cd(datadir->absolutePath());
     tmpdir.cd("Missions/Campaign");
     tmpdir.setFilter(QDir::Files);
     QStringList entries = tmpdir.entryList(QStringList("*#*.lua"));
     //entries.sort();
-    for(int i = 0; (i < entries.count()) && (i <= team.CampaignProgress); i++)
+    for(int i = 0; (i < entries.count()) && (i <= team.CampaignProgress); i++) {
+        if (userentries.contains(entries[i])) continue; 
         ui.pageCampaign->CBSelect->addItem(QString(entries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2").replace("_", " "), QString(entries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1"));
+    }
 }
 
 // used for --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality]
@@ -1240,8 +1250,8 @@
     registry_hkcr.setValue("Hedgewars.Save/Default", tr("Hedgewars Save File", "File Types"));
     registry_hkcr.setValue("Hedgewars.Demo/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwdfile.ico\",0");
     registry_hkcr.setValue("Hedgewars.Save/DefaultIcon/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwsfile.ico\",0");
-    registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
-    registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
+    registry_hkcr.setValue("Hedgewars.Demo/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + cfgdir->absolutePath().replace("/","\\") + "\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
+    registry_hkcr.setValue("Hedgewars.Save/Shell/Open/Command/Default", "\"" + bindir->absolutePath().replace("/", "\\") + "\\hwengine.exe\" \"" + cfgdir->absolutePath().replace("/","\\") + "\" \"" + datadir->absolutePath().replace("/", "\\") + "\" \"%1\" --set-everything "+arguments);
 #elif defined __APPLE__
     success = false;
     // TODO; also enable button in pages.cpp and signal in hwform.cpp
@@ -1259,8 +1269,8 @@
     if (success) success = system(("update-mime-database "+QDir::home().absolutePath()+"/.local/share/mime").toLocal8Bit().constData())==0;
     if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-demo")==0;
     if (success) success = system("xdg-mime default hwengine.desktop application/x-hedgewars-save")==0;
-    // hack to add user's settings to hwengine. might be better at this point to read in the file, append it, and write it out to its new home
-    if (success) success = system(("sed -i 's/^\\(Exec=.*\\)/\\1 --set-everything "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
+    // hack to add user's settings to hwengine. might be better at this point to read in the file, append it, and write it out to its new home.  This assumes no spaces in the data dir path
+    if (success) success = system(("sed -i 's/^\\(Exec=.*\\) \\([^ ]* %f\\)/\\1 "+cfgdir->absolutePath().replace(" ","\\\\ ").replace("/","\\/")+" \\2 --set-everything "+arguments+"/' "+QDir::home().absolutePath()+"/.local/share/applications/hwengine.desktop").toLocal8Bit().constData())==0;
 #endif
     if (success) QMessageBox::information(0, "", QMessageBox::tr("All file associations have been set."));
     else QMessageBox::information(0, "", QMessageBox::tr("File association failed."));
--- a/QTfrontend/main.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/main.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -384,13 +384,19 @@
     }
 
     Themes = new QStringList();
+    QFile userthemesfile(cfgdir->absolutePath() + "/Data/Themes/themes.cfg");
+    if (userthemesfile.open(QIODevice::ReadOnly)) {
+        QTextStream stream(&userthemesfile);
+        while (!stream.atEnd()) Themes->append(stream.readLine());
+        userthemesfile.close();
+    }
     QFile themesfile(datadir->absolutePath() + "/Themes/themes.cfg");
+    QString str;
     if (themesfile.open(QIODevice::ReadOnly)) {
         QTextStream stream(&themesfile);
-        QString str;
-        while (!stream.atEnd())
-        {
-            Themes->append(stream.readLine());
+        while (!stream.atEnd()) {
+            str = stream.readLine();
+            if (!Themes->contains(str)) Themes->append(str);
         }
         themesfile.close();
     } else {
@@ -398,16 +404,29 @@
     }
 
     QDir tmpdir;
-    tmpdir.cd(datadir->absolutePath());
-    tmpdir.cd("Maps");
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Maps");
     tmpdir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
     mapList = new QStringList(tmpdir.entryList(QStringList("*")));
 
     tmpdir.cd(datadir->absolutePath());
-    tmpdir.cd("Scripts/Multiplayer");
+    tmpdir.cd("Maps");
+    tmpdir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+    QStringList tmplist = QStringList(tmpdir.entryList(QStringList("*")));
+    for (QStringList::Iterator it = tmplist.begin(); it != tmplist.end(); ++it)
+        if (!mapList->contains(*it,Qt::CaseInsensitive)) mapList->append(*it);
+ 
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Scripts/Multiplayer");
     tmpdir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
     scriptList = new QStringList(tmpdir.entryList(QStringList("*.lua")));
 
+    tmpdir.cd(datadir->absolutePath());
+    tmpdir.cd("Scripts/Multiplayer");
+    tmpdir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
+    tmplist = QStringList(tmpdir.entryList(QStringList("*.lua")));
+    for (QStringList::Iterator it = tmplist.begin(); it != tmplist.end(); ++it)
+        if (!scriptList->contains(*it,Qt::CaseInsensitive)) scriptList->append(*it);
 
     QTranslator Translator;
     {
@@ -415,7 +434,10 @@
         QString cc = settings.value("misc/locale", "").toString();
         if(!cc.compare(""))
             cc = QLocale::system().name();
-        Translator.load(datadir->absolutePath() + "/Locale/hedgewars_" + cc);
+        QFile tmpfile;
+        tmpfile.setFileName(cfgdir->absolutePath() + "Data/Locale/hedgewars_" + cc);
+        if (!tmpfile.exists()) tmpfile.setFileName(datadir->absolutePath() + "Locale/hedgewars_" + cc);
+        Translator.load(QFileInfo(tmpfile).absoluteFilePath());
         app.installTranslator(&Translator);
     }
 
--- a/QTfrontend/mapContainer.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/mapContainer.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -85,16 +85,29 @@
 
     int missionindex = chooseMap->count();
     numMissions = 0;
+    QFile mapLuaFile;
+    QFile mapCfgFile;
     for (int i = 0; i < mapList->size(); ++i) {
         QString map = (*mapList)[i];
-        QFile mapCfgFile(
-                QString("%1/Maps/%2/map.cfg")
-                .arg(datadir->absolutePath())
+        mapCfgFile.setFileName(
+                QString("%1/Data/Maps/%2/map.cfg")
+                .arg(cfgdir->absolutePath())
                 .arg(map));
-        QFile mapLuaFile(
-                QString("%1/Maps/%2/map.lua")
-                .arg(datadir->absolutePath())
-                .arg(map));
+        if (mapCfgFile.exists()) {
+            mapLuaFile.setFileName(
+                    QString("%1/Data/Maps/%2/map.lua")
+                    .arg(cfgdir->absolutePath())
+                    .arg(map));
+        } else {
+            mapCfgFile.setFileName(
+                    QString("%1/Maps/%2/map.cfg")
+                    .arg(datadir->absolutePath())
+                    .arg(map));
+            mapLuaFile.setFileName(
+                    QString("%1/Maps/%2/map.lua")
+                    .arg(datadir->absolutePath())
+                    .arg(map));
+        }
 
         if (mapCfgFile.open(QFile::ReadOnly)) {
             QString theme;
@@ -190,10 +203,13 @@
     lwThemes = new QListWidget(mapWidget);
     lwThemes->setMinimumHeight(30);
     lwThemes->setFixedWidth(140);
+    QFile tmpfile;
     for (int i = 0; i < Themes->size(); ++i) {
         QListWidgetItem * lwi = new QListWidgetItem();
         lwi->setText(Themes->at(i));
-        lwi->setIcon(QIcon(QString("%1/Themes/%2/icon.png").arg(datadir->absolutePath()).arg(Themes->at(i))));
+        tmpfile.setFileName(QString("%1/Data/Themes/%2/icon.png").arg(cfgdir->absolutePath()).arg(Themes->at(i)));
+        if (tmpfile.exists()) lwi->setIcon(QIcon(QFileInfo(tmpfile).absoluteFilePath()));
+        else lwi->setIcon(QIcon(QString("%1/Themes/%2/icon.png").arg(datadir->absolutePath()).arg(Themes->at(i))));
         //lwi->setTextAlignment(Qt::AlignHCenter);
         lwThemes->addItem(lwi);
     }
@@ -373,7 +389,10 @@
     chooseMap->setItemData(1, mapInfo);
     mapInfo[0] = QString("+drawn+");
     chooseMap->setItemData(2, mapInfo);
-    gbThemes->setIcon(QIcon(QString("%1/Themes/%2/icon@2x.png").arg(datadir->absolutePath()).arg(theme)));
+    QFile tmpfile;
+    tmpfile.setFileName(QString("%1/Data/Themes/%2/icon@2x.png").arg(cfgdir->absolutePath()).arg(theme));
+    if (tmpfile.exists()) gbThemes->setIcon(QIcon(QFileInfo(tmpfile).absoluteFilePath()));
+    else gbThemes->setIcon(QIcon(QString("%1/Themes/%2/icon@2x.png").arg(datadir->absolutePath()).arg(theme)));
     emit themeChanged(theme);
 }
 
@@ -632,7 +651,10 @@
     default:
         QPixmap mapImage;
         qDebug() << "Map data" << curIndex << chooseMap->currentText() << chooseMap->itemData(curIndex);
-        if(!mapImage.load(datadir->absolutePath() + "/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png")) {
+        QFile tmpfile;
+        tmpfile.setFileName(cfgdir->absolutePath() + "/Data//Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png");
+        if (!tmpfile.exists()) tmpfile.setFileName(datadir->absolutePath() + "/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png");
+        if(!mapImage.load(QFileInfo(tmpfile).absoluteFilePath())) {
             imageButt->setIcon(QIcon());
             return;
         }
--- a/QTfrontend/namegen.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/namegen.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -88,21 +88,23 @@
 
 void HWNamegen::DictLoad(const QString filename, QStringList &list)
 {
-     list.clear();
+    list.clear();
 
-     QFile file(QString("%1/Names/%2.txt").arg(datadir->absolutePath()).arg(filename));
-     if (file.open(QIODevice::ReadOnly | QIODevice::Text))
-     {
+    QFile file;
+    file.setFileName(QString("%1/Data/Names/%2.txt").arg(cfgdir->absolutePath()).arg(filename));
+    if (!file.exists()) file.setFileName(QString("%1/Names/%2.txt").arg(datadir->absolutePath()).arg(filename));
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
 
-         QTextStream in(&file);
-         while (!in.atEnd()) {
-             QString line = in.readLine();
-             if(line != QString(""))
-                 {list.append(line);}
-         }
-     }
+        QTextStream in(&file);
+        while (!in.atEnd()) {
+            QString line = in.readLine();
+            if(line != QString(""))
+                {list.append(line);}
+        }
+    }
 
-     if (list.size()==0)
+    if (list.size()==0)
          list.append(filename);
 
 }
@@ -110,21 +112,23 @@
 
 void HWNamegen::HatCfgLoad(const QString hatname, QStringList &list)
 {
-     list.clear();
+    list.clear();
 
-     QFile file(QString("%1/Names/%2.cfg").arg(datadir->absolutePath()).arg(hatname));
-     if (file.open(QIODevice::ReadOnly | QIODevice::Text))
-     {
+    QFile file;
+    file.setFileName(QString("%1/Data/Names/%2.cfg").arg(cfgdir->absolutePath()).arg(hatname));
+    if (!file.exists()) file.setFileName(QString("%1/Names/%2.cfg").arg(datadir->absolutePath()).arg(hatname));
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
 
-         QTextStream in(&file);
-         while (!in.atEnd()) {
-             QString line = in.readLine();
-             if(line != QString(""))
-                 {list.append(line);}
-         }
-     }
+        QTextStream in(&file);
+        while (!in.atEnd()) {
+            QString line = in.readLine();
+            if(line != QString(""))
+                {list.append(line);}
+        }
+    }
 
-     if (list.size()==0)
+    if (list.size()==0)
          list.append(QString("generic"));
 
 }
@@ -132,37 +136,38 @@
 
 void HWNamegen::TypesLoad()
 {
+    QFile file;
+    file.setFileName(QString("%1/Data/Names/types.ini").arg(cfgdir->absolutePath()));
+    if (!file.exists()) file.setFileName(QString("%1/Names/types.ini").arg(datadir->absolutePath()));
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+        {TypesAvliable = FALSE; return;}
 
-     QFile file(QString("%1/Names/types.ini").arg(datadir->absolutePath()));
-     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
-         {TypesAvliable = FALSE; return;}
-
-     int counter = 0; //counter starts with 0 (teamnames mode)
-     TypesTeamnames.append(QStringList());
-     TypesHatnames.append(QStringList());
+    int counter = 0; //counter starts with 0 (teamnames mode)
+    TypesTeamnames.append(QStringList());
+    TypesHatnames.append(QStringList());
 
-     QTextStream in(&file);
-     while (!in.atEnd()) {
-         QString line = in.readLine();
-         if (line == QString("#####")){
-             counter++; //toggle mode (teamnames || hats)
-             if ((counter%2) == 0){
-                 TypesTeamnames.append(QStringList());
-                 TypesHatnames.append(QStringList());
-             }
-         } else if ((line == QString("*****")) || (line == QString("*END*"))){
-             TypesAvliable = TRUE; return; // bye bye
-         } else {
-             if ((counter%2) == 0){ // even => teamnames mode
-                 TypesTeamnames[(counter/2)].append(line);
-             } else { // odd => hats mode
-                 TypesHatnames[((counter-1)/2)].append(line);
-             }
-         }
-//         Types.append(line);
-     }
-         TypesAvliable = TRUE;
-     return;
+    QTextStream in(&file);
+    while (!in.atEnd()) {
+        QString line = in.readLine();
+        if (line == QString("#####")){
+            counter++; //toggle mode (teamnames || hats)
+            if ((counter%2) == 0){
+                TypesTeamnames.append(QStringList());
+                TypesHatnames.append(QStringList());
+            }
+        } else if ((line == QString("*****")) || (line == QString("*END*"))){
+            TypesAvliable = TRUE; return; // bye bye
+        } else {
+            if ((counter%2) == 0){ // even => teamnames mode
+                TypesTeamnames[(counter/2)].append(line);
+            } else { // odd => hats mode
+                TypesHatnames[((counter-1)/2)].append(line);
+            }
+        }
+//        Types.append(line);
+    }
+        TypesAvliable = TRUE;
+    return;
 }
 
 
@@ -173,10 +178,17 @@
 
     //list all available Graves
     QDir tmpdir;
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Graphics/Graves");
+    tmpdir.setFilter(QDir::Files);
+    Graves.append(tmpdir.entryList(QStringList("*.png")).replaceInStrings(QRegExp("^(.*)\\.png"), "\\1"));
+
     tmpdir.cd(datadir->absolutePath());
     tmpdir.cd("Graphics/Graves");
     tmpdir.setFilter(QDir::Files);
-    Graves.append(tmpdir.entryList(QStringList("*.png")).replaceInStrings(QRegExp("^(.*)\\.png"), "\\1"));
+    QStringList tmpList = tmpdir.entryList(QStringList("*.png")).replaceInStrings(QRegExp("^(.*)\\.png"), "\\1");
+    for (QStringList::Iterator it = tmpList.begin(); it != tmpList.end(); ++it) 
+        if (!Graves.contains(*it,Qt::CaseInsensitive)) Graves.append(*it);
 
     if(Graves.size()==0)
     {
--- a/QTfrontend/pageeditteam.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/pageeditteam.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -145,10 +145,19 @@
         CBVoicepack = new QComboBox(GBoxTeam);
         {
             QDir tmpdir;
+            tmpdir.cd(cfgdir->absolutePath());
+            tmpdir.cd("Data/Sounds/voices");
+            QStringList list = tmpdir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name);
+            CBVoicepack->addItems(list);
+
             tmpdir.cd(datadir->absolutePath());
             tmpdir.cd("Sounds/voices");
-            QStringList list = tmpdir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name);
-            CBVoicepack->addItems(list);
+            QStringList tmplist = tmpdir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name);
+            QStringList tmplist2;
+            for (QStringList::Iterator it = tmplist.begin(); it != tmplist.end(); ++it)
+                if (!list.contains(*it,Qt::CaseInsensitive)) tmplist2.append(*it);
+
+            CBVoicepack->addItems(tmplist2);
         }
         hbox->addWidget(CBVoicepack, 100);
         BtnTestSound = addButton(":/res/PlaySound.png", hbox, 1, true);
@@ -173,45 +182,103 @@
     vbox2->addWidget(GBoxFort);
 
     QDir tmpdir;
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Forts");
+    tmpdir.setFilter(QDir::Files);
+
+    QStringList userforts = tmpdir.entryList(QStringList("*L.png")).replaceInStrings(QRegExp("^(.*)L\\.png"), "\\1");
+    CBFort->addItems(userforts);
+
+    tmpdir.cd("../Graphics/Graves");
+    QStringList userlist = tmpdir.entryList(QStringList("*.png"));
+    for (QStringList::Iterator it = userlist.begin(); it != userlist.end(); ++it )
+    {
+        QPixmap pix(cfgdir->absolutePath() + "/Data/Graphics/Graves/" + *it);
+        QIcon icon(pix.copy(0, 0, 32, 32));
+        CBGrave->addItem(icon, QString(*it).replace(QRegExp("^(.*)\\.png"), "\\1"));
+    }
+
     tmpdir.cd(datadir->absolutePath());
     tmpdir.cd("Forts");
     tmpdir.setFilter(QDir::Files);
 
+    QStringList tmplist = tmpdir.entryList(QStringList("*L.png")).replaceInStrings(QRegExp("^(.*)L\\.png"), "\\1");
+    QStringList dataforts;
+    for (QStringList::Iterator it = tmplist.begin(); it != tmplist.end(); ++it)
+        if (!userforts.contains(*it,Qt::CaseInsensitive)) dataforts.append(*it);
+
+    CBVoicepack->addItems(dataforts);
     connect(CBFort, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(CBFort_activated(const QString &)));
-    CBFort->addItems(tmpdir.entryList(QStringList("*L.png")).replaceInStrings(QRegExp("^(.*)L\\.png"), "\\1"));
 
     tmpdir.cd("../Graphics/Graves");
-    QStringList list = tmpdir.entryList(QStringList("*.png"));
-    for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+    QStringList datalist = tmpdir.entryList(QStringList("*.png"));
+    for (QStringList::Iterator it = datalist.begin(); it != datalist.end(); ++it )
     {
+        if (userlist.contains(*it,Qt::CaseInsensitive)) continue;
         QPixmap pix(datadir->absolutePath() + "/Graphics/Graves/" + *it);
         QIcon icon(pix.copy(0, 0, 32, 32));
         CBGrave->addItem(icon, (*it).replace(QRegExp("^(.*)\\.png"), "\\1"));
     }
 
-    tmpdir.cd(datadir->absolutePath());
-    tmpdir.cd("Graphics/Flags");
-    list = tmpdir.entryList(QStringList("*.png"));
-    
     // add the default flag
     CBFlag->addItem(QIcon(QPixmap(datadir->absolutePath() + "/Graphics/Flags/hedgewars.png").copy(0, 0, 22, 15)), "Hedgewars", "hedgewars");
+    CBFlag->insertSeparator(CBFlag->count());
+
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Graphics/Flags");
+    userlist = tmpdir.entryList(QStringList("*.png"));
+    
+    // add all country flags
+    for (QStringList::Iterator it = userlist.begin(); it != userlist.end(); ++it )
+    {
+        QPixmap pix(cfgdir->absolutePath() + "/Data/Graphics/Flags/" + *it);
+        QIcon icon(pix.copy(0, 0, 22, 15));
+        if(it->compare("cpu.png") && it->compare("hedgewars.png") && (it->indexOf("cm_") == -1)) // skip cpu and hedgewars flags as well as all community flags
+        {
+            QString flag = QString(*it).replace(QRegExp("^(.*)\\.png"), "\\1");
+            CBFlag->addItem(icon, QString(flag).replace("_", " "), flag);
+        }
+    }
 
     CBFlag->insertSeparator(CBFlag->count());
+
+    // add all community flags
+    for (QStringList::Iterator it = userlist.begin(); it != userlist.end(); ++it )
+    {
+        QPixmap pix(cfgdir->absolutePath() + "/Data/Graphics/Flags/" + *it);
+        QIcon icon(pix.copy(0, 0, 22, 15));
+        if(it->indexOf("cm_") > -1) // skip non community flags this time
+        {
+            QString flag = QString(*it).replace(QRegExp("^(.*)\\.png"), "\\1");
+            CBFlag->addItem(icon, QString(flag).replace("cm_", QComboBox::tr("Community") + ": "), flag);
+        }
+    }
+
+    CBFlag->insertSeparator(CBFlag->count());
+
+    tmpdir.cd(datadir->absolutePath());
+    tmpdir.cd("Graphics/Flags");
+    datalist = tmpdir.entryList(QStringList("*.png"));
+    
     // add all country flags
-    for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+    for (QStringList::Iterator it = datalist.begin(); it != datalist.end(); ++it )
     {
+        if (userlist.contains(*it,Qt::CaseInsensitive)) continue;
         QPixmap pix(datadir->absolutePath() + "/Graphics/Flags/" + *it);
         QIcon icon(pix.copy(0, 0, 22, 15));
         if(it->compare("cpu.png") && it->compare("hedgewars.png") && (it->indexOf("cm_") == -1)) // skip cpu and hedgewars flags as well as all community flags
         {
-            QString flag = (*it).replace(QRegExp("^(.*)\\.png"), "\\1");
+            QString flag = QString(*it).replace(QRegExp("^(.*)\\.png"), "\\1");
             CBFlag->addItem(icon, QString(flag).replace("_", " "), flag);
         }
     }
+
     CBFlag->insertSeparator(CBFlag->count());
+
     // add all community flags
-    for (QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+    for (QStringList::Iterator it = datalist.begin(); it != datalist.end(); ++it )
     {
+        if (userlist.contains(*it,Qt::CaseInsensitive)) continue;
         QPixmap pix(datadir->absolutePath() + "/Graphics/Flags/" + *it);
         QIcon icon(pix.copy(0, 0, 22, 15));
         if(it->indexOf("cm_") > -1) // skip non community flags this time
@@ -272,7 +339,10 @@
 
 void PageEditTeam::CBFort_activated(const QString & fortname)
 {
-    QPixmap pix(datadir->absolutePath() + "/Forts/" + fortname + "L.png");
+    QFile tmp;
+    tmp.setFileName(cfgdir->absolutePath() + "/Data/Forts/" + fortname + "L.png");
+    if (!tmp.exists()) tmp.setFileName(datadir->absolutePath() + "/Forts/" + fortname + "L.png");
+    QPixmap pix(QFileInfo(tmp).absoluteFilePath());
     FortPreview->setPixmap(pix);
 }
 
@@ -282,9 +352,16 @@
     QDir tmpdir;
     mySdli->SDLMusicInit();
     
-    tmpdir.cd(datadir->absolutePath());
-    tmpdir.cd("Sounds/voices");
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Sounds/voices");
     tmpdir.cd(CBVoicepack->currentText());
+    
+    if (!tmpdir.exists()) {
+        tmpdir.cd(datadir->absolutePath());
+        tmpdir.cd("Sounds/voices");
+        tmpdir.cd(CBVoicepack->currentText());
+    }
+
     QStringList list = tmpdir.entryList(QStringList() << "Illgetyou.ogg" << "Incoming.ogg" << "Stupid.ogg" << "Coward.ogg" << "Firstblood.ogg", QDir::Files);
     if (list.size()) {
         sound = Mix_LoadWAV(QString(tmpdir.absolutePath() + "/" + list[rand() % list.size()]).toLocal8Bit().constData());
--- a/QTfrontend/pageoptions.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/pageoptions.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -207,8 +207,8 @@
 
             CBLanguage = new QComboBox(groupMisc);
             QDir tmpdir;
-            tmpdir.cd(datadir->absolutePath());
-            tmpdir.cd("Locale");
+            tmpdir.cd(cfgdir->absolutePath());
+            tmpdir.cd("Data/Locale");
             tmpdir.setFilter(QDir::Files);
             QStringList locs = tmpdir.entryList(QStringList("hedgewars_*.qm"));
             CBLanguage->addItem(QComboBox::tr("(System default)"), QString(""));
@@ -218,6 +218,17 @@
                 CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
             }
 
+            tmpdir.cd(datadir->absolutePath());
+            tmpdir.cd("Locale");
+            tmpdir.setFilter(QDir::Files);
+            QStringList tmplist = tmpdir.entryList(QStringList("hedgewars_*.qm"));
+            for(int i = 0; i < tmplist.count(); i++)
+            {
+                if (locs.contains(tmplist[i])) continue;
+                QLocale loc(tmplist[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1"));
+                CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name());
+            }
+
             MiscLayout->addWidget(CBLanguage, 2, 1);
 
             CBAltDamage = new QCheckBox(groupMisc);
--- a/QTfrontend/pagetraining.cpp	Fri Jun 10 17:28:53 2011 +0000
+++ b/QTfrontend/pagetraining.cpp	Fri Jun 17 11:58:27 2011 -0400
@@ -35,10 +35,21 @@
     CBSelect = new QComboBox(this);
 
     QDir tmpdir;
+    tmpdir.cd(cfgdir->absolutePath());
+    tmpdir.cd("Data/Missions/Training");
+    tmpdir.setFilter(QDir::Files);
+    QStringList userlist = tmpdir.entryList(QStringList("*.lua")).replaceInStrings(QRegExp("^(.*)\\.lua"), "\\1");
+    CBSelect->addItems(userlist);
+
     tmpdir.cd(datadir->absolutePath());
     tmpdir.cd("Missions/Training");
     tmpdir.setFilter(QDir::Files);
-    CBSelect->addItems(tmpdir.entryList(QStringList("*.lua")).replaceInStrings(QRegExp("^(.*)\\.lua"), "\\1"));
+    QStringList tmplist = tmpdir.entryList(QStringList("*.lua")).replaceInStrings(QRegExp("^(.*)\\.lua"), "\\1");
+    QStringList datalist;
+    for (QStringList::Iterator it = tmplist.begin(); it != tmplist.end(); ++it)
+        if (!userlist.contains(*it,Qt::CaseInsensitive)) datalist.append(*it);
+    CBSelect->addItems(datalist);
+
     for(int i = 0; i < CBSelect->count(); i++)
     {
         CBSelect->setItemData(i, CBSelect->itemText(i));
--- a/hedgewars/ArgParsers.inc	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/ArgParsers.inc	Fri Jun 17 11:58:27 2011 -0400
@@ -34,6 +34,7 @@
 procedure internalStartGameWithParameters();
 var tmp: LongInt;
 begin
+    UserPathPrefix:= ParamStr(1);
     val(ParamStr(2), cScreenWidth);
     val(ParamStr(3), cScreenHeight);
     val(ParamStr(4), cBits);
@@ -146,9 +147,10 @@
 var paramIndex: LongInt;
     wrongParameter: boolean;
 begin
-    PathPrefix:= ParamStr(1);
-    recordFileName:= ParamStr(2);
-    paramIndex:= 3;
+    UserPathPrefix:= ParamStr(1);
+    PathPrefix:= ParamStr(2);
+    recordFileName:= ParamStr(3);
+    paramIndex:= 4;
     wrongParameter:= false;
     while (paramIndex <= ParamCount) and not wrongParameter do
         begin
--- a/hedgewars/GSHandlers.inc	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/GSHandlers.inc	Fri Jun 17 11:58:27 2011 -0400
@@ -1601,7 +1601,6 @@
     else
         if (Gear^.State and gsttmpFlag) = 0 then
             Gear^.State := Gear^.State or gsttmpFlag;
-
 end;
 
 procedure doStepRopeAttach(Gear: PGear);
@@ -1709,7 +1708,8 @@
             Message := Message and not gmAttack
             end;
         DeleteGear(Gear)
-        end
+        end;
+    CheckGearDrowning(HHGear)
 end;
 
 procedure doStepRope(Gear: PGear);
--- a/hedgewars/VGSHandlers.inc	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/VGSHandlers.inc	Fri Jun 17 11:58:27 2011 -0400
@@ -46,7 +46,7 @@
         inc(Frame);
         if Frame = vobSDFramesCount then Frame:= 0
         end;
-    X:= X + (cWindSpeedf * 200 + dX + tdX) * Steps;
+    X:= X + (cWindSpeedf * 600 + dX + tdX) * Steps;
     if SuddenDeathDmg then
         Y:= Y + (dY + tdY + cGravityf * vobSDFallSpeed) * Steps
     else
@@ -649,7 +649,7 @@
 
 Gear^.Angle:= round(Gear^.Angle + Steps) mod cMaxAngle;
 
-if round(Gear^.Y) > cWaterLine then
+if (round(Gear^.Y) > cWaterLine) and ((cReducedQuality and rqPlainSplash) = 0) then
     begin
     AddVisualGear(round(Gear^.X), round(Gear^.Y), vgtDroplet);
     DeleteVisualGear(Gear);
--- a/hedgewars/hwengine.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/hwengine.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -214,6 +214,7 @@
     cFullScreen:= false;
     cTimerInterval:= 8;
     PathPrefix:= 'Data';
+    UserPathPrefix:= '.';
     cShowFPS:= {$IFDEF DEBUGFILE}true{$ELSE}false{$ENDIF};
     val(gameArgs[0], ipcPort);
     val(gameArgs[1], cScreenWidth);
@@ -234,10 +235,16 @@
 
     WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
     AddFileLog('Prefix: "' + PathPrefix +'"');
+    AddFileLog('UserPrefix: "' + UserPathPrefix +'"');
     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... ');
@@ -263,6 +270,7 @@
     InitKbdKeyTable();
     AddProgress();
 
+    LoadLocale(UserPathz[ptLocale] + '/en.txt');  // Do an initial load with english
     LoadLocale(Pathz[ptLocale] + '/en.txt');  // Do an initial load with english
     if (Length(cLocaleFName) > 6) then cLocale := Copy(cLocaleFName,1,5)
     else cLocale := Copy(cLocaleFName,1,2);
@@ -270,8 +278,12 @@
         begin
         // Try two letter locale first before trying specific locale overrides
         if (Length(cLocale) > 2) and (Copy(cLocale,1,2) <> 'en') then
-            LoadLocale(Pathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt');
-        LoadLocale(Pathz[ptLocale] + '/' + cLocaleFName);
+            begin
+            LoadLocale(UserPathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt');
+            LoadLocale(Pathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt')
+            end;
+        LoadLocale(UserPathz[ptLocale] + '/' + cLocaleFName);
+        LoadLocale(Pathz[ptLocale] + '/' + cLocaleFName)
         end
     else cLocale := 'en';
 
@@ -430,7 +442,7 @@
 begin
     WriteLn('Wrong argument format: correct configurations is');
     WriteLn();
-    WriteLn('  hwengine <path to data folder> <path to replay file> [options]');
+    WriteLn('  hwengine <path to user hedgewars folder> <path to global data folder> <path to replay file> [options]');
     WriteLn();
     WriteLn('where [options] must be specified either as:');
     WriteLn(' --set-video [screen width] [screen height] [color dept]');
@@ -453,10 +465,10 @@
 
 procedure GetParams;
 begin
-    if (ParamCount < 2) then
+    if (ParamCount < 3) then
         GameType:= gmtSyntax
     else
-        if (ParamCount = 3) then
+        if (ParamCount = 3) and ((ParamStr(3) = '--stats-only') or (ParamStr(3) = 'landpreview')) then
             internalSetGameTypeLandPreviewFromParameters()
         else
             if (ParamCount = cDefaultParamNum) then
--- a/hedgewars/uCommandHandlers.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uCommandHandlers.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -447,6 +447,7 @@
 begin
 if isDeveloperMode then
 begin
+UserPathz[ptMapCurrent]:= UserPathz[ptMaps] + '/' + s;
 Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s;
 InitStepsFlags:= InitStepsFlags or cifMap
 end
@@ -456,6 +457,7 @@
 begin
 if isDeveloperMode then
 begin
+UserPathz[ptCurrTheme]:= UserPathz[ptThemes] + '/' + s;
 Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s;
 Theme:= s;
 InitStepsFlags:= InitStepsFlags or cifTheme
--- a/hedgewars/uLand.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uLand.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -283,7 +283,8 @@
     r, rr: TSDL_Rect;
     x, yd, yu: LongInt;
 begin
-    tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/LandTex', ifCritical or ifIgnoreCaps);
+    tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/LandTex', ifIgnoreCaps);
+    if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/LandTex', ifCritical or ifIgnoreCaps);
     r.y:= 0;
     while r.y < LAND_HEIGHT do
     begin
@@ -298,9 +299,11 @@
     SDL_FreeSurface(tmpsurf);
 
     // freed in freeModule() below
-    LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent);
+    LandBackSurface:= LoadImage(UserPathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent);
+    if LandBackSurface = nil then LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent);
 
-    tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Border', ifCritical or ifIgnoreCaps or ifTransparent);
+    tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/Border', ifIgnoreCaps or ifTransparent);
+    if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Border', ifCritical or ifIgnoreCaps or ifTransparent);
     for x:= 0 to LAND_WIDTH - 1 do
     begin
         yd:= LAND_HEIGHT - 1;
@@ -1104,21 +1107,18 @@
 
 WriteLnToConsole('Generating forts land...');
 
-tmpsurf:= LoadImage(Pathz[ptForts] + '/' + ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
+tmpsurf:= LoadImage(UserPathz[ptForts] + '/' + ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifTransparent or ifIgnoreCaps);
+if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptForts] + '/' + ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
 BlitImageAndGenerateCollisionInfo(leftX+150, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf);
 SDL_FreeSurface(tmpsurf);
 
-tmpsurf:= LoadImage(Pathz[ptForts] + '/' + ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
+tmpsurf:= LoadImage(UserPathz[ptForts] + '/' + ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifTransparent or ifIgnoreCaps);
+if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptForts] + '/' + ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
 BlitImageAndGenerateCollisionInfo(rightX - 150 - tmpsurf^.w, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf);
 SDL_FreeSurface(tmpsurf);
 end;
 
-// Hi unC0Rr.
-// This is a function that Tiy assures me would not be good for gameplay.
-// It allows the setting of arbitrary portions of landscape as indestructible, or regular, or even blank.
-// He said I could add it here only when I swore it would not impact gameplay.  Which, as far as I can tell, is true.
-// I would just like to play with it with my friends if you do not mind.
-// Can allow for amusing maps.
+// Loads Land[] from an image, allowing overriding standard collision
 procedure LoadMask(mapName: shortstring);
 var tmpsurf: PSDL_Surface;
     p: PLongwordArray;
@@ -1167,16 +1167,19 @@
 isMap:= true;
 WriteLnToConsole('Loading land from file...');
 AddProgress;
-tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/map', ifAlpha or ifTransparent or ifIgnoreCaps);
+tmpsurf:= LoadImage(UserPathz[ptMapCurrent] + '/map', ifAlpha or ifTransparent or ifIgnoreCaps);
+if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/map', ifAlpha or ifTransparent or ifIgnoreCaps);
 if tmpsurf = nil then
 begin
     mapName:= ExtractFileName(Pathz[ptMapCurrent]);
-    tmpsurf:= LoadImage(Pathz[ptMissionMaps] + '/' + mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
+    tmpsurf:= LoadImage(UserPathz[ptMissionMaps] + '/' + mapName + '/map', ifAlpha or ifTransparent or ifIgnoreCaps);
+    if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptMissionMaps] + '/' + mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps);
 end;
 TryDo((tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT), 'Map dimensions too big!', true);
 
 // unC0Rr - should this be passed from the GUI? I am not sure which layer does what
-s:= Pathz[ptMapCurrent] + '/map.cfg';
+s:= UserPathz[ptMapCurrent] + '/map.cfg';
+if not FileExists(s) then s:= Pathz[ptMapCurrent] + '/map.cfg';
 WriteLnToConsole('Fetching map HH limit');
 {$I-}
 Assign(f, s);
--- a/hedgewars/uLandObjects.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uLandObjects.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -196,7 +196,9 @@
 if x1 > 0 then
 begin
     bRes:= true;
-    tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
+    tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
+    if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps);
+    if tmpsurf = nil then tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/Girder', ifTransparent or ifIgnoreCaps);
     if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptGraphics] + '/Girder', ifCritical or ifTransparent or ifIgnoreCaps);
 
     rr.x:= x1;
@@ -383,7 +385,8 @@
 
 AddProgress;
 
-s:= Pathz[ptCurrTheme] + '/' + cThemeCFGFilename;
+s:= UserPathz[ptCurrTheme] + '/' + cThemeCFGFilename;
+if not FileExists(s) then s:= Pathz[ptCurrTheme] + '/' + cThemeCFGFilename;
 WriteLnToConsole('Reading objects info...');
 Assign(f, s);
 {$I-}
@@ -469,7 +472,8 @@
         with ThemeObjects.objs[Pred(ThemeObjects.Count)] do
             begin
             i:= Pos(',', s);
-            Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
+            Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps);
+            if Surf = nil then Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
             Width:= Surf^.w;
             Height:= Surf^.h;
             Delete(s, 1, i);
@@ -525,7 +529,8 @@
         with SprayObjects.objs[Pred(SprayObjects.Count)] do
             begin
             i:= Pos(',', s);
-            Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
+            Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps);
+            if Surf = nil then Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps);
             Width:= Surf^.w;
             Height:= Surf^.h;
             Delete(s, 1, i);
--- a/hedgewars/uMisc.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uMisc.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -79,7 +79,7 @@
 
 // update header information and file name
 
-filename:= ParamStr(1) + '/Screenshots/' + filename + '.bmp';
+filename:= UserPathPrefix + '/Screenshots/' + filename + '.bmp';
 
 head[$02]:= (size + 54) and $ff;
 head[$03]:= ((size + 54) shr 8) and $ff;
--- a/hedgewars/uRender.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uRender.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -266,6 +266,7 @@
 procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt);
 var row, col, numFramesFirstCol: LongInt;
 begin
+if SpritesData[Sprite].imageHeight = 0 then exit;
 numFramesFirstCol:= SpritesData[Sprite].imageHeight div SpritesData[Sprite].Height;
 row:= Frame mod numFramesFirstCol;
 col:= Frame div numFramesFirstCol;
--- a/hedgewars/uScript.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uScript.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -72,7 +72,8 @@
     uRenderUtils,
     uTextures,
     uLandGraphics,
-    SDLh; 
+    SDLh,
+    sysutils; 
 
 var luaState : Plua_State;
     ScriptAmmoLoadout : shortstring;
@@ -1220,6 +1221,18 @@
     lc_getdatapath:= 1
 end;
 
+function lc_getuserdatapath(L : Plua_State) : LongInt; Cdecl;
+begin
+    if lua_gettop(L) <> 0 then
+        begin
+        LuaError('Lua: Wrong number of parameters passed to GetUserDataPath!');
+        lua_pushnil(L);
+        end
+    else
+        lua_pushstring(L, str2pchar(UserPathz[ptData]));
+    lc_getuserdatapath:= 1
+end;
+
 function lc_maphasborder(L : Plua_State) : LongInt; Cdecl;
 begin
     if lua_gettop(L) <> 0 then
@@ -1424,8 +1437,11 @@
 
 procedure ScriptLoad(name : shortstring);
 var ret : LongInt;
+      s : shortstring;
 begin
-ret:= luaL_loadfile(luaState, Str2PChar(Pathz[ptData] + '/' + name));
+s:= UserPathz[ptData] + '/' + name;
+if not FileExists(s) then s:= Pathz[ptData] + '/' + name;
+ret:= luaL_loadfile(luaState, Str2PChar(s));
 if ret <> 0 then
     begin
     LuaError('Lua: Failed to load ' + name + '(error ' + IntToStr(ret) + ')');
@@ -1722,6 +1738,7 @@
 lua_register(luaState, 'GetRandom', @lc_getrandom);
 lua_register(luaState, 'SetWind', @lc_setwind);
 lua_register(luaState, 'GetDataPath', @lc_getdatapath);
+lua_register(luaState, 'GetUserDataPath', @lc_getuserdatapath);
 lua_register(luaState, 'MapHasBorder', @lc_maphasborder);
 lua_register(luaState, 'GetHogHat', @lc_gethoghat);
 lua_register(luaState, 'SetHogHat', @lc_sethoghat);
--- a/hedgewars/uSound.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uSound.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -106,13 +106,23 @@
     if cLocale <> 'en' then
         begin
         locName:= name+'_'+cLocale;
-        path:= Pathz[ptVoices] + '/' + locName;
+        path:= UserPathz[ptVoices] + '/' + locName;
         if DirectoryExists(path) then name:= locName
-        else if Length(cLocale) > 2 then
+        else
             begin
-            locName:= name+'_'+Copy(cLocale,1,2);
             path:= Pathz[ptVoices] + '/' + locName;
             if DirectoryExists(path) then name:= locName
+            else if Length(cLocale) > 2 then
+                begin
+                locName:= name+'_'+Copy(cLocale,1,2);
+                path:= UserPathz[ptVoices] + '/' + locName;
+                if DirectoryExists(path) then name:= locName
+                else
+                    begin
+                    path:= Pathz[ptVoices] + '/' + locName;
+                    if DirectoryExists(path) then name:= locName
+                    end
+                end
             end
         end;
 
@@ -209,7 +219,8 @@
                   sndMolotov, sndMortar, sndRideOfTheValkyries, sndYoohoo])
             and (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
         begin
-            s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
+            s:= UserPathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
+            if not FileExists(s) then s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
             WriteToConsole(msgLoading + s + ' ');
             defVoicepack^.chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
             TryDo(defVoicepack^.chunks[i] <> nil, msgFailed, true);
@@ -247,7 +258,8 @@
     begin
         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
         begin
-            s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
+            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;
             WriteToConsole(msgLoading + s + ' ');
             voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
             if voicepack^.chunks[snd] = nil then
@@ -261,7 +273,8 @@
     begin
         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
         begin
-            s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
+            s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
+            if not FileExists(s) then s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
             defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
             TryDo(defVoicepack^.chunks[snd] <> nil, msgFailed, true);
@@ -300,7 +313,8 @@
     begin
         if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then
         begin
-            s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
+            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;
             WriteToConsole(msgLoading + s + ' ');
             voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
             if voicepack^.chunks[snd] = nil then
@@ -314,7 +328,8 @@
     begin
         if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then
         begin
-            s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
+            s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
+            if not FileExists(s) then s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName;
             WriteToConsole(msgLoading + s + ' ');
             defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
             TryDo(defVoicepack^.chunks[snd] <> nil, msgFailed, true);
@@ -360,7 +375,8 @@
     if (not isSoundEnabled) or (MusicFN = '') or (not isMusicEnabled) then
         exit;
 
-    s:= PathPrefix + '/Music/' + MusicFN;
+    s:= UserPathPrefix + '/Data/Music/' + MusicFN;
+    if not FileExists(s) then s:= PathPrefix + '/Music/' + MusicFN;
     WriteToConsole(msgLoading + s + ' ');
 
     Mus:= Mix_LoadMUS(Str2PChar(s));
--- a/hedgewars/uStore.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uStore.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -82,7 +82,8 @@
     Color, i: Longword;
     s : shortstring;
 begin
-s:= Pathz[ptGraphics] + '/' + cCHFileName;
+s:= UserPathz[ptGraphics] + '/' + cCHFileName;
+if not FileExists(s+'.png') then s:= Pathz[ptGraphics] + '/' + cCHFileName;
 tmpsurf:= LoadImage(s, ifAlpha or ifCritical);
 
 for t:= 0 to Pred(TeamsCount) do
@@ -168,9 +169,10 @@
         else if Flag = 'cpu' then
             Flag:= 'hedgewars';
 
-        flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone);
-        if flagsurf = nil then
-            flagsurf:= LoadImage(Pathz[ptFlags] + '/hedgewars', ifNone);
+        flagsurf:= LoadImage(UserPathz[ptFlags] + '/' + Flag, ifNone);
+        if flagsurf = nil then flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone);
+        if flagsurf = nil then flagsurf:= LoadImage(UserPathz[ptFlags] + '/hedgewars', ifNone);
+        if flagsurf = nil then flagsurf:= LoadImage(Pathz[ptFlags] + '/hedgewars', ifNone);
         TryDo(flagsurf <> nil, 'Failed to load flag "' + Flag + '" as well as the default flag', true);
         copyToXY(flagsurf, texsurf, 2, 2);
         SDL_FreeSurface(flagsurf);
@@ -204,7 +206,8 @@
                         end
                     end;
         end;
-    MissionIcons:= LoadImage(Pathz[ptGraphics] + '/missions', ifCritical);
+    MissionIcons:= LoadImage(UserPathz[ptGraphics] + '/missions', ifNone);
+    if MissionIcons = nil then MissionIcons:= LoadImage(Pathz[ptGraphics] + '/missions', ifCritical);
     iconsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, 28, 28, 32, RMask, GMask, BMask, AMask);
     if iconsurf <> nil then
         begin
@@ -241,7 +244,9 @@
         with TeamsArray[t]^ do
             begin
             if GraveName = '' then GraveName:= 'Statue';
-            texsurf:= LoadImage(Pathz[ptGraves] + '/' + GraveName, ifTransparent);
+            texsurf:= LoadImage(UserPathz[ptGraves] + '/' + GraveName, ifTransparent);
+            if texsurf = nil then texsurf:= LoadImage(Pathz[ptGraves] + '/' + GraveName, ifTransparent);
+            if texsurf = nil then texsurf:= LoadImage(UserPathz[ptGraves] + '/Statue', ifTransparent);
             if texsurf = nil then texsurf:= LoadImage(Pathz[ptGraves] + '/Statue', ifCritical or ifTransparent);
             GraveTex:= Surface2Tex(texsurf, false);
             SDL_FreeSurface(texsurf)
@@ -258,7 +263,8 @@
 for fi:= Low(THWFont) to High(THWFont) do
     with Fontz[fi] do
         begin
-        s:= Pathz[ptFonts] + '/' + Name;
+        s:= UserPathz[ptFonts] + '/' + Name;
+        if not FileExists(s) then s:= Pathz[ptFonts] + '/' + Name;
         WriteToConsole(msgLoading + s + ' (' + inttostr(Height) + 'pt)... ');
         Handle:= TTF_OpenFont(Str2PChar(s), Height);
         SDLTry(Handle <> nil, true);
@@ -281,13 +287,20 @@
         begin
             if AltPath = ptNone then
                 if ii in [sprHorizontL, sprHorizontR, sprSkyL, sprSkyR] then // FIXME: hack
-                    tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent)
+                    begin
+                    tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent);
+                    if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent)
+                    end
                 else
-                    tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent or ifCritical)
+                    begin
+                    tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent);
+                    if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent or ifCritical)
+                    end
             else begin
-                tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent);
-                if tmpsurf = nil then
-                    tmpsurf:= LoadImage(Pathz[AltPath] + '/' + FileName, ifAlpha or ifCritical or ifTransparent);
+                tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent);
+                if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent);
+                if tmpsurf = nil then tmpsurf:= LoadImage(UserPathz[AltPath] + '/' + FileName, ifAlpha or ifTransparent);
+                if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[AltPath] + '/' + FileName, ifAlpha or ifCritical or ifTransparent);
                 end;
 
             if tmpsurf <> nil then
@@ -324,7 +337,8 @@
 
 AddProgress;
 
-tmpsurf:= LoadImage(Pathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifCritical or ifTransparent);
+tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifTransparent);
+if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifCritical or ifTransparent);
 HHTexture:= Surface2Tex(tmpsurf, false);
 SDL_FreeSurface(tmpsurf);
 
@@ -475,7 +489,8 @@
 procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring);
 var texsurf: PSDL_Surface;
 begin
-    texsurf:= LoadImage(Pathz[ptHats] + '/' + newHat, ifNone);
+    texsurf:= LoadImage(UserPathz[ptHats] + '/' + newHat, ifNone);
+    if texsurf = nil then texsurf:= LoadImage(Pathz[ptHats] + '/' + newHat, ifNone);
 
     // only do something if the hat could be loaded
     if texsurf <> nil then
@@ -667,7 +682,8 @@
     if Step = 0 then
     begin
         WriteToConsole(msgLoading + 'progress sprite: ');
-        texsurf:= LoadImage(Pathz[ptGraphics] + '/Progress', ifCritical or ifTransparent);
+        texsurf:= LoadImage(UserPathz[ptGraphics] + '/Progress', ifTransparent);
+        if texsurf = nil then texsurf:= LoadImage(Pathz[ptGraphics] + '/Progress', ifCritical or ifTransparent);
 
         ProgrTex:= Surface2Tex(texsurf, false);
 
@@ -906,9 +922,11 @@
 {$ENDIF}
     // load engine icon
 {$IFDEF DARWIN}
-    ico:= LoadImage(Pathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps);
+    ico:= LoadImage(UserPathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps);
+    if ico = nil then ico:= LoadImage(Pathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps);
 {$ELSE}
-    ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps);
+    ico:= LoadImage(UserPathz[ptGraphics] + '/hwengine', ifIgnoreCaps);
+    if ico = nil then ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps);
 {$ENDIF}
     if ico <> nil then
     begin
--- a/hedgewars/uUtils.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uUtils.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -359,7 +359,7 @@
             i:= 0;
             while(i < 7) do
             begin
-                assign(f, ParamStr(1) + '/Logs/' + cLogfileBase + inttostr(i) + '.log');
+                assign(f, UserPathPrefix + '/Logs/' + cLogfileBase + inttostr(i) + '.log');
                 rewrite(f);
                 if IOResult = 0 then break;
                 inc(i)
--- a/hedgewars/uVariables.pas	Fri Jun 10 17:28:53 2011 +0000
+++ b/hedgewars/uVariables.pas	Fri Jun 17 11:58:27 2011 -0400
@@ -37,6 +37,7 @@
     cInitVolume     : LongInt     = 100;
     cTimerInterval  : LongInt     = 8;
     PathPrefix      : shortstring = './';
+    UserPathPrefix  : shortstring = './';
     cShowFPS        : boolean     = false;
     cAltDamage      : boolean     = true;
     cReducedQuality : LongWord    = rqNone;
@@ -101,6 +102,7 @@
 
     // originally from uConsts
     Pathz: array[TPathType] of shortstring;
+    UserPathz: array[TPathType] of shortstring;
     CountTexz: array[1..Pred(AMMO_INFINITE)] of PTexture;
     LAND_WIDTH       : Word;
     LAND_HEIGHT      : Word;
@@ -2402,6 +2404,7 @@
     cInitVolume     := 100;
     cTimerInterval  := 8;
     PathPrefix      := './';
+    UserPathPrefix  := './';
     cShowFPS        := false;
     cAltDamage      := true;
     cReducedQuality := rqNone;