# HG changeset patch # User nemo # Date 1307927208 14400 # Node ID 46ddaf14509dcda335e8dbec65c144d7e10e6cbe # Parent 963d787a25c2142616d00e507a10514f387ebfde Enable ~/.hedgewars/Data (or platform equivalent) to override/extend pretty much everything in system Data dir. Obviously desyncing can occur, so this is at user's own risk. Should simplify map etc install. Needs testing. diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/SDLs.cpp --- a/QTfrontend/SDLs.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/SDLs.cpp Sun Jun 12 21:06:48 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); diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/chatwidget.cpp --- a/QTfrontend/chatwidget.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/chatwidget.cpp Sun Jun 12 21:06:48 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); diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/gamecfgwidget.cpp --- a/QTfrontend/gamecfgwidget.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/gamecfgwidget.cpp Sun Jun 12 21:06:48 2011 -0400 @@ -61,7 +61,9 @@ QString script = (*scriptList)[i].remove(".lua", Qt::CaseInsensitive); QList 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; diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/hats.cpp --- a/QTfrontend/hats.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/hats.cpp Sun Jun 12 21:06:48 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"); diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/hwform.cpp Sun Jun 12 21:06:48 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.")); diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/main.cpp --- a/QTfrontend/main.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/main.cpp Sun Jun 12 21:06:48 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); } diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/mapContainer.cpp --- a/QTfrontend/mapContainer.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/mapContainer.cpp Sun Jun 12 21:06:48 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; } diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/namegen.cpp --- a/QTfrontend/namegen.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/namegen.cpp Sun Jun 12 21:06:48 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) { diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/pageeditteam.cpp --- a/QTfrontend/pageeditteam.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/pageeditteam.cpp Sun Jun 12 21:06:48 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()); diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/pageoptions.cpp --- a/QTfrontend/pageoptions.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/pageoptions.cpp Sun Jun 12 21:06:48 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); diff -r 963d787a25c2 -r 46ddaf14509d QTfrontend/pagetraining.cpp --- a/QTfrontend/pagetraining.cpp Sun Jun 12 14:45:26 2011 -0400 +++ b/QTfrontend/pagetraining.cpp Sun Jun 12 21:06:48 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)); diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/ArgParsers.inc --- a/hedgewars/ArgParsers.inc Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/ArgParsers.inc Sun Jun 12 21:06:48 2011 -0400 @@ -34,6 +34,7 @@ procedure internalStartGameWithParameters(); var tmp: LongInt; begin + UserPathPrefix:= ParamStr(1)+'/Data'; 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)+'/Data'; + PathPrefix:= ParamStr(2); + recordFileName:= ParamStr(3); + paramIndex:= 4; wrongParameter:= false; while (paramIndex <= ParamCount) and not wrongParameter do begin diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/hwengine.pas Sun Jun 12 21:06:48 2011 -0400 @@ -214,6 +214,7 @@ cFullScreen:= false; cTimerInterval:= 8; PathPrefix:= 'Data'; + UserPathPrefix:= 'Data'; cShowFPS:= {$IFDEF DEBUGFILE}true{$ELSE}false{$ENDIF}; val(gameArgs[0], ipcPort); val(gameArgs[1], cScreenWidth); @@ -234,10 +235,14 @@ 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 then UserPathz[p]:= UserPathPrefix + '/' + Pathz[p]; + + for p:= Succ(Low(TPathType)) to High(TPathType) do if p <> ptMapCurrent then Pathz[p]:= PathPrefix + '/' + Pathz[p]; WriteToConsole('Init SDL... '); @@ -263,6 +268,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 +276,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 +440,7 @@ begin WriteLn('Wrong argument format: correct configurations is'); WriteLn(); - WriteLn(' hwengine [options]'); + WriteLn(' hwengine [options]'); WriteLn(); WriteLn('where [options] must be specified either as:'); WriteLn(' --set-video [screen width] [screen height] [color dept]'); @@ -453,10 +463,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 diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uCommandHandlers.pas Sun Jun 12 21:06:48 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 diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uLand.pas --- a/hedgewars/uLand.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uLand.pas Sun Jun 12 21:06:48 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,11 +1167,13 @@ 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); diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uLandObjects.pas --- a/hedgewars/uLandObjects.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uLandObjects.pas Sun Jun 12 21:06:48 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 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); diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uScript.pas --- a/hedgewars/uScript.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uScript.pas Sun Jun 12 21:06:48 2011 -0400 @@ -1220,6 +1220,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 @@ -1722,6 +1734,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); diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uSound.pas --- a/hedgewars/uSound.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uSound.pas Sun Jun 12 21:06:48 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 + '/Music/' + MusicFN; + if not FileExists(s) then s:= PathPrefix + '/Music/' + MusicFN; WriteToConsole(msgLoading + s + ' '); Mus:= Mix_LoadMUS(Str2PChar(s)); diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uStore.pas --- a/hedgewars/uStore.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uStore.pas Sun Jun 12 21:06:48 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 diff -r 963d787a25c2 -r 46ddaf14509d hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Sun Jun 12 14:45:26 2011 -0400 +++ b/hedgewars/uVariables.pas Sun Jun 12 21:06:48 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;