diff -Nru openmw-0.35.0/apps/esmtool/record.cpp openmw-0.35.1/apps/esmtool/record.cpp --- openmw-0.35.0/apps/esmtool/record.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/esmtool/record.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -535,10 +535,10 @@ std::cout << " Specialization: " << specializationLabel(mData.mData.mSpecialization) << " (" << mData.mData.mSpecialization << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0]) + std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][0]) << " (" << mData.mData.mSkills[i][0] << ")" << std::endl; for (int i = 0; i != 5; i++) - std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1]) + std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; } @@ -837,7 +837,7 @@ std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; @@ -849,7 +849,7 @@ std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; + std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) std::cout << " Inventory: Level: " << iit->mLevel << " Item: " << iit->mId << std::endl; diff -Nru openmw-0.35.0/apps/essimporter/converter.hpp openmw-0.35.1/apps/essimporter/converter.hpp --- openmw-0.35.0/apps/essimporter/converter.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/converter.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -18,6 +18,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -387,24 +388,50 @@ virtual void read(ESM::ESMReader &esm) { std::string itemid = esm.getHNString("NAME"); + Misc::StringUtils::toLower(itemid); while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) { if (esm.retSubName().toString() == "FNAM") { std::string factionid = esm.getHString(); - mFactionStolenItems.insert(std::make_pair(itemid, factionid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(factionid), true)); } else { std::string ownerid = esm.getHString(); - mStolenItems.insert(std::make_pair(itemid, ownerid)); + mStolenItems[itemid].insert(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); } } } + virtual void write(ESM::ESMWriter &esm) + { + ESM::StolenItems items; + for (std::map >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + std::map, int> owners; + for (std::set::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt) + { + owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second) + // Since OpenMW doesn't suffer from the owner contamination bug, + // it needs a count argument. But for legacy savegames, we don't know + // this count, so must assume all items of that ID are stolen, + // like vanilla MW did. + ,std::numeric_limits::max())); + } + + items.mStolenItems.insert(std::make_pair(it->first, owners)); + } + + esm.startRecord(ESM::REC_STLN); + items.write(esm); + esm.endRecord(ESM::REC_STLN); + } + private: - std::multimap mStolenItems; - std::multimap mFactionStolenItems; + typedef std::pair Owner; // + + std::map > mStolenItems; }; /// Seen responses for a dialogue topic? diff -Nru openmw-0.35.0/apps/essimporter/convertplayer.cpp openmw-0.35.1/apps/essimporter/convertplayer.cpp --- openmw-0.35.0/apps/essimporter/convertplayer.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/convertplayer.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -17,6 +17,8 @@ } for (int i=0; i<8; ++i) out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + for (int i=0; i<27; ++i) + out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) @@ -24,9 +26,6 @@ if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) out.mObject.mCreatureStats.mDrawState = 2; - // TODO: convert PNAM.mSkillProgress, needs to be converted to uniform scale - // (or change openmw to accept non-uniform skill progress) - firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); diff -Nru openmw-0.35.0/apps/essimporter/importacdt.hpp openmw-0.35.1/apps/essimporter/importacdt.hpp --- openmw-0.35.0/apps/essimporter/importacdt.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/importacdt.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -43,13 +43,17 @@ float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes unsigned char mUnknown4[4]; unsigned int mGoldPool; - unsigned char mUnknown5[4]; + unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe + // this one is for respawning? + unsigned char mUnknown5[3]; }; struct ACSC { unsigned char mUnknown1[17]; unsigned char mFlags; // ACSCFlags - unsigned char mUnknown2[94]; + unsigned char mUnknown2[22]; + unsigned char mCorpseClearCountdown; // hours? + unsigned char mUnknown3[71]; }; #pragma pack(pop) @@ -61,7 +65,7 @@ bool mHasACSC; ACSC mACSC; - int mSkills[27][2]; + int mSkills[27][2]; // skills, base and modified // creature combat stats, base and modified // I think these can be ignored in the conversion, because it is not possible diff -Nru openmw-0.35.0/apps/essimporter/importcellref.cpp openmw-0.35.1/apps/essimporter/importcellref.cpp --- openmw-0.35.0/apps/essimporter/importcellref.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/importcellref.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -22,7 +22,7 @@ ActorData::load(esm); if (esm.isNextSub("LVCR")) { - // occurs on leveled creature spawner references + // occurs on levelled creature spawner references // probably some identifier for the creature that has been spawned? unsigned char lvcr; esm.getHT(lvcr); @@ -32,7 +32,7 @@ mEnabled = true; esm.getHNOT(mEnabled, "ZNAM"); - // DATA should occur for all references, except leveled creature spawners + // DATA should occur for all references, except levelled creature spawners // I've seen DATA *twice* on a creature record, and with the exact same content too! weird // alarmvoi0000.ess esm.getHNOT(mPos, "DATA", 24); diff -Nru openmw-0.35.0/apps/essimporter/importcrec.cpp openmw-0.35.1/apps/essimporter/importcrec.cpp --- openmw-0.35.0/apps/essimporter/importcrec.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/importcrec.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -14,10 +14,10 @@ float scale; esm.getHNOT(scale, "XSCL"); - // FIXME: use AiPackageList, need to fix getSubName() + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff -Nru openmw-0.35.0/apps/essimporter/importcrec.hpp openmw-0.35.1/apps/essimporter/importcrec.hpp --- openmw-0.35.0/apps/essimporter/importcrec.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/importcrec.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,7 @@ #define OPENMW_ESSIMPORT_CREC_H #include "importinventory.hpp" +#include namespace ESM { @@ -17,6 +18,7 @@ int mIndex; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader& esm); }; diff -Nru openmw-0.35.0/apps/essimporter/importnpcc.cpp openmw-0.35.1/apps/essimporter/importnpcc.cpp --- openmw-0.35.0/apps/essimporter/importnpcc.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/importnpcc.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -9,10 +9,9 @@ { esm.getHNT(mNPDT, "NPDT"); - // FIXME: use AiPackageList, need to fix getSubName() while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff -Nru openmw-0.35.0/apps/essimporter/importnpcc.hpp openmw-0.35.1/apps/essimporter/importnpcc.hpp --- openmw-0.35.0/apps/essimporter/importnpcc.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/essimporter/importnpcc.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -27,6 +27,7 @@ } mNPDT; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader &esm); }; diff -Nru openmw-0.35.0/apps/launcher/datafilespage.cpp openmw-0.35.1/apps/launcher/datafilespage.cpp --- openmw-0.35.0/apps/launcher/datafilespage.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/datafilespage.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -20,6 +20,9 @@ #include "utils/textinputdialog.hpp" #include "utils/profilescombobox.hpp" + +const char *Launcher::DataFilesPage::mDefaultContentListName = "Default"; + Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings, Config::LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) @@ -48,9 +51,9 @@ ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); //combo box - ui.profilesComboBox->addItem ("Default"); + ui.profilesComboBox->addItem(mDefaultContentListName); ui.profilesComboBox->setPlaceholderText (QString("Select a Content List...")); - ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String("Default"))); + ui.profilesComboBox->setCurrentIndex(ui.profilesComboBox->findText(QLatin1String(mDefaultContentListName))); // Add the actions to the toolbuttons ui.newProfileButton->setDefaultAction (ui.newProfileAction); @@ -284,7 +287,7 @@ void Launcher::DataFilesPage::checkForDefaultProfile() { //don't allow deleting "Default" profile - bool success = (ui.profilesComboBox->currentText() != "Default"); + bool success = (ui.profilesComboBox->currentText() != mDefaultContentListName); ui.deleteProfileAction->setEnabled (success); ui.profilesComboBox->setEditEnabled (success); diff -Nru openmw-0.35.0/apps/launcher/datafilespage.hpp openmw-0.35.1/apps/launcher/datafilespage.hpp --- openmw-0.35.0/apps/launcher/datafilespage.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/datafilespage.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -58,6 +58,10 @@ void on_newProfileAction_triggered(); void on_deleteProfileAction_triggered(); + public: + /// Content List that is always present + const static char *mDefaultContentListName; + private: TextInputDialog *mProfileDialog; diff -Nru openmw-0.35.0/apps/launcher/graphicspage.cpp openmw-0.35.1/apps/launcher/graphicspage.cpp --- openmw-0.35.0/apps/launcher/graphicspage.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/graphicspage.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,7 +10,7 @@ #define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #endif // MAC_OS_X_VERSION_MIN_REQUIRED -#include +#include #include #include @@ -67,7 +67,7 @@ } catch(Ogre::Exception &ex) { - QString ogreError = QString::fromStdString(ex.getFullDescription().c_str()); + QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str()); QMessageBox msgBox; msgBox.setWindowTitle("Error creating Ogre::Root"); msgBox.setIcon(QMessageBox::Critical); @@ -135,7 +135,7 @@ msgBox.setWindowTitle(tr("Error receiving number of screens")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return false; } @@ -237,7 +237,7 @@ opt_it != i->second.possibleValues.end(); ++opt_it, ++idx) { if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { - result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); + result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified(); } } } @@ -266,7 +266,7 @@ msgBox.setWindowTitle(tr("Error receiving resolutions")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } @@ -279,7 +279,7 @@ msgBox.setWindowTitle(tr("Error receiving resolutions")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromUtf8(SDL_GetError()) + "
"); msgBox.exec(); return result; } diff -Nru openmw-0.35.0/apps/launcher/main.cpp openmw-0.35.1/apps/launcher/main.cpp --- openmw-0.35.0/apps/launcher/main.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/main.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,4 +1,5 @@ #include +#include #include #include @@ -23,9 +24,11 @@ SDL_SetMainReady(); if (SDL_Init(SDL_INIT_VIDEO) != 0) { - qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); + qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError()); return 0; } + signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher, + // so reset SIGINT which SDL wants to redirect to an SDL_Quit event. QApplication app(argc, argv); diff -Nru openmw-0.35.0/apps/launcher/maindialog.cpp openmw-0.35.1/apps/launcher/maindialog.cpp --- openmw-0.35.0/apps/launcher/maindialog.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/maindialog.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -61,6 +61,7 @@ QString revision(OPENMW_VERSION_COMMITHASH); QString tag(OPENMW_VERSION_TAGHASH); + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); if (!revision.isEmpty() && !tag.isEmpty()) { if (revision == tag) { @@ -238,24 +239,8 @@ current = previous; int currentIndex = iconWidget->row(current); -// int previousIndex = iconWidget->row(previous); - pagesWidget->setCurrentIndex(currentIndex); - - // DataFilesPage *previousPage = dynamic_cast(pagesWidget->widget(previousIndex)); - // DataFilesPage *currentPage = dynamic_cast(pagesWidget->widget(currentIndex)); - - // //special call to update/save data files page list view when it's displayed/hidden. - // if (previousPage) - // { - // if (previousPage->objectName() == "DataFilesPage") - // previousPage->saveSettings(); - // } - // else if (currentPage) - // { - // if (currentPage->objectName() == "DataFilesPage") - // currentPage->loadSettings(); - // } + mSettingsPage->resetProgressBar(); } bool Launcher::MainDialog::setupLauncherSettings() diff -Nru openmw-0.35.0/apps/launcher/settingspage.cpp openmw-0.35.1/apps/launcher/settingspage.cpp --- openmw-0.35.0/apps/launcher/settingspage.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/settingspage.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,6 +11,7 @@ #include #include "utils/textinputdialog.hpp" +#include "datafilespage.hpp" using namespace Process; @@ -38,6 +39,7 @@ mWizardInvoker = new ProcessInvoker(); mImporterInvoker = new ProcessInvoker(); + resetProgressBar(); connect(mWizardInvoker->getProcess(), SIGNAL(started()), this, SLOT(wizardStarted())); @@ -93,7 +95,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked() { - saveSettings(); + mMain->writeSettings(); if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return; @@ -101,7 +103,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() { - saveSettings(); + mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); @@ -140,8 +142,13 @@ qDebug() << "arguments " << arguments; + // start the progress bar as a "bouncing ball" + progressBar->setMaximum(0); + progressBar->setValue(0); if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) - return; + { + resetProgressBar(); + } } void Launcher::SettingsPage::on_browseButton_clicked() @@ -196,27 +203,35 @@ void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode != 0 || exitStatus == QProcess::CrashExit) - return; - - // Re-read the settings in their current state - mMain->reloadSettings(); + { + resetProgressBar(); - // Import selected data files from openmw.cfg - if (addonsCheckBox->isChecked()) + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Importer finished")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(tr("Failed to import settings from INI file.")); + msgBox.exec(); + } + else { - if (mProfileDialog->exec() == QDialog::Accepted) - { - const QString profile(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(profile); - mLauncherSettings.setContentList(profile, files); - } + // indicate progress finished + progressBar->setMaximum(1); + progressBar->setValue(1); + + // Importer may have changed settings, so refresh + mMain->reloadSettings(); } - mMain->reloadSettings(); importerButton->setEnabled(true); } +void Launcher::SettingsPage::resetProgressBar() +{ + // set progress bar to 0 % + progressBar->reset(); +} + void Launcher::SettingsPage::updateOkButton(const QString &text) { // We do this here because we need to access the profiles diff -Nru openmw-0.35.0/apps/launcher/settingspage.hpp openmw-0.35.1/apps/launcher/settingspage.hpp --- openmw-0.35.0/apps/launcher/settingspage.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/launcher/settingspage.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -29,6 +29,9 @@ void saveSettings(); bool loadSettings(); + + /// set progress bar on page to 0% + void resetProgressBar(); private slots: @@ -57,7 +60,6 @@ MainDialog *mMain; TextInputDialog *mProfileDialog; - }; } diff -Nru openmw-0.35.0/apps/mwiniimporter/importer.cpp openmw-0.35.1/apps/mwiniimporter/importer.cpp --- openmw-0.35.0/apps/mwiniimporter/importer.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/mwiniimporter/importer.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,7 +8,8 @@ #include #include -#include +#include +#include #include namespace bfs = boost::filesystem; @@ -660,7 +661,7 @@ return str.str(); } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); @@ -719,7 +720,7 @@ return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; @@ -825,10 +826,14 @@ } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { - std::vector contentFiles; +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { + std::vector > contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); + std::time_t defaultTime = 0; + + // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini + const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { @@ -845,18 +850,20 @@ Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { - contentFiles.push_back(*entry); + boost::filesystem::path filepath(gameFilesDir); + filepath /= *entry; + contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry)); } } - - gameFile = ""; } cfg.erase("content"); cfg.insert( std::make_pair("content", std::vector() ) ); - for(std::vector::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { - cfg["content"].push_back(*it); + // this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed. + sort(contentFiles.begin(), contentFiles.end()); + for(std::vector >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { + cfg["content"].push_back(it->second); } } @@ -873,3 +880,27 @@ { mEncoding = encoding; } + +std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) +{ + std::time_t writeTime(defaultTime); + if (boost::filesystem::exists(filename)) + { + // FixMe: remove #if when Boost dependency for Linux builds updated + // This allows Linux to build until then +#if (BOOST_VERSION >= 104800) + // need to resolve any symlinks so that we get time of file, not symlink + boost::filesystem::path resolved = boost::filesystem::canonical(filename); +#else + boost::filesystem::path resolved = filename; +#endif + writeTime = boost::filesystem::last_write_time(resolved); + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << + ") " << asctime(localtime(&writeTime)) << std::endl; + } + else + { + std::cout << "content file: " << filename << " not found" << std::endl; + } + return writeTime; +} \ No newline at end of file diff -Nru openmw-0.35.0/apps/mwiniimporter/importer.hpp openmw-0.35.1/apps/mwiniimporter/importer.hpp --- openmw-0.35.0/apps/mwiniimporter/importer.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/mwiniimporter/importer.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -17,17 +18,22 @@ MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(const std::string& filename) const; - static multistrmap loadCfgFile(const std::string& filename); + multistrmap loadIniFile(const boost::filesystem::path& filename) const; + static multistrmap loadCfgFile(const boost::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; - void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; + void importGameFiles(multistrmap &cfg, const multistrmap &ini, + const boost::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); private: static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); + + /// \return file's "last modified time", used in original MW to determine plug-in load order + static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); + bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; diff -Nru openmw-0.35.0/apps/mwiniimporter/main.cpp openmw-0.35.1/apps/mwiniimporter/main.cpp --- openmw-0.35.0/apps/mwiniimporter/main.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/mwiniimporter/main.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -93,8 +93,8 @@ bpo::notify(vm); - std::string iniFile = vm["ini"].as(); - std::string cfgFile = vm["cfg"].as(); + boost::filesystem::path iniFile(vm["ini"].as()); + boost::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file std::string outputFile(vm["output"].as()); @@ -123,7 +123,7 @@ importer.mergeFallback(cfg, ini); if(vm.count("game-files")) { - importer.importGameFiles(cfg, ini); + importer.importGameFiles(cfg, ini, iniFile); } if(!vm.count("no-archives")) { diff -Nru openmw-0.35.0/apps/opencs/CMakeLists.txt openmw-0.35.1/apps/opencs/CMakeLists.txt --- openmw-0.35.0/apps/opencs/CMakeLists.txt 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/CMakeLists.txt 2015-03-12 11:06:00.000000000 +0000 @@ -4,8 +4,6 @@ opencs_units (. editor) -set (CMAKE_BUILD_TYPE DEBUG) - opencs_units (model/doc document operation saving documentmanager loader runner ) @@ -41,7 +39,7 @@ opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck spellcheck referenceablecheck scriptcheck bodypartcheck + birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck ) diff -Nru openmw-0.35.0/apps/opencs/model/doc/savingstages.hpp openmw-0.35.1/apps/opencs/model/doc/savingstages.hpp --- openmw-0.35.0/apps/opencs/model/doc/savingstages.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/doc/savingstages.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -7,6 +7,8 @@ #include "../world/idcollection.hpp" #include "../world/scope.hpp" +#include + #include "savingstate.hpp" namespace ESM @@ -103,8 +105,15 @@ if (state==CSMWorld::RecordBase::State_Modified || state==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); + // FIXME: A quick Workaround to support records which should not write + // NAME, including SKIL, MGEF and SCPT. If there are many more + // idcollection records that doesn't use NAME then a more generic + // solution may be required. + uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; + mState.getWriter().startRecord (name); + + if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) + mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); } diff -Nru openmw-0.35.0/apps/opencs/model/tools/referencecheck.cpp openmw-0.35.1/apps/opencs/model/tools/referencecheck.cpp --- openmw-0.35.0/apps/opencs/model/tools/referencecheck.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/tools/referencecheck.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,110 @@ +#include "referencecheck.hpp" + +#include + +CSMTools::ReferenceCheckStage::ReferenceCheckStage( + const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions) + : + mReferences(references), + mReferencables(referencables), + mDataSet(referencables.getDataSet()), + mCells(cells), + mFactions(factions) +{ +} + +void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &messages) +{ + const CSMWorld::Record& record = mReferences.getRecord(stage); + + if (record.isDeleted()) + return; + + const CSMWorld::CellRef& cellRef = record.get(); + const CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Reference, cellRef.mId); + + // Check for empty reference id + if (cellRef.mRefID.empty()) { + messages.push_back(std::make_pair(id, " is an empty reference")); + } else { + // Check for non existing referenced object + if (mReferencables.searchId(cellRef.mRefID) == -1) { + messages.push_back(std::make_pair(id, " is referencing non existing object " + cellRef.mRefID)); + } else { + // Check if reference charge is valid for it's proper referenced type + CSMWorld::RefIdData::LocalIndex localIndex = mDataSet.searchId(cellRef.mRefID); + bool isLight = localIndex.second == CSMWorld::UniversalId::Type_Light; + if ((isLight && cellRef.mChargeFloat < -1) || (!isLight && cellRef.mChargeInt < -1)) { + std::string str = " has invalid charge "; + if (localIndex.second == CSMWorld::UniversalId::Type_Light) + str += boost::lexical_cast(cellRef.mChargeFloat); + else + str += boost::lexical_cast(cellRef.mChargeInt); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + } + } + + // Check if referenced object is in valid cell + if (mCells.searchId(cellRef.mCell) == -1) + messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); + + // If object have owner, check if that owner reference is valid + if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) + messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); + + // If object have creature soul trapped, check if that creature reference is valid + if (!cellRef.mSoul.empty()) + if (mReferencables.searchId(cellRef.mSoul) == -1) + messages.push_back(std::make_pair(id, " has non existing trapped soul " + cellRef.mSoul)); + + bool hasFaction = !cellRef.mFaction.empty(); + + // If object have faction, check if that faction reference is valid + if (hasFaction) + if (mFactions.searchId(cellRef.mFaction) == -1) + messages.push_back(std::make_pair(id, " has non existing faction " + cellRef.mFaction)); + + // Check item's faction rank + if (hasFaction && cellRef.mFactionRank < -1) + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); + else if (!hasFaction && cellRef.mFactionRank != -2) + messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); + + // If door have destination cell, check if that reference is valid + if (!cellRef.mDestCell.empty()) + if (mCells.searchId(cellRef.mDestCell) == -1) + messages.push_back(std::make_pair(id, " has non existing destination cell " + cellRef.mDestCell)); + + // Check if scale isn't negative + if (cellRef.mScale < 0) + { + std::string str = " has negative scale "; + str += boost::lexical_cast(cellRef.mScale); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if enchantement points aren't negative or are at full (-1) + if (cellRef.mEnchantmentCharge < 0 && cellRef.mEnchantmentCharge != -1) + { + std::string str = " has negative enchantment points "; + str += boost::lexical_cast(cellRef.mEnchantmentCharge); + messages.push_back(std::make_pair(id, id.getId() + str)); + } + + // Check if gold value isn't negative + if (cellRef.mGoldValue < 0) + { + std::string str = " has negative gold value "; + str += cellRef.mGoldValue; + messages.push_back(std::make_pair(id, id.getId() + str)); + } +} + +int CSMTools::ReferenceCheckStage::setup() +{ + return mReferences.getSize(); +} diff -Nru openmw-0.35.0/apps/opencs/model/tools/referencecheck.hpp openmw-0.35.1/apps/opencs/model/tools/referencecheck.hpp --- openmw-0.35.0/apps/opencs/model/tools/referencecheck.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/tools/referencecheck.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_REFERENCECHECK_H +#define CSM_TOOLS_REFERENCECHECK_H + +#include "../doc/state.hpp" +#include "../doc/document.hpp" + +namespace CSMTools +{ + class ReferenceCheckStage : public CSMDoc::Stage + { + public: + ReferenceCheckStage (const CSMWorld::RefCollection& references, + const CSMWorld::RefIdCollection& referencables, + const CSMWorld::IdCollection& cells, + const CSMWorld::IdCollection& factions); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + + private: + const CSMWorld::RefCollection& mReferences; + const CSMWorld::RefIdCollection& mReferencables; + const CSMWorld::RefIdData& mDataSet; + const CSMWorld::IdCollection& mCells; + const CSMWorld::IdCollection& mFactions; + }; +} + +#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file diff -Nru openmw-0.35.0/apps/opencs/model/tools/tools.cpp openmw-0.35.1/apps/opencs/model/tools/tools.cpp --- openmw-0.35.0/apps/opencs/model/tools/tools.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/tools/tools.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -23,6 +23,7 @@ #include "referenceablecheck.hpp" #include "scriptcheck.hpp" #include "bodypartcheck.hpp" +#include "referencecheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -57,9 +58,6 @@ mandatoryIds.push_back ("GameHour"); mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mandatoryIds.push_back ("PCVampire"); - mandatoryIds.push_back ("PCWerewolf"); - mandatoryIds.push_back ("PCYear"); mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); @@ -82,6 +80,8 @@ mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifier->appendStage (new ScriptCheckStage (mDocument)); mVerifier->appendStage( diff -Nru openmw-0.35.0/apps/opencs/model/world/pathgrid.cpp openmw-0.35.1/apps/opencs/model/world/pathgrid.cpp --- openmw-0.35.0/apps/opencs/model/world/pathgrid.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/world/pathgrid.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,4 +1,5 @@ - +#include "cell.hpp" +#include "idcollection.hpp" #include "pathgrid.hpp" #include diff -Nru openmw-0.35.0/apps/opencs/model/world/pathgrid.hpp openmw-0.35.1/apps/opencs/model/world/pathgrid.hpp --- openmw-0.35.0/apps/opencs/model/world/pathgrid.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/world/pathgrid.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -6,11 +6,12 @@ #include -#include "idcollection.hpp" -#include "cell.hpp" - namespace CSMWorld { + struct Cell; + template + class IdCollection; + /// \brief Wrapper for Pathgrid record /// /// \attention The mData.mX and mData.mY fields of the ESM::Pathgrid struct are not used. diff -Nru openmw-0.35.0/apps/opencs/model/world/subcellcollection.hpp openmw-0.35.1/apps/opencs/model/world/subcellcollection.hpp --- openmw-0.35.0/apps/opencs/model/world/subcellcollection.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/model/world/subcellcollection.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,10 +1,17 @@ #ifndef CSM_WOLRD_SUBCOLLECTION_H #define CSM_WOLRD_SUBCOLLECTION_H -#include "idcollection.hpp" +namespace ESM +{ + class ESMReader; +} namespace CSMWorld { + struct Cell; + template + class IdCollection; + /// \brief Single type collection of top level records that are associated with cells template > class SubCellCollection : public IdCollection diff -Nru openmw-0.35.0/apps/opencs/view/doc/adjusterwidget.cpp openmw-0.35.1/apps/opencs/view/doc/adjusterwidget.cpp --- openmw-0.35.0/apps/opencs/view/doc/adjusterwidget.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/view/doc/adjusterwidget.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -72,8 +73,11 @@ { boost::filesystem::path path (name.toUtf8().data()); - bool isLegacyPath = (path.extension() == ".esm" || - path.extension() == ".esp"); + std::string extension = path.extension().string(); + boost::algorithm::to_lower(extension); + + bool isLegacyPath = (extension == ".esm" || + extension == ".esp"); bool isFilePathChanged = (path.parent_path().string() != mLocalData.string()); diff -Nru openmw-0.35.0/apps/opencs/view/doc/filedialog.cpp openmw-0.35.1/apps/opencs/view/doc/filedialog.cpp --- openmw-0.35.0/apps/opencs/view/doc/filedialog.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/view/doc/filedialog.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -147,7 +147,7 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool) { - bool success = (mSelector->selectedFiles().size() > 0); + bool success = !mSelector->selectedFiles().empty(); bool isNew = (mAction == ContentAction_New); diff -Nru openmw-0.35.0/apps/opencs/view/doc/startup.cpp openmw-0.35.1/apps/opencs/view/doc/startup.cpp --- openmw-0.35.0/apps/opencs/view/doc/startup.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/view/doc/startup.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -96,7 +96,7 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) { - setWindowTitle ("Open CS"); + setWindowTitle ("OpenMW-CS"); QVBoxLayout *layout = new QVBoxLayout (this); diff -Nru openmw-0.35.0/apps/opencs/view/render/cell.cpp openmw-0.35.1/apps/opencs/view/render/cell.cpp --- openmw-0.35.0/apps/opencs/view/render/cell.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/opencs/view/render/cell.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -78,7 +78,7 @@ if (landIndex != -1) { const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand) + if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, Terrain::Align_XY)); diff -Nru openmw-0.35.0/apps/openmw/CMakeLists.txt openmw-0.35.1/apps/openmw/CMakeLists.txt --- openmw-0.35.0/apps/openmw/CMakeLists.txt 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/CMakeLists.txt 2015-03-12 11:06:00.000000000 +0000 @@ -41,7 +41,7 @@ itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop + draganddrop timeadvancer jailscreen ) add_openmw_dir (mwdialogue diff -Nru openmw-0.35.0/apps/openmw/engine.cpp openmw-0.35.1/apps/openmw/engine.cpp --- openmw-0.35.0/apps/openmw/engine.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/engine.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -109,11 +109,14 @@ { if (!paused) { - // local scripts - executeLocalScripts(); - - // global scripts - MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + if (MWBase::Environment::get().getWorld()->getScriptsEnabled()) + { + // local scripts + executeLocalScripts(); + + // global scripts + MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); + } MWBase::Environment::get().getWorld()->markCellAsUnchanged(); } @@ -170,7 +173,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) - , mFpsLevel(0) , mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) @@ -192,7 +194,7 @@ std::srand ( std::time(NULL) ); MWClass::registerClasses(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; if(SDL_WasInit(flags) == 0) { //kindly ask SDL not to trash our OGL context @@ -292,16 +294,10 @@ else throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); - // load user settings if they exist, otherwise just load the default settings as user settings + // load user settings if they exist const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg"; if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - settings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - settings.loadUser(globaldefault); - - mFpsLevel = settings.getInt("fps", "HUD"); // load nif overrides NifOverrides::Overrides nifOverrides; @@ -372,13 +368,33 @@ // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so - std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab); + if(!keybinderUserExists) + { + std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + if(boost::filesystem::exists(input2)) { + boost::filesystem::copy_file(input2, keybinderUser); + keybinderUserExists = boost::filesystem::exists(keybinderUser); + } + } + + // find correct path to the game controller bindings + const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.cfg"; + std::string gameControllerdb; + if (boost::filesystem::exists(localdefault)) + gameControllerdb = localdefault; + else if (boost::filesystem::exists(globaldefault)) + gameControllerdb = globaldefault; + else + gameControllerdb = ""; //if it doesn't exist, pass in an empty string + + MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( - mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts, mFallbackMap); mEnvironment.setWindowManager (window); @@ -579,11 +595,6 @@ mUseSound = soundUsage; } -void OMW::Engine::showFPS(int level) -{ - mFpsLevel = level; -} - void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; diff -Nru openmw-0.35.0/apps/openmw/engine.hpp openmw-0.35.1/apps/openmw/engine.hpp --- openmw-0.35.0/apps/openmw/engine.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/engine.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -71,7 +71,6 @@ OEngine::Render::OgreRenderer *mOgre; std::string mCellName; std::vector mContentFiles; - int mFpsLevel; bool mVerboseScripts; bool mSkipMenu; bool mUseSound; @@ -151,9 +150,6 @@ */ void addContentFile(const std::string& file); - /// Enable fps counter - void showFPS(int level); - /// Enable or disable verbose script output void setScriptsVerbosity(bool scriptsVerbosity); diff -Nru openmw-0.35.0/apps/openmw/main.cpp openmw-0.35.1/apps/openmw/main.cpp --- openmw-0.35.0/apps/openmw/main.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/main.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -153,7 +153,7 @@ ->default_value(true), "enable script blacklisting") ("load-savegame", bpo::value()->default_value(""), - "load a save game file on game startup") + "load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)") ("skip-menu", bpo::value()->implicit_value(true) ->default_value(false), "skip main menu on game startup") @@ -390,12 +390,12 @@ catch (std::exception &e) { #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE - if (isatty(fileno(stdin))) - std::cerr << "\nERROR: " << e.what() << std::endl; - else + if (!isatty(fileno(stdin))) #endif SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL); + std::cerr << "\nERROR: " << e.what() << std::endl; + ret = 1; } diff -Nru openmw-0.35.0/apps/openmw/mwbase/environment.hpp openmw-0.35.1/apps/openmw/mwbase/environment.hpp --- openmw-0.35.0/apps/openmw/mwbase/environment.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwbase/environment.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,5 +1,5 @@ -#ifndef GAME_BASE_INVIRONMENT_H -#define GAME_BASE_INVIRONMENT_H +#ifndef GAME_BASE_ENVIRONMENT_H +#define GAME_BASE_ENVIRONMENT_H namespace MWBase { diff -Nru openmw-0.35.0/apps/openmw/mwbase/inputmanager.hpp openmw-0.35.1/apps/openmw/mwbase/inputmanager.hpp --- openmw-0.35.0/apps/openmw/mwbase/inputmanager.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwbase/inputmanager.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,8 +2,8 @@ #define GAME_MWBASE_INPUTMANAGER_H #include - -#include +#include +#include namespace MWBase { @@ -29,7 +29,7 @@ virtual void changeInputMode(bool guiMode) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void setDragDrop(bool dragDrop) = 0; @@ -37,11 +37,23 @@ virtual bool getControlSwitch (const std::string& sw) = 0; virtual std::string getActionDescription (int action) = 0; - virtual std::string getActionBindingName (int action) = 0; - virtual std::vector getActionSorting () = 0; + virtual std::string getActionKeyBindingName (int action) = 0; + virtual std::string getActionControllerBindingName (int action) = 0; + virtual std::string sdlControllerAxisToString(int axis) = 0; + virtual std::string sdlControllerButtonToString(int button) = 0; + ///Actions available for binding to keyboard buttons + virtual std::vector getActionKeySorting() = 0; + ///Actions available for binding to controller buttons + virtual std::vector getActionControllerSorting() = 0; virtual int getNumActions() = 0; - virtual void enableDetectingBindingMode (int action) = 0; - virtual void resetToDefaultBindings() = 0; + ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to controller events (excluding esc) + virtual void enableDetectingBindingMode (int action, bool keyboard) = 0; + virtual void resetToDefaultKeyBindings() = 0; + virtual void resetToDefaultControllerBindings() = 0; + + /// Returns if the last used input device was a joystick or a keyboard + /// @return true if joystick, false otherwise + virtual bool joystickLastUsed() = 0; }; } diff -Nru openmw-0.35.0/apps/openmw/mwbase/mechanicsmanager.hpp openmw-0.35.1/apps/openmw/mwbase/mechanicsmanager.hpp --- openmw-0.35.0/apps/openmw/mwbase/mechanicsmanager.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwbase/mechanicsmanager.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -129,16 +129,15 @@ /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; + /// @param container The container the item is in; may be empty for an item in the world + virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, + int count) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. /// @return was it illegal, and someone saw you doing it? virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0; - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) = 0; - enum PersuasionType { PT_Admire, @@ -203,6 +202,15 @@ virtual void keepPlayerAlive() = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; + + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid) = 0; + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; }; } diff -Nru openmw-0.35.0/apps/openmw/mwbase/soundmanager.hpp openmw-0.35.1/apps/openmw/mwbase/soundmanager.hpp --- openmw-0.35.0/apps/openmw/mwbase/soundmanager.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwbase/soundmanager.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,11 +2,9 @@ #define GAME_MWBASE_SOUNDMANAGER_H #include - +#include #include -#include - #include "../mwworld/ptr.hpp" namespace Ogre @@ -74,7 +72,7 @@ virtual ~SoundManager() {} - virtual void processChangedSettings(const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings(const std::set< std::pair >& settings) = 0; virtual void stopMusic() = 0; ///< Stops music if it's playing diff -Nru openmw-0.35.0/apps/openmw/mwbase/windowmanager.hpp openmw-0.35.1/apps/openmw/mwbase/windowmanager.hpp --- openmw-0.35.0/apps/openmw/mwbase/windowmanager.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwbase/windowmanager.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,19 +1,23 @@ #ifndef GAME_MWBASE_WINDOWMANAGER_H #define GAME_MWBASE_WINDOWMANAGER_H +#include #include #include #include +#include -#include - -#include - -#include +#include "../mwgui/mode.hpp" -#include "../mwmechanics/stat.hpp" +namespace Loading +{ + class Listener; +} -#include "../mwgui/mode.hpp" +namespace Translation +{ + class Storage; +} namespace MyGUI { @@ -38,6 +42,14 @@ struct CellId; } +namespace MWMechanics +{ + class AttributeValue; + template + class DynamicStat; + class SkillValue; +} + namespace MWWorld { class CellStore; @@ -59,6 +71,7 @@ class ContainerWindow; class DialogueWindow; class WindowModal; + class JailScreen; enum ShowInDialogueMode { ShowInDialogueMode_IfPossible, @@ -110,6 +123,8 @@ virtual void removeGuiMode (MWGui::GuiMode mode) = 0; ///< can be anywhere in the stack + virtual void goToJail(int days) = 0; + virtual void updatePlayer() = 0; virtual MWGui::GuiMode getMode() const = 0; @@ -267,7 +282,7 @@ */ virtual std::string getGameSettingString(const std::string &id, const std::string &default_) = 0; - virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + virtual void processChangedSettings(const std::set< std::pair >& changed) = 0; virtual void windowResized(int x, int y) = 0; diff -Nru openmw-0.35.0/apps/openmw/mwbase/world.hpp openmw-0.35.1/apps/openmw/mwbase/world.hpp --- openmw-0.35.0/apps/openmw/mwbase/world.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwbase/world.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -3,26 +3,23 @@ #include #include - -#include +#include #include -#include "../mwworld/globals.hpp" #include "../mwworld/ptr.hpp" namespace Ogre { class Vector2; class Vector3; + class Quaternion; + class Image; } -namespace OEngine +namespace Loading { - namespace Physic - { - class PhysicEngine; - } + class Listener; } namespace ESM @@ -271,6 +268,8 @@ virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getMaxActivationDistance() = 0; + /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. @@ -390,7 +389,7 @@ virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual void processChangedSettings (const std::set< std::pair >& settings) = 0; virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; @@ -492,6 +491,9 @@ virtual bool toggleGodMode() = 0; + virtual bool toggleScripts() = 0; + virtual bool getScriptsEnabled() const = 0; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor @@ -551,7 +553,7 @@ virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff -Nru openmw-0.35.0/apps/openmw/mwclass/armor.cpp openmw-0.35.1/apps/openmw/mwclass/armor.cpp --- openmw-0.35.0/apps/openmw/mwclass/armor.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwclass/armor.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -245,7 +245,8 @@ else typeText = "#{sHeavy}"; - text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); + text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, + MWBase::Environment::get().getWorld()->getPlayerPtr())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" @@ -290,6 +291,22 @@ return record->mId; } + int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + + int armorSkillType = getEquipmentSkill(ptr); + int armorSkill = actor.getClass().getSkill(actor, armorSkillType); + + const MWBase::World *world = MWBase::Environment::get().getWorld(); + int iBaseArmorSkill = world->getStore().get().find("iBaseArmorSkill")->getInt(); + + if(ref->mBase->mData.mWeight == 0) + return ref->mBase->mData.mArmor; + else + return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); diff -Nru openmw-0.35.0/apps/openmw/mwclass/armor.hpp openmw-0.35.1/apps/openmw/mwclass/armor.hpp --- openmw-0.35.0/apps/openmw/mwclass/armor.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwclass/armor.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -86,6 +86,9 @@ virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } diff -Nru openmw-0.35.0/apps/openmw/mwclass/container.cpp openmw-0.35.1/apps/openmw/mwclass/container.cpp --- openmw-0.35.0/apps/openmw/mwclass/container.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwclass/container.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -59,8 +59,10 @@ MWWorld::LiveCellRef *ref = ptr.get(); + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically data->mContainerStore.fill( - ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore()); + ref->mBase->mInventory, ""); // store ptr.getRefData().setCustomData (data.release()); @@ -82,7 +84,10 @@ MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank()); + + // setting ownership not needed, since taking items from a container inherits the + // container's owner automatically + store.restock(list, ptr, ""); } void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const diff -Nru openmw-0.35.0/apps/openmw/mwclass/creature.cpp openmw-0.35.1/apps/openmw/mwclass/creature.cpp --- openmw-0.35.0/apps/openmw/mwclass/creature.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwclass/creature.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -139,8 +139,7 @@ // store ptr.getRefData().setCustomData(data.release()); - getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr)); if (ref->mBase->mFlags & ESM::Creature::Weapon) getInventoryStore(ptr).autoEquip(ptr); @@ -886,7 +885,7 @@ MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const diff -Nru openmw-0.35.0/apps/openmw/mwclass/misc.cpp openmw-0.35.1/apps/openmw/mwclass/misc.cpp --- openmw-0.35.0/apps/openmw/mwclass/misc.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwclass/misc.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -12,6 +12,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwclass/npc.cpp openmw-0.35.1/apps/openmw/mwclass/npc.cpp --- openmw-0.35.0/apps/openmw/mwclass/npc.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwclass/npc.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -384,8 +384,8 @@ } // inventory - data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1, - MWBase::Environment::get().getWorld()->getStore()); + // setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items + data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr)); data->mNpcStats.setGoldPool(gold); @@ -1086,7 +1086,6 @@ MWMechanics::NpcStats &stats = getNpcStats(ptr); MWWorld::InventoryStore &invStore = getInventoryStore(ptr); - int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt(); float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); @@ -1102,15 +1101,7 @@ } else { - MWWorld::LiveCellRef *ref = it->get(); - - int armorSkillType = it->getClass().getEquipmentSkill(*it); - int armorSkill = stats.getSkill(armorSkillType).getModified(); - - if(ref->mBase->mData.mWeight == 0) - ratings[i] = ref->mBase->mData.mArmor; - else - ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr); } } @@ -1328,7 +1319,7 @@ MWWorld::LiveCellRef *ref = ptr.get(); const ESM::InventoryList& list = ref->mBase->mInventory; MWWorld::ContainerStore& store = getContainerStore(ptr); - store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1); + store.restock(list, ptr, ptr.getCellRef().getRefId()); } int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const diff -Nru openmw-0.35.0/apps/openmw/mwdialogue/scripttest.cpp openmw-0.35.1/apps/openmw/mwdialogue/scripttest.cpp --- openmw-0.35.0/apps/openmw/mwdialogue/scripttest.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwdialogue/scripttest.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,6 +1,9 @@ #include "scripttest.hpp" +#include + #include "../mwworld/manualref.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwgui/container.cpp openmw-0.35.1/apps/openmw/mwgui/container.cpp --- openmw-0.35.0/apps/openmw/mwgui/container.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/container.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -285,7 +285,7 @@ if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) return true; else - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count); } return true; } diff -Nru openmw-0.35.0/apps/openmw/mwgui/enchantingdialog.cpp openmw-0.35.1/apps/openmw/mwgui/enchantingdialog.cpp --- openmw-0.35.0/apps/openmw/mwgui/enchantingdialog.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/enchantingdialog.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -339,7 +339,8 @@ for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); - if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) diff -Nru openmw-0.35.0/apps/openmw/mwgui/hud.cpp openmw-0.35.1/apps/openmw/mwgui/hud.cpp --- openmw-0.35.0/apps/openmw/mwgui/hud.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/hud.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,6 +10,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -670,4 +671,14 @@ mEnemyHealthTimer = -1; } + void HUD::customMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + + void HUD::doorMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + } diff -Nru openmw-0.35.0/apps/openmw/mwgui/hud.hpp openmw-0.35.1/apps/openmw/mwgui/hud.hpp --- openmw-0.35.0/apps/openmw/mwgui/hud.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/hud.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -119,6 +119,10 @@ void onMagicClicked(MyGUI::Widget* _sender); void onMapClicked(MyGUI::Widget* _sender); + // LocalMapBase + virtual void customMarkerCreated(MyGUI::Widget* marker); + virtual void doorMarkerCreated(MyGUI::Widget* marker); + void updateEnemyHealthBar(); void updatePositions(); diff -Nru openmw-0.35.0/apps/openmw/mwgui/inventoryitemmodel.cpp openmw-0.35.1/apps/openmw/mwgui/inventoryitemmodel.cpp --- openmw-0.35.0/apps/openmw/mwgui/inventoryitemmodel.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/inventoryitemmodel.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -65,16 +65,7 @@ if (item.mFlags & ItemStack::Flag_Bound) return MWWorld::Ptr(); - bool setNewOwner = false; - - // Are you dead? Then you wont need that anymore - if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead() - // Make sure that the item is actually owned by the dead actor - // Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse - && Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId())) - setNewOwner = true; - - MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner); + MWWorld::Ptr ret = otherModel->copyItem(item, count, false); removeItem(item, count); return ret; } diff -Nru openmw-0.35.0/apps/openmw/mwgui/inventorywindow.cpp openmw-0.35.1/apps/openmw/mwgui/inventorywindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/inventorywindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/inventorywindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,6 +8,8 @@ #include #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -418,7 +420,7 @@ // Give the script a chance to run once before we do anything else // this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this) - if (!script.empty()) + if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled()) { MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); @@ -622,7 +624,7 @@ throw std::runtime_error("Added item not found"); mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); @@ -651,16 +653,13 @@ if (selected != -1) lastId = model.getItem(selected).mBase.getCellRef().getRefId(); ItemModel::ModelIndex cycled = selected; - while (!found) + for (unsigned int i=0; i + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/store.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwgui/itemmodel.hpp openmw-0.35.1/apps/openmw/mwgui/itemmodel.hpp --- openmw-0.35.0/apps/openmw/mwgui/itemmodel.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/itemmodel.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -46,20 +46,27 @@ ItemModel(); virtual ~ItemModel() {} - typedef int ModelIndex; + typedef int ModelIndex; // -1 means invalid index + /// Throws for invalid index or out of range index virtual ItemStack getItem (ModelIndex index) = 0; - ///< throws for invalid index + + /// The number of items in the model, this specifies the range of indices you can pass to + /// the getItem function (but this range is only valid until the next call to update()) virtual size_t getItemCount() = 0; + /// Returns an invalid index if the item was not found virtual ModelIndex getIndex (ItemStack item) = 0; + /// Rebuild the item model, this will invalidate existing model indices virtual void update() = 0; /// Move items from this model to \a otherModel. + /// @note Derived implementations may return an empty Ptr if the move was unsuccessful. virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); - /// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner? + /// @param setNewOwner If true, set the copied item's owner to the actor we are copying to, + /// otherwise reset owner to "" virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; diff -Nru openmw-0.35.0/apps/openmw/mwgui/jailscreen.cpp openmw-0.35.1/apps/openmw/mwgui/jailscreen.cpp --- openmw-0.35.0/apps/openmw/mwgui/jailscreen.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/jailscreen.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,129 @@ +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "../mwworld/esmstore.hpp" +#include "../mwworld/store.hpp" +#include "../mwworld/class.hpp" + +#include "jailscreen.hpp" + +namespace MWGui +{ + JailScreen::JailScreen() + : WindowBase("openmw_jail_screen.layout"), + mTimeAdvancer(0.01), + mDays(1), + mFadeTimeRemaining(0) + { + getWidget(mProgressBar, "ProgressBar"); + + setVisible(false); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); + + center(); + } + + void JailScreen::goToJail(int days) + { + mDays = days; + + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + mFadeTimeRemaining = 0.5; + + setVisible(false); + mProgressBar->setScrollRange(100+1); + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(0); + } + + void JailScreen::onFrame(float dt) + { + mTimeAdvancer.onFrame(dt); + + if (mFadeTimeRemaining <= 0) + return; + + mFadeTimeRemaining -= dt; + + if (mFadeTimeRemaining <= 0) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); + + setVisible(true); + mTimeAdvancer.run(100); + } + } + + void JailScreen::onJailProgressChanged(int cur, int /*total*/) + { + mProgressBar->setScrollPosition(0); + mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + } + + void JailScreen::onJailFinished() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Jail); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + MWBase::Environment::get().getWorld()->advanceTime(mDays * 24); + for (int i=0; irest(true); + + std::set skills; + for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + skills.insert(skill); + + MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); + if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) + value.setBase(std::min(100, value.getBase()+1)); + else + value.setBase(value.getBase()-1); + } + + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + std::string message; + if (mDays == 1) + message = gmst.find("sNotifyMessage42")->getString(); + else + message = gmst.find("sNotifyMessage43")->getString(); + + std::stringstream dayStr; + dayStr << mDays; + if (message.find("%d") != std::string::npos) + message.replace(message.find("%d"), 2, dayStr.str()); + + for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) + { + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); + std::stringstream skillValue; + skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); + std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); + if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) + skillMsg = gmst.find("sNotifyMessage39")->getString(); + + if (skillMsg.find("%s") != std::string::npos) + skillMsg.replace(skillMsg.find("%s"), 2, skillName); + if (skillMsg.find("%d") != std::string::npos) + skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); + message += "\n" + skillMsg; + } + + std::vector buttons; + buttons.push_back("#{sOk}"); + MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + } +} diff -Nru openmw-0.35.0/apps/openmw/mwgui/jailscreen.hpp openmw-0.35.1/apps/openmw/mwgui/jailscreen.hpp --- openmw-0.35.0/apps/openmw/mwgui/jailscreen.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/jailscreen.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,31 @@ +#ifndef MWGUI_JAILSCREEN_H +#define MWGUI_JAILSCREEN_H + +#include "windowbase.hpp" +#include "timeadvancer.hpp" + +namespace MWGui +{ + class JailScreen : public WindowBase + { + public: + JailScreen(); + void goToJail(int days); + + void onFrame(float dt); + + private: + int mDays; + + float mFadeTimeRemaining; + + MyGUI::ScrollBar* mProgressBar; + + void onJailProgressChanged(int cur, int total); + void onJailFinished(); + + TimeAdvancer mTimeAdvancer; + }; +} + +#endif diff -Nru openmw-0.35.0/apps/openmw/mwgui/journalviewmodel.cpp openmw-0.35.1/apps/openmw/mwgui/journalviewmodel.cpp --- openmw-0.35.0/apps/openmw/mwgui/journalviewmodel.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/journalviewmodel.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,6 +8,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/environment.hpp" @@ -197,7 +199,7 @@ }; - void visitQuestNames (bool active_only, boost::function visitor) const + void visitQuestNames (bool active_only, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get ().getJournal (); @@ -229,7 +231,7 @@ if (visitedQuests.find(quest.getName()) != visitedQuests.end()) continue; - visitor (quest.getName()); + visitor (quest.getName(), isFinished); visitedQuests.insert(quest.getName()); } diff -Nru openmw-0.35.0/apps/openmw/mwgui/journalviewmodel.hpp openmw-0.35.1/apps/openmw/mwgui/journalviewmodel.hpp --- openmw-0.35.0/apps/openmw/mwgui/journalviewmodel.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/journalviewmodel.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -67,8 +67,8 @@ /// returns true if their are no journal entries to display virtual bool isEmpty () const = 0; - /// walks the active and optionally completed, quests providing the name - virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; + /// walks the active and optionally completed, quests providing the name and completed status + virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; /// walks over the journal entries related to all quests with the given name /// If \a questName is empty, simply visits all journal entries diff -Nru openmw-0.35.0/apps/openmw/mwgui/journalwindow.cpp openmw-0.35.1/apps/openmw/mwgui/journalwindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/journalwindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/journalwindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -7,10 +7,12 @@ #include #include +#include #include #include +#include #include #include @@ -427,11 +429,24 @@ AddNamesToList(Gui::MWList* list) : mList(list) {} Gui::MWList* mList; - void operator () (const std::string& name) + void operator () (const std::string& name, bool finished=false) { mList->addItem(name); } }; + struct SetNamesInactive + { + SetNamesInactive(Gui::MWList* list) : mList(list) {} + + Gui::MWList* mList; + void operator () (const std::string& name, bool finished) + { + if (finished) + { + mList->getItemWidget(name)->setStateSelected(true); + } + } + }; void notifyQuests(MyGUI::Widget* _sender) { @@ -452,6 +467,12 @@ mModel->visitQuestNames(!mAllQuests, add); list->adjustSize(); + + if (mAllQuests) + { + SetNamesInactive setInactive(list); + mModel->visitQuestNames(!mAllQuests, setInactive); + } } void notifyShowAll(MyGUI::Widget* _sender) diff -Nru openmw-0.35.0/apps/openmw/mwgui/levelupdialog.cpp openmw-0.35.1/apps/openmw/mwgui/levelupdialog.cpp --- openmw-0.35.0/apps/openmw/mwgui/levelupdialog.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/levelupdialog.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -139,7 +139,6 @@ if(world->getStore().get().isDynamic(cls->mId)) { - // Vanilla uses thief.dds for custom classes. // Choosing Stealth specialization and Speed/Agility as attributes, if possible. Otherwise fall back to first class found. MWWorld::SharedIterator it = world->getStore().get().begin(); for(; it != world->getStore().get().end(); ++it) @@ -173,14 +172,17 @@ if (pcStats.getAttribute(i).getBase() < 100) { mAttributes[i]->setEnabled(true); + mAttributeValues[i]->setEnabled(true); availableAttributes++; int mult = pcStats.getLevelupAttributeMultiplier (i); + mult = std::min(mult, 100-pcStats.getAttribute(i).getBase()); text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult)); } else { mAttributes[i]->setEnabled(false); + mAttributeValues[i]->setEnabled(false); text->setCaption(""); } diff -Nru openmw-0.35.0/apps/openmw/mwgui/loadingscreen.cpp openmw-0.35.1/apps/openmw/mwgui/loadingscreen.cpp --- openmw-0.35.0/apps/openmw/mwgui/loadingscreen.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/loadingscreen.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -15,6 +15,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwgui/mainmenu.cpp openmw-0.35.1/apps/openmw/mwgui/mainmenu.cpp --- openmw-0.35.0/apps/openmw/mwgui/mainmenu.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/mainmenu.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -9,6 +9,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwgui/mapwindow.cpp openmw-0.35.1/apps/openmw/mwgui/mapwindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/mapwindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/mapwindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwgui/mode.hpp openmw-0.35.1/apps/openmw/mwgui/mode.hpp --- openmw-0.35.0/apps/openmw/mwgui/mode.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/mode.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -46,6 +46,7 @@ GM_Loading, GM_LoadingWallpaper, + GM_Jail, GM_QuickKeysMenu }; diff -Nru openmw-0.35.0/apps/openmw/mwgui/settingswindow.cpp openmw-0.35.1/apps/openmw/mwgui/settingswindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/settingswindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/settingswindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -14,7 +14,9 @@ #include +#include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -161,7 +163,8 @@ } SettingsWindow::SettingsWindow() : - WindowBase("openmw_settings_window.layout") + WindowBase("openmw_settings_window.layout"), + mKeyboardMode(true) { configureWidgets(mMainWidget); @@ -186,6 +189,8 @@ getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); + getWidget(mKeyboardSwitch, "KeyboardButton"); + getWidget(mControllerSwitch, "ControllerButton"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -211,6 +216,9 @@ mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); + mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); + mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); + center(); mResetControlsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindings); @@ -258,9 +266,13 @@ MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); + diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); + + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -460,14 +472,37 @@ MWBase::Environment::get().getInputManager()->processChangedSettings(changed); } + void SettingsWindow::onKeyboardSwitchClicked(MyGUI::Widget* _sender) + { + if(mKeyboardMode) + return; + mKeyboardMode = true; + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); + updateControlsBox(); + } + + void SettingsWindow::onControllerSwitchClicked(MyGUI::Widget* _sender) + { + if(!mKeyboardMode) + return; + mKeyboardMode = false; + mKeyboardSwitch->setStateSelected(false); + mControllerSwitch->setStateSelected(true); + updateControlsBox(); + } + void SettingsWindow::updateControlsBox() { while (mControlsBox->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mControlsBox->getChildAt(0)); - MWBase::Environment::get().getWindowManager ()->removeStaticMessageBox(); - - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + MWBase::Environment::get().getWindowManager()->removeStaticMessageBox(); + std::vector actions; + if(mKeyboardMode) + actions = MWBase::Environment::get().getInputManager()->getActionKeySorting(); + else + actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); const int h = 18; const int w = mControlsBox->getWidth() - 28; @@ -478,7 +513,11 @@ if (desc == "") continue; - std::string binding = MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + std::string binding; + if(mKeyboardMode) + binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(*it); + else + binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); @@ -512,7 +551,7 @@ MWBase::Environment::get().getWindowManager ()->staticMessageBox ("#{sControlsMenu3}"); MWBase::Environment::get().getWindowManager ()->disallowMouse(); - MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId); + MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId, mKeyboardMode); } @@ -535,7 +574,10 @@ void SettingsWindow::onResetDefaultBindingsAccept() { - MWBase::Environment::get().getInputManager ()->resetToDefaultBindings (); + if(mKeyboardMode) + MWBase::Environment::get().getInputManager ()->resetToDefaultKeyBindings (); + else + MWBase::Environment::get().getInputManager()->resetToDefaultControllerBindings(); updateControlsBox (); } diff -Nru openmw-0.35.0/apps/openmw/mwgui/settingswindow.hpp openmw-0.35.1/apps/openmw/mwgui/settingswindow.hpp --- openmw-0.35.0/apps/openmw/mwgui/settingswindow.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/settingswindow.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -46,6 +46,9 @@ // controls MyGUI::ScrollView* mControlsBox; MyGUI::Button* mResetControlsButton; + MyGUI::Button* mKeyboardSwitch; + MyGUI::Button* mControllerSwitch; + bool mKeyboardMode; //if true, setting up the keyboard. Otherwise, it's controller void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); @@ -63,6 +66,8 @@ void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); void onResetDefaultBindings(MyGUI::Widget* _sender); void onResetDefaultBindingsAccept (); + void onKeyboardSwitchClicked(MyGUI::Widget* _sender); + void onControllerSwitchClicked(MyGUI::Widget* _sender); void onWindowResize(MyGUI::Window* _sender); diff -Nru openmw-0.35.0/apps/openmw/mwgui/spellwindow.cpp openmw-0.35.1/apps/openmw/mwgui/spellwindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/spellwindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/spellwindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -95,58 +95,60 @@ return; } - MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); store.setSelectedEnchantItem(it); + // to reset WindowManager::mSelectedSpell immediately + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(*it); updateSpells(); } - void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) + void SpellWindow::askDeleteSpell(const std::string &spellId) { - const Spell& spell = mSpellView->getModel()->getItem(index); - if (spell.mType == Spell::Type_EnchantedItem) + // delete spell, if allowed + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + if (spell->mData.mFlags & ESM::Spell::F_Always + || spell->mData.mType == ESM::Spell::ST_Power) { - onEnchantedItemSelected(spell.mItem, spell.mActive); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } else { - onSpellSelected(spell.mId); + // ask for confirmation + mSpellToDelete = spellId; + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + question = boost::str(boost::format(question) % spell->mName); + dialog->open(question); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); + dialog->eventCancelClicked.clear(); } } - void SpellWindow::onSpellSelected(const std::string& spellId) + void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) { - if (MyGUI::InputManager::getInstance().isShiftPressed()) + const Spell& spell = mSpellView->getModel()->getItem(index); + if (spell.mType == Spell::Type_EnchantedItem) { - // delete spell, if allowed - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - if (spell->mData.mFlags & ESM::Spell::F_Always - || spell->mData.mType == ESM::Spell::ST_Power) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); - } - else - { - // ask for confirmation - mSpellToDelete = spellId; - ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); - dialog->eventCancelClicked.clear(); - } + onEnchantedItemSelected(spell.mItem, spell.mActive); } else { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - store.setSelectedEnchantItem(store.end()); - MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + if (MyGUI::InputManager::getInstance().isShiftPressed()) + askDeleteSpell(spell.mId); + else + onSpellSelected(spell.mId); } + } + + void SpellWindow::onSpellSelected(const std::string& spellId) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + store.setSelectedEnchantItem(store.end()); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); } @@ -183,6 +185,10 @@ return; selected = (selected + itemcount) % itemcount; - onModelIndexSelected(selected); + const Spell& spell = mSpellView->getModel()->getItem(selected); + if (spell.mType == Spell::Type_EnchantedItem) + onEnchantedItemSelected(spell.mItem, spell.mActive); + else + onSpellSelected(spell.mId); } } diff -Nru openmw-0.35.0/apps/openmw/mwgui/spellwindow.hpp openmw-0.35.1/apps/openmw/mwgui/spellwindow.hpp --- openmw-0.35.0/apps/openmw/mwgui/spellwindow.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/spellwindow.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -33,6 +33,7 @@ void onSpellSelected(const std::string& spellId); void onModelIndexSelected(SpellModel::ModelIndex index); void onDeleteSpellAccept(); + void askDeleteSpell(const std::string& spellId); virtual void onPinToggled(); virtual void onTitleDoubleClicked(); diff -Nru openmw-0.35.0/apps/openmw/mwgui/statswindow.cpp openmw-0.35.1/apps/openmw/mwgui/statswindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/statswindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/statswindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -376,18 +376,26 @@ for (SkillList::const_iterator it = skills.begin(); it != end; ++it) { int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; int base = stat.getBase(); int modified = stat.getModified(); - int progressPercent = stat.getProgress() * 100; + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); + float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId, + *esmStore.get().find(player.get()->mBase->mClass)); + + // This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate, + // due to the int casting in the skill levelup logic. Also the progress label could in rare cases + // reach 100% without the skill levelling up. + // Leaving the original display logic for now, for consistency with ess-imported savegames. + int progressPercent = int(float(stat.getProgress()) / float(progressRequirement) * 100.f + 0.5f); + const ESM::Skill* skill = esmStore.get().find(skillId); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; diff -Nru openmw-0.35.0/apps/openmw/mwgui/timeadvancer.cpp openmw-0.35.1/apps/openmw/mwgui/timeadvancer.cpp --- openmw-0.35.0/apps/openmw/mwgui/timeadvancer.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/timeadvancer.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,73 @@ +#include "timeadvancer.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWGui +{ + TimeAdvancer::TimeAdvancer(float delay) + : mRunning(false), + mCurHour(0), + mHours(1), + mInterruptAt(-1), + mDelay(delay), + mRemainingTime(delay) + { + } + + void TimeAdvancer::run(int hours, int interruptAt) + { + mHours = hours; + mCurHour = 0; + mInterruptAt = interruptAt; + mRemainingTime = mDelay; + + mRunning = true; + } + + void TimeAdvancer::stop() + { + mRunning = false; + } + + void TimeAdvancer::onFrame(float dt) + { + if (!mRunning) + return; + + if (mCurHour == mInterruptAt) + { + stop(); + eventInterrupted(); + return; + } + + mRemainingTime -= dt; + + while (mRemainingTime <= 0) + { + mRemainingTime += mDelay; + ++mCurHour; + + if (mCurHour <= mHours) + eventProgressChanged(mCurHour, mHours); + else + { + stop(); + eventFinished(); + return; + } + + } + } + + int TimeAdvancer::getHours() + { + return mHours; + } + + bool TimeAdvancer::isRunning() + { + return mRunning; + } +} diff -Nru openmw-0.35.0/apps/openmw/mwgui/timeadvancer.hpp openmw-0.35.1/apps/openmw/mwgui/timeadvancer.hpp --- openmw-0.35.0/apps/openmw/mwgui/timeadvancer.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/timeadvancer.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,40 @@ +#ifndef MWGUI_TIMEADVANCER_H +#define MWGUI_TIMEADVANCER_H + +#include + +namespace MWGui +{ + class TimeAdvancer + { + public: + TimeAdvancer(float delay); + + void run(int hours, int interruptAt=-1); + void stop(); + void onFrame(float dt); + + int getHours(); + bool isRunning(); + + // signals + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_IntInt; + + EventHandle_IntInt eventProgressChanged; + EventHandle_Void eventInterrupted; + EventHandle_Void eventFinished; + + private: + bool mRunning; + + int mCurHour; + int mHours; + int mInterruptAt; + + float mDelay; + float mRemainingTime; + }; +} + +#endif diff -Nru openmw-0.35.0/apps/openmw/mwgui/tooltips.cpp openmw-0.35.1/apps/openmw/mwgui/tooltips.cpp --- openmw-0.35.0/apps/openmw/mwgui/tooltips.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/tooltips.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,10 +8,12 @@ #include #include +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -585,6 +587,15 @@ ret += getMiscString(cellref.getFaction(), "Faction"); if (cellref.getFactionRank() > 0) ret += getValueString(cellref.getFactionRank(), "Rank"); + + std::vector > itemOwners = + MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); + + for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) + { + ret += std::string("\nStolen from ") + it->first; + } + ret += getMiscString(cellref.getGlobalVariable(), "Global"); return ret; } diff -Nru openmw-0.35.0/apps/openmw/mwgui/tradeitemmodel.cpp openmw-0.35.1/apps/openmw/mwgui/tradeitemmodel.cpp --- openmw-0.35.0/apps/openmw/mwgui/tradeitemmodel.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/tradeitemmodel.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -135,11 +135,9 @@ if (i == sourceModel->getItemCount()) throw std::runtime_error("The borrowed item disappeared"); - // reset owner while copying, but only for items bought by the player - bool setNewOwner = (mMerchant.isEmpty()); const ItemStack& item = sourceModel->getItem(i); // copy the borrowed items to our model - copyItem(item, it->mCount, setNewOwner); + copyItem(item, it->mCount); // then remove them from the source model sourceModel->removeItem(item, it->mCount); } diff -Nru openmw-0.35.0/apps/openmw/mwgui/tradewindow.cpp openmw-0.35.1/apps/openmw/mwgui/tradewindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/tradewindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/tradewindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -16,6 +16,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -300,7 +301,8 @@ // check if the player is attempting to sell back an item stolen from this actor for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { - if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), + mPtr.getCellRef().getRefId())) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) @@ -315,6 +317,8 @@ } } + // TODO: move to mwmechanics + // Is the player buying? bool buying = (mCurrentMerchantOffer < 0); diff -Nru openmw-0.35.0/apps/openmw/mwgui/trainingwindow.cpp openmw-0.35.1/apps/openmw/mwgui/trainingwindow.cpp --- openmw-0.35.0/apps/openmw/mwgui/trainingwindow.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/trainingwindow.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -40,12 +40,18 @@ TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) + , mTimeAdvancer(0.05) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked); + + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); + + mProgressBar.setVisible(false); } void TrainingWindow::open() @@ -173,12 +179,28 @@ MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); + mProgressBar.setVisible(true); + mProgressBar.setProgress(0, 2); + mTimeAdvancer.run(2); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); mFadeTimeRemaining = 0.5; } + void TrainingWindow::onTrainingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + } + + void TrainingWindow::onTrainingFinished() + { + mProgressBar.setVisible(false); + } + void TrainingWindow::onFrame(float dt) { + mTimeAdvancer.onFrame(dt); + if (mFadeTimeRemaining <= 0) return; diff -Nru openmw-0.35.0/apps/openmw/mwgui/trainingwindow.hpp openmw-0.35.1/apps/openmw/mwgui/trainingwindow.hpp --- openmw-0.35.0/apps/openmw/mwgui/trainingwindow.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/trainingwindow.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -3,6 +3,8 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" +#include "timeadvancer.hpp" +#include "waitdialog.hpp" namespace MWGui { @@ -26,11 +28,17 @@ void onCancelButtonClicked (MyGUI::Widget* sender); void onTrainingSelected(MyGUI::Widget* sender); + void onTrainingProgressChanged(int cur, int total); + void onTrainingFinished(); + MyGUI::Widget* mTrainingOptions; MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; float mFadeTimeRemaining; + + WaitDialogProgressBar mProgressBar; + TimeAdvancer mTimeAdvancer; }; } diff -Nru openmw-0.35.0/apps/openmw/mwgui/waitdialog.cpp openmw-0.35.1/apps/openmw/mwgui/waitdialog.cpp --- openmw-0.35.0/apps/openmw/mwgui/waitdialog.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/waitdialog.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -3,6 +3,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" @@ -48,12 +49,11 @@ WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mWaiting(false) + , mTimeAdvancer(0.05) , mSleeping(false) , mHours(1) - , mRemainingTime(0.05) - , mCurHour(0) , mManualHours(1) + , mFadeTimeRemaining(0) , mInterruptAt(-1) { getWidget(mDateTimeText, "DateTimeText"); @@ -69,6 +69,10 @@ mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); + mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); + mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); + mProgressBar.setVisible (false); } @@ -132,11 +136,9 @@ MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); + mFadeTimeRemaining = 0.4; setVisible(false); - mProgressBar.setVisible (true); - mWaiting = true; - mCurHour = 0; mHours = hoursToWait; // FIXME: move this somewhere else? @@ -163,8 +165,7 @@ } } - mRemainingTime = 0.05; - mProgressBar.setProgress (0, mHours); + mProgressBar.setProgress (0, hoursToWait); } void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) @@ -178,6 +179,36 @@ mManualHours = position+1; } + void WaitDialog::onWaitingProgressChanged(int cur, int total) + { + mProgressBar.setProgress(cur, total); + MWBase::Environment::get().getWorld()->advanceTime(1); + MWBase::Environment::get().getMechanicsManager()->rest(mSleeping); + } + + void WaitDialog::onWaitingInterrupted() + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); + MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); + stopWaiting(); + } + + void WaitDialog::onWaitingFinished() + { + stopWaiting(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); + + // trigger levelup if possible + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); + } + } + void WaitDialog::setCanRest (bool canRest) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -204,45 +235,17 @@ void WaitDialog::onFrame(float dt) { - if (!mWaiting) - return; + mTimeAdvancer.onFrame(dt); - if (mCurHour == mInterruptAt) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}"); - MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList); - stopWaiting(); - } + if (mFadeTimeRemaining <= 0) + return; - mRemainingTime -= dt; + mFadeTimeRemaining -= dt; - while (mRemainingTime < 0) + if (mFadeTimeRemaining <= 0) { - mRemainingTime += 0.05; - ++mCurHour; - mProgressBar.setProgress (mCurHour, mHours); - - if (mCurHour <= mHours) - { - MWBase::Environment::get().getWorld ()->advanceTime (1); - MWBase::Environment::get().getMechanicsManager ()->rest (mSleeping); - } - } - - if (mCurHour > mHours) - { - stopWaiting(); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const MWMechanics::NpcStats &pcstats = player.getClass().getNpcStats(player); - - // trigger levelup if possible - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); - } + mProgressBar.setVisible(true); + mTimeAdvancer.run(mHours, mInterruptAt); } } @@ -252,14 +255,14 @@ mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); - mWaiting = false; + mTimeAdvancer.stop(); } void WaitDialog::wakeUp () { mSleeping = false; - mWaiting = false; + mTimeAdvancer.stop(); stopWaiting(); } diff -Nru openmw-0.35.0/apps/openmw/mwgui/waitdialog.hpp openmw-0.35.1/apps/openmw/mwgui/waitdialog.hpp --- openmw-0.35.0/apps/openmw/mwgui/waitdialog.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/waitdialog.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,6 +1,8 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H +#include "timeadvancer.hpp" + #include "windowbase.hpp" namespace MWGui @@ -38,7 +40,7 @@ void bedActivated() { setCanRest(true); } - bool getSleeping() { return mWaiting && mSleeping; } + bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); @@ -51,12 +53,11 @@ MyGUI::Button* mCancelButton; MWGui::Widgets::MWScrollBar* mHourSlider; - bool mWaiting; + TimeAdvancer mTimeAdvancer; bool mSleeping; - int mCurHour; int mHours; int mManualHours; // stores the hours to rest selected via slider - float mRemainingTime; + float mFadeTimeRemaining; int mInterruptAt; std::string mInterruptCreatureList; @@ -68,6 +69,10 @@ void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onWaitingProgressChanged(int cur, int total); + void onWaitingInterrupted(); + void onWaitingFinished(); + void setCanRest(bool canRest); void startWaiting(int hoursToWait); diff -Nru openmw-0.35.0/apps/openmw/mwgui/windowbase.cpp openmw-0.35.1/apps/openmw/mwgui/windowbase.cpp --- openmw-0.35.0/apps/openmw/mwgui/windowbase.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/windowbase.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwgui/windowmanagerimp.cpp openmw-0.35.1/apps/openmw/mwgui/windowmanagerimp.cpp --- openmw-0.35.0/apps/openmw/mwgui/windowmanagerimp.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/windowmanagerimp.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -19,6 +19,9 @@ #include #include +#include +#include + #include #include @@ -26,6 +29,8 @@ #include +#include + #include #include @@ -37,6 +42,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/stat.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwsound/soundmanagerimp.hpp" @@ -86,12 +92,13 @@ #include "draganddrop.hpp" #include "container.hpp" #include "controllers.hpp" +#include "jailscreen.hpp" namespace MWGui { WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, + const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap) : mConsoleOnlyScripts(consoleOnlyScripts) @@ -138,6 +145,7 @@ , mHitFader(NULL) , mScreenFader(NULL) , mDebugWindow(NULL) + , mJailScreen(NULL) , mTranslationDataStorage (translationDataStorage) , mCharGen(NULL) , mInputBlocker(NULL) @@ -162,7 +170,6 @@ , mForceHidden(GW_None) , mAllowed(GW_ALL) , mRestAllowed(true) - , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) @@ -264,7 +271,7 @@ trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(mCustomMarkers, mShowFPSLevel, mDragAndDrop); + mHud = new HUD(mCustomMarkers, Settings::Manager::getInt("fps", "HUD"), mDragAndDrop); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -286,6 +293,7 @@ mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mJailScreen = new JailScreen(); mWerewolfFader = new ScreenFader("textures\\werewolfoverlay.dds"); mBlindnessFader = new ScreenFader("black.png"); @@ -398,6 +406,7 @@ delete mScreenFader; delete mBlindnessFader; delete mDebugWindow; + delete mJailScreen; delete mCursorManager; @@ -463,6 +472,7 @@ mInventoryWindow->setTrading(false); mRecharge->setVisible(false); mVideoBackground->setVisible(false); + mJailScreen->setVisible(false); mHud->setVisible(mHudEnabled && mGuiEnabled); mToolTips->setVisible(mGuiEnabled); @@ -608,6 +618,9 @@ case GM_Journal: mJournal->setVisible(true); break; + case GM_Jail: + mJailScreen->setVisible(true); + break; case GM_LoadingWallpaper: case GM_Loading: // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway, @@ -908,6 +921,7 @@ mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); mCompanionWindow->onFrame(); + mJailScreen->onFrame(frameDuration); mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); @@ -1183,6 +1197,12 @@ updateVisible(); } + void WindowManager::goToJail(int days) + { + pushGuiMode(MWGui::GM_Jail); + mJailScreen->goToJail(days); + } + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { mSelectedSpell = spellId; diff -Nru openmw-0.35.0/apps/openmw/mwgui/windowmanagerimp.hpp openmw-0.35.1/apps/openmw/mwgui/windowmanagerimp.hpp --- openmw-0.35.0/apps/openmw/mwgui/windowmanagerimp.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwgui/windowmanagerimp.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -5,13 +5,15 @@ This class owns and controls all the MW specific windows in the GUI. It can enable/disable Gui mode, and is responsible for sending and retrieving information from the Gui. - - MyGUI should be initialized separately before creating instances of - this class. **/ +#include + #include "../mwbase/windowmanager.hpp" +#include +#include + #include "mapwindow.hpp" #include @@ -89,6 +91,7 @@ class WindowModal; class ScreenFader; class DebugWindow; + class JailScreen; class WindowManager : public MWBase::WindowManager { @@ -96,7 +99,7 @@ typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, + WindowManager(const Compiler::Extensions& extensions, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding, bool exportFonts, const std::map& fallbackMap); @@ -127,6 +130,8 @@ virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void goToJail(int days); + virtual GuiMode getMode() const; virtual bool containsMode(GuiMode mode) const; @@ -403,6 +408,7 @@ ScreenFader* mHitFader; ScreenFader* mScreenFader; DebugWindow* mDebugWindow; + JailScreen* mJailScreen; Translation::Storage& mTranslationDataStorage; @@ -450,7 +456,6 @@ void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings - int mShowFPSLevel; float mFPS; unsigned int mTriangleCount; unsigned int mBatchCount; diff -Nru openmw-0.35.0/apps/openmw/mwinput/inputmanagerimp.cpp openmw-0.35.1/apps/openmw/mwinput/inputmanagerimp.cpp --- openmw-0.35.0/apps/openmw/mwinput/inputmanagerimp.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwinput/inputmanagerimp.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,7 @@ #include #include +#include #include @@ -11,6 +12,8 @@ #include #include +#include + #include #include "../engine.hpp" @@ -32,6 +35,8 @@ #include "../mwgui/windowbase.hpp" +#include + using namespace ICS; namespace @@ -97,7 +102,8 @@ { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab) + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab) : mOgre(ogre) , mPlayer(NULL) , mEngine(engine) @@ -120,6 +126,9 @@ , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mAttemptJump(false) , mControlsDisabled(false) + , mJoystickLastUsed(false) + , mDetectingKeyboard(false) + , mFakeDeviceID(1) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -128,13 +137,14 @@ mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); + mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); + loadControllerDefaults(); for (int i = 0; i < A_Last; ++i) { @@ -148,6 +158,32 @@ mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; + + /* Joystick Init */ + + //Load controller mappings +#if SDL_VERSION_ATLEAST(2,0,2) + if(controllerBindingsFile!="") + { + SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); + } +#endif + + //Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(mFakeDeviceID, evt); + } + else + { + //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + } + } } void InputManager::clear() @@ -190,6 +226,27 @@ int action = channel->getNumber(); + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) + { + //Is a normal button press, so don't change it at all + } + //Otherwise only trigger button presses as they go through specific points + else if(previousValue >= .8 && currentValue < .8) + { + currentValue = 0.0; + previousValue = 1.0; + } + else if(previousValue <= .6 && currentValue > .6) + { + currentValue = 1.0; + previousValue = 0.0; + } + else + { + //If it's not switching between those values, ignore the channel change. + return; + } + if (mControlSwitch["playercontrols"]) { if (action == A_Use) @@ -219,7 +276,6 @@ break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) activate(); break; @@ -346,6 +402,47 @@ updateCursorMode(); + if(mJoystickLastUsed) + { + if (mGuiCursorEnabled) + { + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; + float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // We keep track of our own mouse position, so that moving the mouse while in + // game mode does not move the position of the GUI cursor + mMouseX += xAxis * dt * 1500.0f; + mMouseY += yAxis * dt * 1500.0f; + mMouseWheel -= zAxis * dt * 1500.0f; + + mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); + mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + + MyGUI::InputManager::getInstance().injectMouseMove( mMouseX, mMouseY, mMouseWheel); + mInputManager->warpMouse(mMouseX, mMouseY); + } + if (mMouseLookEnabled) + { + float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + resetIdleTime(); + + float rot[3]; + rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + rot[1] = 0.0f; + rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer->yaw(rot[2]); + mPlayer->pitch(rot[0]); + } + } + } + // Disable movement in Gui mode if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)) @@ -355,34 +452,74 @@ if (mControlSwitch["playercontrols"]) { bool triedToMove = false; - if (actionIsActive(A_MoveLeft)) + bool isRunning = false; + if(mJoystickLastUsed) { - triedToMove = true; - mPlayer->setLeftRight (-1); - } - else if (actionIsActive(A_MoveRight)) - { - triedToMove = true; - mPlayer->setLeftRight (1); - } + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); + if (xAxis < .5) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (xAxis > .5) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } - if (actionIsActive(A_MoveForward)) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); + if (yAxis < .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (yAxis > .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } + isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; + if(triedToMove) resetIdleTime(); } - else if (actionIsActive(A_MoveBackward)) + else { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); - } + if (actionIsActive(A_MoveLeft)) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (actionIsActive(A_MoveRight)) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } - else if(mPlayer->getAutoMove()) - { - triedToMove = true; - mPlayer->setForwardBackward (1); + if (actionIsActive(A_MoveForward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (actionIsActive(A_MoveBackward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } } mPlayer->setSneak(actionIsActive(A_Sneak)); @@ -394,7 +531,7 @@ mOverencumberedMessageDelay = 0.f; } - if (mAlwaysRunActive) + if (mAlwaysRunActive || isRunning) mPlayer->setRunState(!actionIsActive(A_Run)); else mPlayer->setRunState(actionIsActive(A_Run)); @@ -538,6 +675,7 @@ } if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); + mJoystickLastUsed = false; } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -550,6 +688,7 @@ void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { + mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); @@ -558,6 +697,7 @@ void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { + mJoystickLastUsed = false; bool guiMode = false; if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events @@ -582,7 +722,8 @@ } void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) - { + { + mJoystickLastUsed = false; if(mInputBinder->detectingBindingState()) { @@ -602,6 +743,7 @@ { mInputBinder->mouseMoved (arg); + mJoystickLastUsed = false; resetIdleTime (); if (mGuiCursorEnabled) @@ -650,6 +792,78 @@ } } + void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + bool guiMode = false; + + if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click + { + guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + if(!mInputBinder->detectingBindingState()) + { + guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + { + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } + } + } + } + + setPlayerControlsEnabled(!guiMode); + + //esc, to leave initial movie screen + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); + + if (!mControlsDisabled) + mInputBinder->buttonPressed(deviceID, arg); + } + + void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + if(mInputBinder->detectingBindingState()) + mInputBinder->buttonReleased(deviceID, arg); + else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + { + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + + if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind + + setPlayerControlsEnabled(!guiMode); + mInputBinder->buttonReleased(deviceID, arg); + } + else + mInputBinder->buttonReleased(deviceID, arg); + + //to escape initial movie + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + } + + void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) + { + mJoystickLastUsed = true; + if (!mControlsDisabled) + mInputBinder->axisMoved(deviceID, arg); + } + + void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerAdded(deviceID, arg); + } + void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerRemoved(arg); + } + void InputManager::windowFocusChange(bool have_focus) { } @@ -895,7 +1109,7 @@ bool InputManager::actionIsActive (int id) { - return mInputBinder->getChannel (id)->getValue () == 1; + return (mInputBinder->getChannel (id)->getValue ()==1.0); } void InputManager::loadKeyDefaults (bool force) @@ -968,14 +1182,88 @@ && mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { - clearAllBindings (control); + clearAllKeyBindings(control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end() && !mInputBinder->isKeyBound(defaultKeyBindings[i])) + { + control->setInitialValue(0.0f); mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); + } else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) + { + control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); + } + } + } + } + + void InputManager::loadControllerDefaults(bool force) + { + // using hardcoded key defaults is inevitable, if we want the configuration files to stay valid + // across different versions of OpenMW (in the case where another input action is added) + std::map defaultButtonBindings; + + defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A; + defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X; + defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + //defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9) + defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; + defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y; + defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK; + defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; + defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; + defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; + defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; + defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + defaultButtonBindings[A_QuickKey4] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + + std::map defaultAxisBindings; + defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY; + defaultAxisBindings[A_MoveLeftRight] = SDL_CONTROLLER_AXIS_LEFTX; + defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY; + defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX; + defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + + for (int i = 0; i < A_Last; i++) + { + ICS::Control* control; + bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; + if (!controlExists) + { + float initial; + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + initial = 0.0f; + else initial = 0.5f; + control = new ICS::Control(boost::lexical_cast(i), false, true, initial, ICS::ICS_MAX, ICS::ICS_MAX); + mInputBinder->addControl(control); + control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); + } + else + { + control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; + } + + if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) + { + clearAllControllerBindings(control); + + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + { + control->setInitialValue(0.0f); + mInputBinder->addJoystickButtonBinding(control, mFakeDeviceID, defaultButtonBindings[i], ICS::Control::INCREASE); + } + else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) + { + control->setValue(0.5f); + control->setInitialValue(0.5f); + mInputBinder->addJoystickAxisBinding(control, mFakeDeviceID, defaultAxisBindings[i], ICS::Control::INCREASE); + } } } } @@ -1029,7 +1317,7 @@ return "#{" + descriptions[action] + "}"; } - std::string InputManager::getActionBindingName (int action) + std::string InputManager::getActionKeyBindingName (int action) { if (mInputBinder->getChannel (action)->getControlsCount () == 0) return "#{sNone}"; @@ -1044,7 +1332,81 @@ return "#{sNone}"; } - std::vector InputManager::getActionSorting() + std::string InputManager::getActionControllerBindingName (int action) + { + if (mInputBinder->getChannel (action)->getControlsCount () == 0) + return "#{sNone}"; + + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; + + if (mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) + return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); + else if (mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) + return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); + else + return "#{sNone}"; + } + + std::string InputManager::sdlControllerButtonToString(int button) + { + switch(button) + { + case SDL_CONTROLLER_BUTTON_A: + return "A Button"; + case SDL_CONTROLLER_BUTTON_B: + return "B Button"; + case SDL_CONTROLLER_BUTTON_BACK: + return "Back Button"; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + return "DPad Down"; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + return "DPad Left"; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + return "DPad Right"; + case SDL_CONTROLLER_BUTTON_DPAD_UP: + return "DPad Up"; + case SDL_CONTROLLER_BUTTON_GUIDE: + return "Guide Button"; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + return "Left Shoulder"; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + return "Left Stick Button"; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + return "Right Shoulder"; + case SDL_CONTROLLER_BUTTON_RIGHTSTICK: + return "Right Stick Button"; + case SDL_CONTROLLER_BUTTON_START: + return "Start Button"; + case SDL_CONTROLLER_BUTTON_X: + return "X Button"; + case SDL_CONTROLLER_BUTTON_Y: + return "Y Button"; + default: + return "Button " + boost::lexical_cast(button); + } + } + std::string InputManager::sdlControllerAxisToString(int axis) + { + switch(axis) + { + case SDL_CONTROLLER_AXIS_LEFTX: + return "Left Stick X"; + case SDL_CONTROLLER_AXIS_LEFTY: + return "Left Stick Y"; + case SDL_CONTROLLER_AXIS_RIGHTX: + return "Right Stick X"; + case SDL_CONTROLLER_AXIS_RIGHTY: + return "Right Stick Y"; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + return "Left Trigger"; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + return "Right Trigger"; + default: + return "Axis " + boost::lexical_cast(axis); + } + } + + std::vector InputManager::getActionKeySorting() { std::vector ret; ret.push_back(A_MoveForward); @@ -1086,11 +1448,42 @@ return ret; } + std::vector InputManager::getActionControllerSorting() + { + std::vector ret; + ret.push_back(A_TogglePOV); + ret.push_back(A_Sneak); + ret.push_back(A_Activate); + ret.push_back(A_Use); + ret.push_back(A_ToggleWeapon); + ret.push_back(A_ToggleSpell); + ret.push_back(A_AutoMove); + ret.push_back(A_Jump); + ret.push_back(A_Inventory); + ret.push_back(A_Journal); + ret.push_back(A_Rest); + ret.push_back(A_QuickSave); + ret.push_back(A_QuickLoad); + ret.push_back(A_Screenshot); + ret.push_back(A_QuickKeysMenu); + ret.push_back(A_QuickKey1); + ret.push_back(A_QuickKey2); + ret.push_back(A_QuickKey3); + ret.push_back(A_QuickKey4); + ret.push_back(A_QuickKey5); + ret.push_back(A_QuickKey6); + ret.push_back(A_QuickKey7); + ret.push_back(A_QuickKey8); + ret.push_back(A_QuickKey9); + ret.push_back(A_QuickKey10); + + return ret; + } - void InputManager::enableDetectingBindingMode (int action) + void InputManager::enableDetectingBindingMode (int action, bool keyboard) { + mDetectingKeyboard = keyboard; ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE); } @@ -1106,9 +1499,17 @@ { //Disallow binding escape key if(key==SDL_SCANCODE_ESCAPE) + { + //Stop binding if esc pressed + mInputBinder->cancelDetectingBindingState(); + MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); + return; + } + if(!mDetectingKeyboard) return; - clearAllBindings(control); + clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1116,59 +1517,69 @@ void InputManager::mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); + if(!mDetectingKeyboard) + return; + clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, deviceId, axis, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } - - void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction) + void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , int axis, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, deviceId, button, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } + //only allow binding to the trigers + if(axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + return; + if(mDetectingKeyboard) + return; - void InputManager::joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickPOVBindingDetected (ICS, control, deviceId, pov, axis, direction); + clearAllControllerBindings(control); + control->setValue(0.5f); //axis bindings must start at 0.5 + control->setInitialValue(0.5f); + ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, deviceID, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction) + void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickSliderBindingDetected (ICS, control, deviceId, slider, direction); + if(mDetectingKeyboard) + return; + clearAllControllerBindings(control); + control->setInitialValue(0.0f); + ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::clearAllBindings (ICS::Control* control) + void InputManager::clearAllKeyBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE)); if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE)); + } - /// \todo add joysticks here once they are added + void InputManager::clearAllControllerBindings (ICS::Control* control) + { + // right now we don't really need multiple bindings for the same action, so remove all others first + if (mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) + mInputBinder->removeJoystickAxisBinding (mFakeDeviceID, mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); } - void InputManager::resetToDefaultBindings() + void InputManager::resetToDefaultKeyBindings() { loadKeyDefaults(true); } + void InputManager::resetToDefaultControllerBindings() + { + loadControllerDefaults(true); + } + MyGUI::MouseButton InputManager::sdlButtonToMyGUI(Uint8 button) { //The right button is the second button, according to MyGUI diff -Nru openmw-0.35.0/apps/openmw/mwinput/inputmanagerimp.hpp openmw-0.35.1/apps/openmw/mwinput/inputmanagerimp.hpp --- openmw-0.35.0/apps/openmw/mwinput/inputmanagerimp.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwinput/inputmanagerimp.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -4,6 +4,7 @@ #include "../mwgui/mode.hpp" #include +#include #include "../mwbase/inputmanager.hpp" #include @@ -41,6 +42,11 @@ class MouseButton; } +namespace Files +{ + struct ConfigurationManager; +} + #include #include @@ -55,13 +61,15 @@ public SFO::KeyListener, public SFO::MouseListener, public SFO::WindowListener, + public SFO::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { public: InputManager(OEngine::Render::OgreRenderer &_ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab); + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab); virtual ~InputManager(); @@ -82,11 +90,16 @@ virtual bool getControlSwitch (const std::string& sw); virtual std::string getActionDescription (int action); - virtual std::string getActionBindingName (int action); + virtual std::string getActionKeyBindingName (int action); + virtual std::string getActionControllerBindingName (int action); virtual int getNumActions() { return A_Last; } - virtual std::vector getActionSorting (); - virtual void enableDetectingBindingMode (int action); - virtual void resetToDefaultBindings(); + virtual std::vector getActionKeySorting(); + virtual std::vector getActionControllerSorting(); + virtual void enableDetectingBindingMode (int action, bool keyboard); + virtual void resetToDefaultKeyBindings(); + virtual void resetToDefaultControllerBindings(); + + virtual bool joystickLastUsed() {return mJoystickLastUsed;} public: virtual void keyPressed(const SDL_KeyboardEvent &arg ); @@ -97,6 +110,12 @@ virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg); + virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); virtual void windowResized (int x, int y); @@ -113,21 +132,17 @@ virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction); - - virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction); + virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , int axis, ICS::Control::ControlChangingDirection direction); - virtual void joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction); - - virtual void joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction); + virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , unsigned int button, ICS::Control::ControlChangingDirection direction); - void clearAllBindings (ICS::Control* control); + void clearAllKeyBindings (ICS::Control* control); + void clearAllControllerBindings (ICS::Control* control); private: + bool mJoystickLastUsed; OEngine::Render::OgreRenderer &mOgre; MWWorld::Player* mPlayer; OMW::Engine& mEngine; @@ -156,6 +171,8 @@ bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDetectingKeyboard; + float mOverencumberedMessageDelay; float mMouseX; @@ -171,6 +188,9 @@ void adjustMouseRegion(int width, int height); MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); + virtual std::string sdlControllerAxisToString(int axis); + virtual std::string sdlControllerButtonToString(int button); + void resetIdleTime(); void updateIdleTime(float dt); @@ -199,6 +219,9 @@ bool actionIsActive (int id); void loadKeyDefaults(bool force = false); + void loadControllerDefaults(bool force = false); + + int mFakeDeviceID; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers private: enum Actions @@ -263,6 +286,11 @@ A_ToggleDebug, + A_LookUpDown, //Joystick look + A_LookLeftRight, + A_MoveForwardBackward, + A_MoveLeftRight, + A_Last // Marker for the last item }; }; diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/activespells.cpp openmw-0.35.1/apps/openmw/mwmechanics/activespells.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/activespells.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/activespells.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -152,12 +152,7 @@ void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, const std::string &displayName, int casterActorId) { - bool exists = false; - for (TContainer::const_iterator it = begin(); it != end(); ++it) - { - if (id == it->first) - exists = true; - } + TContainer::iterator it(mSpells.find(id)); ActiveSpellParams params; params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); @@ -165,14 +160,44 @@ params.mDisplayName = displayName; params.mCasterActorId = casterActorId; - if (!exists || stack) - mSpells.insert (std::make_pair(id, params)); + if (it == end() || stack) + { + mSpells.insert(std::make_pair(id, params)); + } else - mSpells.find(id)->second = params; + { + // addSpell() is called with effects for a range. + // but a spell may have effects with different ranges (e.g. Touch & Target) + // so, if we see new effects for same spell assume additional + // spell effects and add to existing effects of spell + mergeEffects(params.mEffects, it->second.mEffects); + it->second = params; + } mSpellsChanged = true; } + void ActiveSpells::mergeEffects(std::vector& addTo, const std::vector& from) + { + for (std::vector::const_iterator effect(from.begin()); effect != from.end(); ++effect) + { + // if effect is not in addTo, add it + bool missing = true; + for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) + { + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) + { + missing = false; + break; + } + } + if (missing) + { + addTo.push_back(*effect); + } + } + } + void ActiveSpells::removeEffects(const std::string &id) { mSpells.erase(Misc::StringUtils::lowerCase(id)); diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/activespells.hpp openmw-0.35.1/apps/openmw/mwmechanics/activespells.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/activespells.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/activespells.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -55,6 +55,9 @@ void rebuildEffects() const; + /// Add any effects that are in "from" and not in "addTo" to "addTo" + void mergeEffects(std::vector& addTo, const std::vector& from); + double timeToExpire (const TIterator& iterator) const; ///< Returns time (in in-game hours) until the spell pointed to by \a iterator /// expires. diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/actors.cpp openmw-0.35.1/apps/openmw/mwmechanics/actors.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/actors.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/actors.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -515,8 +515,8 @@ for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - + stat.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); @@ -782,8 +782,8 @@ for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - + skill.setModifiers(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude(), + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude(), effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/actors.hpp openmw-0.35.1/apps/openmw/mwmechanics/actors.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/actors.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/actors.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -5,6 +5,7 @@ #include #include #include +#include #include "movement.hpp" #include "../mwbase/world.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/aicombat.cpp openmw-0.35.1/apps/openmw/mwmechanics/aicombat.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/aicombat.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/aicombat.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -207,16 +207,6 @@ const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. - if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) - { - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); - return true; - } - - - - //Update every frame bool& combatMove = storage.mCombatMove; @@ -476,6 +466,19 @@ // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. + if (distToTarget >= rangeAttack + && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) + { + // TODO: start fleeing? + movement.mPosition[0] = 0; + movement.mPosition[1] = 0; + movement.mPosition[2] = 0; + readyToAttack = false; + actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + return false; + } + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/aiwander.hpp openmw-0.35.1/apps/openmw/mwmechanics/aiwander.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/aiwander.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/aiwander.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -17,6 +17,7 @@ namespace ESM { + class Cell; namespace AiSequence { struct AiWander; diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/character.cpp openmw-0.35.1/apps/openmw/mwmechanics/character.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/character.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/character.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/enchanting.cpp openmw-0.35.1/apps/openmw/mwmechanics/enchanting.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/enchanting.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/enchanting.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/levelledlist.hpp openmw-0.35.1/apps/openmw/mwmechanics/levelledlist.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/levelledlist.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/levelledlist.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,7 @@ #define OPENMW_MECHANICS_LEVELLEDLIST_H #include "../mwworld/ptr.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" @@ -12,9 +13,9 @@ { /// @return ID of resulting item, or empty if none - inline std::string getLevelledItem (const ESM::LeveledListBase* levItem, bool creature, unsigned char failChance=0) + inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, unsigned char failChance=0) { - const std::vector& items = levItem->mList; + const std::vector& items = levItem->mList; const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerLevel = player.getClass().getCreatureStats(player).getLevel(); @@ -27,7 +28,7 @@ std::vector candidates; int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (it->mLevel > highestLevel && it->mLevel <= playerLevel) highestLevel = it->mLevel; @@ -39,7 +40,7 @@ allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; std::pair highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { if (playerLevel >= it->mLevel && (allLevels || it->mLevel == highestLevel)) diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/magiceffects.hpp openmw-0.35.1/apps/openmw/mwmechanics/magiceffects.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/magiceffects.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/magiceffects.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -72,6 +72,8 @@ // Used by effect management classes (ActiveSpells, InventoryStore, Spells) to list active effect sources for GUI display struct EffectSourceVisitor { + virtual ~EffectSourceVisitor() { } + virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp openmw-0.35.1/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -873,31 +875,31 @@ mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) { - const std::string& owner = item.getCellRef().getOwner(); + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; - const std::string& faction = item.getCellRef().getFaction(); + const std::string& faction = cellref.getFaction(); bool isFactionOwned = false; if (!faction.empty() && ptr.getClass().isNpc()) { const std::map& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks(); std::map::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction)); if (found == factions.end() - || found->second < item.getCellRef().getFactionRank()) + || found->second < cellref.getFactionRank()) isFactionOwned = true; } - const std::string& globalVariable = item.getCellRef().getGlobalVariable(); + const std::string& globalVariable = cellref.getGlobalVariable(); if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1) { isOwned = false; isFactionOwned = false; } - if (!item.getCellRef().getOwner().empty()) - victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true); + if (!cellref.getOwner().empty()) + victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true); return (!isOwned && !isFactionOwned); } @@ -916,7 +918,7 @@ } MWWorld::Ptr victim; - if (isAllowedToUse(ptr, bed, victim)) + if (isAllowedToUse(ptr, bed.getCellRef(), victim)) return false; if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) @@ -931,16 +933,103 @@ void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) + if (isAllowedToUse(ptr, item.getCellRef(), victim)) return; commitCrime(ptr, victim, OT_Trespassing); } - void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count) + std::vector > MechanicsManager::getStolenItemOwners(const std::string& itemid) + { + std::vector > result; + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return result; + else + { + const OwnerMap& owners = it->second; + for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt) + result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second)); + return result; + } + } + + bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid) + { + StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid)); + if (it == mStolenItems.end()) + return false; + const OwnerMap& owners = it->second; + OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false)); + return ownerFound != owners.end(); + } + + void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) + { + MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it))); + if (stolenIt == mStolenItems.end()) + continue; + OwnerMap& owners = stolenIt->second; + int itemCount = it->getRefData().getCount(); + for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();) + { + int toRemove = std::min(itemCount, ownerIt->second); + itemCount -= toRemove; + ownerIt->second -= toRemove; + if (ownerIt->second == 0) + owners.erase(ownerIt++); + else + ++ownerIt; + } + + int toMove = it->getRefData().getCount() - itemCount; + + targetContainer.getClass().getContainerStore(targetContainer).add(*it, toMove, targetContainer); + store.remove(*it, toMove, player); + } + // TODO: unhardcode the locklevel + targetContainer.getClass().lock(targetContainer,50); + } + + void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, + int count) { + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item, victim)) + + const MWWorld::CellRef* ownerCellRef = &item.getCellRef(); + if (!container.isEmpty()) + { + // Inherit the owner of the container + ownerCellRef = &container.getCellRef(); + } + else + { + if (!item.getCellRef().hasContentFile()) + { + // this is a manually placed item, which means it was already stolen + return; + } + } + + if (isAllowedToUse(ptr, *ownerCellRef, victim)) return; + + Owner owner; + owner.first = ownerCellRef->getOwner(); + owner.second = false; + if (owner.first.empty()) + { + owner.first = ownerCellRef->getFaction(); + owner.second = true; + } + Misc::StringUtils::toLower(owner.first); + mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count; + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } @@ -949,7 +1038,7 @@ // NOTE: victim may be empty // Only player can commit crime - if (player.getRefData().getHandle() != "player") + if (player != MWBase::Environment::get().getWorld()->getPlayerPtr()) return false; // Find all the actors within the alarm radius @@ -1351,22 +1440,37 @@ int MechanicsManager::countSavedGameRecords() const { - return 1; // Death counter + return 1 // Death counter + +1; // Stolen items } void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const { mActors.write(writer, listener); + + ESM::StolenItems items; + items.mStolenItems = mStolenItems; + writer.startRecord(ESM::REC_STLN); + items.write(writer); + writer.endRecord(ESM::REC_STLN); } void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - mActors.readRecord(reader, type); + if (type == ESM::REC_STLN) + { + ESM::StolenItems items; + items.load(reader); + mStolenItems = items.mStolenItems; + } + else + mActors.readRecord(reader, type); } void MechanicsManager::clear() { mActors.clear(); + mStolenItems.clear(); } bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp openmw-0.35.1/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -35,6 +35,11 @@ Objects mObjects; Actors mActors; + typedef std::pair Owner; // < Owner id, bool isFaction > + typedef std::map OwnerMap; // < Owner, number of stolen items with this id from this owner > + typedef std::map StolenItemsMap; + StolenItemsMap mStolenItems; + public: void buildPlayer(); @@ -121,16 +126,15 @@ /// @return false if the attack was considered a "friendly hit" and forgiven virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so - virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); + /// @param container The container the item is in; may be empty for an item in the world + virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, + int count); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); /// Attempt sleeping in a bed. If this is illegal, call commitCrime. /// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed); - /// @return is \a ptr allowed to take/use \a item or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim); - virtual void forceStateUpdate(const MWWorld::Ptr &ptr); virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); @@ -168,9 +172,21 @@ virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); + + /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). + /// + virtual std::vector > getStolenItemOwners(const std::string& itemid); + + /// Has the player stolen this item from the given owner? + virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); + + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); }; } diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/npcstats.cpp openmw-0.35.1/apps/openmw/mwmechanics/npcstats.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/npcstats.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/npcstats.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -140,32 +140,9 @@ mFactionReputation[Misc::StringUtils::lowerCase(faction)] = value; } -float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, - int level, float extraFactor) const +float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - if (level<0) - level = static_cast (getSkill (skillIndex).getBase()); - - const ESM::Skill *skill = - MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); - - float skillFactor = 1; - - if (usageType>=4) - throw std::runtime_error ("skill usage type out of range"); - - if (usageType>=0) - { - skillFactor = skill->mData.mUseValue[usageType]; - - if (skillFactor<0) - throw std::runtime_error ("invalid skill gain factor"); - - if (skillFactor==0) - return 0; - } - - skillFactor *= extraFactor; + float progressRequirement = 1 + getSkill (skillIndex).getBase(); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -188,11 +165,15 @@ break; } + progressRequirement *= typeFactor; + if (typeFactor<=0) throw std::runtime_error ("invalid skill type factor"); float specialisationFactor = 1; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); if (skill->mData.mSpecialization==class_.mData.mSpecialization) { specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); @@ -200,7 +181,9 @@ if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } - return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor); + progressRequirement *= specialisationFactor; + + return progressRequirement; } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor) @@ -209,13 +192,26 @@ if(mIsWerewolf) return; + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); + float skillGain = 1; + if (usageType>=4) + throw std::runtime_error ("skill usage type out of range"); + if (usageType>=0) + { + skillGain = skill->mData.mUseValue[usageType]; + if (skillGain<0) + throw std::runtime_error ("invalid skill gain factor"); + } + skillGain *= extraFactor; + MWMechanics::SkillValue& value = getSkill (skillIndex); - value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType, -1, extraFactor)); + value.setProgress(value.getProgress() + skillGain); - if (value.getProgress()>=1) + if (int(value.getProgress())>=int(getSkillProgressRequirement(skillIndex, class_))) { - // skill leveled up + // skill levelled up increaseSkill(skillIndex, class_, false); } } @@ -271,7 +267,7 @@ MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never); } - getSkill (skillIndex).setBase (base); + getSkill(skillIndex).setBase (base); if (!preserveProgress) getSkill(skillIndex).setProgress(0); } @@ -283,13 +279,15 @@ void MWMechanics::NpcStats::levelUp() { - mLevelProgress -= 10; - for (int i=0; i &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + mLevelProgress -= gmst.find("iLevelUpTotal")->getInt(); + mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console + + for (int i=0; i #include -#include "stat.hpp" - #include "creaturestats.hpp" namespace ESM @@ -23,7 +21,7 @@ class NpcStats : public CreatureStats { int mDisposition; - SkillValue mSkill[ESM::Skill::Length]; + SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only SkillValue mWerewolfSkill[ESM::Skill::Length]; int mReputation; int mCrimeId; @@ -74,11 +72,7 @@ bool isInFaction (const std::string& faction) const; - float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1, - int level = -1, float extraFactor=1.f) const; - ///< \param usageType: Usage specific factor, specified in the respective skill record; - /// -1: use a factor of 1.0 instead. - /// \param level Level to base calculation on; -1: use current level. + float getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const; void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f); ///< Increase skill by usage. diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/obstacle.hpp openmw-0.35.1/apps/openmw/mwmechanics/obstacle.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/obstacle.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/obstacle.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,10 +1,6 @@ #ifndef OPENMW_MECHANICS_OBSTACLE_H #define OPENMW_MECHANICS_OBSTACLE_H -//#include "../mwbase/world.hpp" -//#include "../mwworld/class.hpp" -#include "../mwworld/cellstore.hpp" - namespace MWWorld { class Ptr; diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/spellcasting.cpp openmw-0.35.1/apps/openmw/mwmechanics/spellcasting.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/spellcasting.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/spellcasting.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -56,6 +56,64 @@ } } + void applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) + { + MWMechanics::DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); + target.getClass().getCreatureStats(target).setDynamic(attribute, value); + } + + // TODO: refactor the effect tick functions in Actors so they can be reused here + void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) + { + int effectId = effect.mId; + if (effectId == ESM::MagicEffect::DamageHealth) + { + applyDynamicStatsEffect(0, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreHealth) + { + applyDynamicStatsEffect(0, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageFatigue) + { + applyDynamicStatsEffect(2, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreFatigue) + { + applyDynamicStatsEffect(2, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageMagicka) + { + applyDynamicStatsEffect(1, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreMagicka) + { + applyDynamicStatsEffect(1, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) + { + int attribute = effect.mArg; + MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); + if (effectId == ESM::MagicEffect::DamageAttribute) + value.damage(magnitude); + else + value.restore(magnitude); + target.getClass().getCreatureStats(target).setAttribute(attribute, value); + } + else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) + { + if (target.getTypeName() != typeid(ESM::NPC).name()) + return; + int skill = effect.mArg; + MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); + if (effectId == ESM::MagicEffect::DamageSkill) + value.damage(magnitude); + else + value.restore(magnitude); + } + } + } namespace MWMechanics @@ -309,9 +367,11 @@ for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) { - if (iter->mRange != range) - continue; - found = true; + if (iter->mRange == range) + { + found = true; + break; + } } if (!found) return; @@ -436,8 +496,8 @@ float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; - if (target.getClass().isActor() && hasDuration) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0) { ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; @@ -469,7 +529,12 @@ } } else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + { + if (hasDuration && target.getClass().isActor()) + applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); + else + applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + } // Re-casting a summon effect will remove the creature from previous castings of that effect. if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) @@ -483,16 +548,6 @@ } } - // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. - // This was probably just done to have the effect visible in the magic menu for a while - // to notify the player they've been damaged? - if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute - || effectIt->mEffectID == ESM::MagicEffect::DamageSkill - || effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute - || effectIt->mEffectID == ESM::MagicEffect::RestoreSkill - ) - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); - if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) { // Play sound, only for the first effect @@ -582,52 +637,6 @@ } else { - if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - if (effectId == ESM::MagicEffect::CurePoison) target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); else if (effectId == ESM::MagicEffect::CureParalyzation) @@ -677,13 +686,7 @@ } } } - - void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) - { - DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.modify(magnitude); - target.getClass().getCreatureStats(target).setDynamic(attribute, value); - } + bool CastSpell::cast(const std::string &id) { @@ -766,8 +769,7 @@ if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } std::string projectileModel; @@ -851,10 +853,7 @@ if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - { - inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } + inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); } diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/spellcasting.hpp openmw-0.35.1/apps/openmw/mwmechanics/spellcasting.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/spellcasting.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/spellcasting.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -97,8 +97,6 @@ /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); - - void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude); }; } diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/stat.cpp openmw-0.35.1/apps/openmw/mwmechanics/stat.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/stat.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/stat.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -15,6 +15,11 @@ mDamage = state.mDamage; } +void MWMechanics::AttributeValue::setModifiers(int fortify, int drain, int absorb) +{ + mFortified = fortify; + mModifier = (fortify - drain) - absorb; +} void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/stat.hpp openmw-0.35.1/apps/openmw/mwmechanics/stat.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/stat.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/stat.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -235,26 +235,29 @@ class AttributeValue { int mBase; - int mModifier; + int mFortified; + int mModifier; // net effect of Fortified, Drain & Absorb float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue() : mBase(0), mFortified(0), mModifier(0), mDamage(0) {} int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } - void setModifier(int mod) { mModifier = mod; } + void setModifiers(int fortify, int drain, int absorb); - void damage(float damage) { mDamage += damage; } + void damage(float damage) { mDamage = std::min(mDamage + damage, (float)(mBase + mFortified)); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const AttributeValue& left, const AttributeValue& right); }; class SkillValue : public AttributeValue @@ -268,13 +271,16 @@ void writeState (ESM::StatState& state) const; void readState (const ESM::StatState& state); + + friend bool operator== (const SkillValue& left, const SkillValue& right); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) { return left.getBase() == right.getBase() + && left.mFortified == right.mFortified && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage(); + && left.mDamage == right.mDamage; } inline bool operator!= (const AttributeValue& left, const AttributeValue& right) { @@ -283,9 +289,8 @@ inline bool operator== (const SkillValue& left, const SkillValue& right) { - return left.getBase() == right.getBase() - && left.getModifier() == right.getModifier() - && left.getDamage() == right.getDamage() + // delegate to base class for most of the work + return (static_cast(left) == right) && left.getProgress() == right.getProgress(); } inline bool operator!= (const SkillValue& left, const SkillValue& right) diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/summoning.cpp openmw-0.35.1/apps/openmw/mwmechanics/summoning.cpp --- openmw-0.35.0/apps/openmw/mwmechanics/summoning.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/summoning.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -51,6 +51,10 @@ } + UpdateSummonedCreatures::~UpdateSummonedCreatures() + { + } + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { if (isSummoningEffect(key.mId) && magnitude > 0) diff -Nru openmw-0.35.0/apps/openmw/mwmechanics/summoning.hpp openmw-0.35.1/apps/openmw/mwmechanics/summoning.hpp --- openmw-0.35.0/apps/openmw/mwmechanics/summoning.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwmechanics/summoning.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -14,6 +14,7 @@ struct UpdateSummonedCreatures : public EffectSourceVisitor { UpdateSummonedCreatures(const MWWorld::Ptr& actor); + virtual ~UpdateSummonedCreatures(); virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, diff -Nru openmw-0.35.0/apps/openmw/mwrender/animation.cpp openmw-0.35.1/apps/openmw/mwrender/animation.cpp --- openmw-0.35.0/apps/openmw/mwrender/animation.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/animation.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -1270,7 +1271,11 @@ if (bonename.empty()) params.mObjects = NifOgre::Loader::createObjects(mInsert, model); else + { + if (!mSkelBase) + return; params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); + } setRenderProperties(params.mObjects, RV_Effects, RQG_Main, RQG_Alpha, 0.f, false, NULL); diff -Nru openmw-0.35.0/apps/openmw/mwrender/creatureanimation.cpp openmw-0.35.1/apps/openmw/mwrender/creatureanimation.cpp --- openmw-0.35.0/apps/openmw/mwrender/creatureanimation.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/creatureanimation.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -88,6 +88,9 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot) { + if (!mSkelBase) + return; + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); MWWorld::ContainerStoreIterator it = inv.getSlot(slot); @@ -181,7 +184,9 @@ Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration) { Ogre::Vector3 ret = Animation::runAnimation(duration); - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); + + if (mSkelBase) + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); if (!mWeapon.isNull()) { diff -Nru openmw-0.35.0/apps/openmw/mwrender/globalmap.cpp openmw-0.35.1/apps/openmw/mwrender/globalmap.cpp --- openmw-0.35.0/apps/openmw/mwrender/globalmap.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/globalmap.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,6 +11,7 @@ #include #include +#include #include diff -Nru openmw-0.35.0/apps/openmw/mwrender/npcanimation.cpp openmw-0.35.1/apps/openmw/mwrender/npcanimation.cpp --- openmw-0.35.0/apps/openmw/mwrender/npcanimation.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/npcanimation.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -335,7 +335,10 @@ } void NpcAnimation::updateParts() -{ +{ + if (!mSkelBase) + return; + mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -621,30 +624,33 @@ } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) -{ +{ Ogre::Vector3 ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode == VM_FirstPerson) + if (mSkelBase) { - float pitch = mPtr.getRefData().getPosition().rot[0]; - Ogre::Node *node = baseinst->getBone("Bip01 Neck"); - node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); - - // This has to be done before this function ends; - // updateSkeletonInstance, below, touches the hands. - node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); - } - else - { - // In third person mode we may still need pitch for ranged weapon targeting - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - - Ogre::Node* node = baseinst->getBone("Bip01 Head"); - if (node) - node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + if(mViewMode == VM_FirstPerson) + { + float pitch = mPtr.getRefData().getPosition().rot[0]; + Ogre::Node *node = baseinst->getBone("Bip01 Neck"); + node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); + + // This has to be done before this function ends; + // updateSkeletonInstance, below, touches the hands. + node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); + } + else + { + // In third person mode we may still need pitch for ranged weapon targeting + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); + + Ogre::Node* node = baseinst->getBone("Bip01 Head"); + if (node) + node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + } } mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. @@ -659,7 +665,9 @@ if (!isSkinned(mObjectParts[i])) continue; - updateSkeletonInstance(baseinst, mObjectParts[i]->mSkelBase->getSkeleton()); + if (mSkelBase) + updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton()); + mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } diff -Nru openmw-0.35.0/apps/openmw/mwrender/renderingmanager.cpp openmw-0.35.1/apps/openmw/mwrender/renderingmanager.cpp --- openmw-0.35.0/apps/openmw/mwrender/renderingmanager.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/renderingmanager.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -120,14 +120,12 @@ // Set default texture filtering options TextureFilterOptions tfo; std::string filter = Settings::Manager::getString("texture filtering", "General"); -#ifndef ANDROID + if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; else /*if (filter == "none")*/ tfo = TFO_NONE; -#else - tfo = TFO_NONE; -#endif + MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); @@ -632,12 +630,12 @@ } } -void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_moon) +void RenderingManager::setSunDirection(const Ogre::Vector3& direction, bool is_night) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); - mSkyManager->setSunDirection(direction, is_moon); + mSkyManager->setSunDirection(direction, is_night); } void RenderingManager::setGlare(bool glare) diff -Nru openmw-0.35.0/apps/openmw/mwrender/renderingmanager.hpp openmw-0.35.1/apps/openmw/mwrender/renderingmanager.hpp --- openmw-0.35.0/apps/openmw/mwrender/renderingmanager.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/renderingmanager.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -141,7 +141,7 @@ void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) void sunDisable(bool real); diff -Nru openmw-0.35.0/apps/openmw/mwrender/ripplesimulation.cpp openmw-0.35.1/apps/openmw/mwrender/ripplesimulation.cpp --- openmw-0.35.0/apps/openmw/mwrender/ripplesimulation.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/ripplesimulation.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -113,7 +113,7 @@ position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(50,50); + created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); } } diff -Nru openmw-0.35.0/apps/openmw/mwrender/sky.cpp openmw-0.35.1/apps/openmw/mwrender/sky.cpp --- openmw-0.35.0/apps/openmw/mwrender/sky.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/sky.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -767,14 +767,14 @@ mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_moon) +void SkyManager::setSunDirection(const Vector3& direction, bool is_night) { if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_moon ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } diff -Nru openmw-0.35.0/apps/openmw/mwrender/sky.hpp openmw-0.35.1/apps/openmw/mwrender/sky.hpp --- openmw-0.35.0/apps/openmw/mwrender/sky.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwrender/sky.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -153,7 +153,7 @@ void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_moon); + void setSunDirection(const Ogre::Vector3& direction, bool is_night); void setMasserDirection(const Ogre::Vector3& direction); diff -Nru openmw-0.35.0/apps/openmw/mwscript/animationextensions.cpp openmw-0.35.1/apps/openmw/mwscript/animationextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/animationextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/animationextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -2,6 +2,7 @@ #include "animationextensions.hpp" #include +#include #include #include @@ -10,6 +11,7 @@ #include #include +#include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwscript/containerextensions.cpp openmw-0.35.1/apps/openmw/mwscript/containerextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/containerextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/containerextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -14,10 +14,13 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwscript/controlextensions.cpp openmw-0.35.1/apps/openmw/mwscript/controlextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/controlextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/controlextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwscript/dialogueextensions.cpp openmw-0.35.1/apps/openmw/mwscript/dialogueextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/dialogueextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/dialogueextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,6 +11,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwscript/docs/vmformat.txt openmw-0.35.1/apps/openmw/mwscript/docs/vmformat.txt --- openmw-0.35.0/apps/openmw/mwscript/docs/vmformat.txt 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/docs/vmformat.txt 2015-03-12 11:06:00.000000000 +0000 @@ -444,5 +444,6 @@ op 0x20002fe: RemoveFromLevItem op 0x20002ff: SetFactionReaction op 0x2000300: EnableLevelupMenu +op 0x2000301: ToggleScripts -opcodes 0x2000301-0x3ffffff unused +opcodes 0x2000302-0x3ffffff unused diff -Nru openmw-0.35.0/apps/openmw/mwscript/guiextensions.cpp openmw-0.35.1/apps/openmw/mwscript/guiextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/guiextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/guiextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -12,7 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" - +#include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwscript/interpretercontext.cpp openmw-0.35.1/apps/openmw/mwscript/interpretercontext.cpp --- openmw-0.35.0/apps/openmw/mwscript/interpretercontext.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/interpretercontext.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -270,15 +270,21 @@ std::string InterpreterContext::getActionBinding(const std::string& action) const { - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { - std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + std::string desc = input->getActionDescription (*it); if(desc == "") continue; if(desc == action) - return MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + { + if(input->joystickLastUsed()) + return input->getActionControllerBindingName(*it); + else + return input->getActionKeyBindingName (*it); + } } return "None"; diff -Nru openmw-0.35.0/apps/openmw/mwscript/miscextensions.cpp openmw-0.35.1/apps/openmw/mwscript/miscextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/miscextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/miscextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -17,6 +17,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -34,24 +35,24 @@ namespace { - void addToLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (it->mLevel == level && itemId == it->mId) return; } - ESM::LeveledListBase::LevelItem item; + ESM::LevelledListBase::LevelItem item; item.mId = itemId; item.mLevel = level; list->mList.push_back(item); } - void removeFromLevList(ESM::LeveledListBase* list, const std::string& itemId, int level) + void removeFromLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { // level of -1 removes all items with that itemId - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) { if (level != -1 && it->mLevel != level) { @@ -914,6 +915,19 @@ } }; + class OpToggleScripts : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = static_cast (runtime.getContext()); + + bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); + + context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + } + }; + class OpToggleGodMode : public Interpreter::Opcode0 { public: @@ -1007,8 +1021,7 @@ virtual void execute (Interpreter::Runtime &runtime) { - /// \todo implement jail check - runtime.push (0); + runtime.push (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail)); } }; @@ -1220,6 +1233,7 @@ interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeShowVarsExplicit, new OpShowVars); interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); + interpreter.installSegment5 (Compiler::Misc::opcodeToggleScripts, new OpToggleScripts); interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeCast, new OpCast); diff -Nru openmw-0.35.0/apps/openmw/mwscript/ref.cpp openmw-0.35.1/apps/openmw/mwscript/ref.cpp --- openmw-0.35.0/apps/openmw/mwscript/ref.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/ref.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,29 @@ +#include "ref.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "interpretercontext.hpp" + +MWWorld::Ptr MWScript::ExplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + std::string id = runtime.getStringLiteral(runtime[0].mInteger); + runtime.pop(); + + if (required) + return MWBase::Environment::get().getWorld()->getPtr(id, activeOnly); + else + return MWBase::Environment::get().getWorld()->searchPtr(id, activeOnly); +} + +MWWorld::Ptr MWScript::ImplicitRef::operator() (Interpreter::Runtime& runtime, bool required, + bool activeOnly) const +{ + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + return context.getReference(required); +} diff -Nru openmw-0.35.0/apps/openmw/mwscript/ref.hpp openmw-0.35.1/apps/openmw/mwscript/ref.hpp --- openmw-0.35.0/apps/openmw/mwscript/ref.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/ref.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -3,14 +3,12 @@ #include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - #include "../mwworld/ptr.hpp" -#include "interpretercontext.hpp" +namespace Interpreter +{ + class Runtime; +} namespace MWScript { @@ -18,31 +16,16 @@ { static const bool implicit = false; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - std::string id = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - if (required) - return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly); - else - return MWBase::Environment::get().getWorld()->searchPtr (id, activeOnly); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; struct ImplicitRef { static const bool implicit = true; - MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required=true, - bool activeOnly = false) const - { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - - return context.getReference(required); - } + MWWorld::Ptr operator() (Interpreter::Runtime& runtime, bool required = true, + bool activeOnly = false) const; }; } diff -Nru openmw-0.35.0/apps/openmw/mwscript/statsextensions.cpp openmw-0.35.1/apps/openmw/mwscript/statsextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/statsextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/statsextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -18,6 +18,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -348,29 +349,12 @@ MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr); - MWWorld::LiveCellRef *ref = ptr.get(); - - assert (ref); - - const ESM::Class& class_ = - *MWBase::Environment::get().getWorld()->getStore().get().find (ref->mBase->mClass); - - float level = stats.getSkill(mIndex).getBase(); - float progress = stats.getSkill(mIndex).getProgress(); - int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase()); if (newLevel<0) newLevel = 0; - progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) - * stats.getSkillGain (mIndex, class_, -1, newLevel); - - if (progress>=1) - progress = 0.999999999; - stats.getSkill (mIndex).setBase (newLevel); - stats.getSkill (mIndex).setProgress(progress); } }; diff -Nru openmw-0.35.0/apps/openmw/mwscript/transformationextensions.cpp openmw-0.35.1/apps/openmw/mwscript/transformationextensions.cpp --- openmw-0.35.0/apps/openmw/mwscript/transformationextensions.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwscript/transformationextensions.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,7 +10,9 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" @@ -308,12 +310,14 @@ } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + runtime.getContext().report ("unknown cell (" + cellID + ")"); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -333,10 +337,6 @@ ptr.getClass().adjustPosition(ptr, false); } - else - { - throw std::runtime_error (std::string("unknown cell (") + cellID + ")"); - } } }; @@ -424,11 +424,13 @@ catch(std::exception&) { const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + runtime.getContext().report ("unknown cell (" + cellID + ")"); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -444,10 +446,6 @@ MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); placed.getClass().adjustPosition(placed, true); } - else - { - throw std::runtime_error ( std::string("unknown cell (") + cellID + ")"); - } } }; @@ -691,10 +689,10 @@ if (!ptr.getRefData().getBaseNode()) return; - Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); - - dynamic_cast(runtime.getContext()).updatePtr( - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); + Ogre::Vector3 diff = ptr.getRefData().getBaseNode()->getOrientation() * posChange; + Ogre::Vector3 worldPos(ptr.getRefData().getPosition().pos); + worldPos += diff; + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); } }; diff -Nru openmw-0.35.0/apps/openmw/mwstate/statemanagerimp.cpp openmw-0.35.1/apps/openmw/mwstate/statemanagerimp.cpp --- openmw-0.35.0/apps/openmw/mwstate/statemanagerimp.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwstate/statemanagerimp.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -13,6 +13,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -420,6 +421,7 @@ break; case ESM::REC_DCOU: + case ESM::REC_STLN: MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.val); break; diff -Nru openmw-0.35.0/apps/openmw/mwworld/actiontake.cpp openmw-0.35.1/apps/openmw/mwworld/actiontake.cpp --- openmw-0.35.0/apps/openmw/mwworld/actiontake.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/actiontake.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -16,7 +16,7 @@ void ActionTake::executeImp (const Ptr& actor) { MWBase::Environment::get().getMechanicsManager()->itemTaken( - actor, getTarget(), getTarget().getRefData().getCount()); + actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); } diff -Nru openmw-0.35.0/apps/openmw/mwworld/actiontrap.cpp openmw-0.35.1/apps/openmw/mwworld/actiontrap.cpp --- openmw-0.35.0/apps/openmw/mwworld/actiontrap.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/actiontrap.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,16 +1,39 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { void ActionTrap::executeImp(const Ptr &actor) { - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); - cast.cast(mSpellId); + Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); + Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + // GUI calcs if object in activation distance include object and player geometry + const float fudgeFactor = 1.25f; + + // Hack: if actor is beyond activation range, then assume actor is using telekinesis + // to open door/container. + // Note, can't just detonate the trap at the trapped object's location and use the blast + // radius, because for most trap spells this is 1 foot, much less than the activation distance. + if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + { + // assume actor touched trap + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + } + else + { + // assume telekinesis used + MWMechanics::CastSpell cast(mTrapSource, mTrapSource); + cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } mTrapSource.getCellRef().setTrap(""); } diff -Nru openmw-0.35.0/apps/openmw/mwworld/cellref.cpp openmw-0.35.1/apps/openmw/mwworld/cellref.cpp --- openmw-0.35.0/apps/openmw/mwworld/cellref.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/cellref.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -117,6 +117,15 @@ return mCellRef.mGlobalVariable; } + void CellRef::resetGlobalVariable() + { + if (!mCellRef.mGlobalVariable.empty()) + { + mChanged = true; + mCellRef.mGlobalVariable.erase(); + } + } + void CellRef::setFactionRank(int factionRank) { if (factionRank != mCellRef.mFactionRank) diff -Nru openmw-0.35.0/apps/openmw/mwworld/cellref.hpp openmw-0.35.1/apps/openmw/mwworld/cellref.hpp --- openmw-0.35.0/apps/openmw/mwworld/cellref.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/cellref.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -75,6 +75,8 @@ // Used by bed rent scripts to allow the player to use the bed for the duration of the rent. std::string getGlobalVariable() const; + void resetGlobalVariable(); + // ID of creature trapped in this soul gem std::string getSoul() const; void setSoul(const std::string& soul); diff -Nru openmw-0.35.0/apps/openmw/mwworld/cellstore.cpp openmw-0.35.1/apps/openmw/mwworld/cellstore.cpp --- openmw-0.35.0/apps/openmw/mwworld/cellstore.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/cellstore.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -407,8 +407,6 @@ if (mState==State_Preloaded) mIds.clear(); - std::cout << "loading cell " << mCell->getDescription() << std::endl; - loadRefs (store, esm); mState = State_Loaded; diff -Nru openmw-0.35.0/apps/openmw/mwworld/cellstore.hpp openmw-0.35.1/apps/openmw/mwworld/cellstore.hpp --- openmw-0.35.0/apps/openmw/mwworld/cellstore.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/cellstore.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "livecellref.hpp" @@ -181,7 +183,12 @@ template CellRefList& get() { - throw std::runtime_error ("Storage for this type not exist in cells"); + throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); + } + + template + const CellRefList& getReadOnly() { + throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } bool isPointConnected(const int start, const int end) const; @@ -357,6 +364,12 @@ return mWeapons; } + template<> + inline const CellRefList& CellStore::getReadOnly() + { + return mDoors; + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff -Nru openmw-0.35.0/apps/openmw/mwworld/class.cpp openmw-0.35.1/apps/openmw/mwworld/class.cpp --- openmw-0.35.0/apps/openmw/mwworld/class.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/class.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -454,4 +454,9 @@ { return -1; } + + int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const + { + throw std::runtime_error("class does not support armor ratings"); + } } diff -Nru openmw-0.35.0/apps/openmw/mwworld/class.hpp openmw-0.35.1/apps/openmw/mwworld/class.hpp --- openmw-0.35.0/apps/openmw/mwworld/class.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/class.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -80,6 +80,8 @@ virtual std::string getId (const Ptr& ptr) const; ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + /// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId. + /// Leaving it here for now in case we want to optimize later. virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const; @@ -345,6 +347,9 @@ virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } diff -Nru openmw-0.35.0/apps/openmw/mwworld/containerstore.cpp openmw-0.35.1/apps/openmw/mwworld/containerstore.cpp --- openmw-0.35.0/apps/openmw/mwworld/containerstore.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/containerstore.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -222,29 +222,22 @@ MWWorld::ContainerStoreIterator it = end(); - if (setOwner && actorPtr.getClass().isActor()) + // HACK: Set owner on the original item, then reset it after we have copied it + // If we set the owner on the copied item, it would not stack correctly... + std::string oldOwner = itemPtr.getCellRef().getOwner(); + if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway { - // HACK: Set owner on the original item, then reset it after we have copied it - // If we set the owner on the copied item, it would not stack correctly... - std::string oldOwner = itemPtr.getCellRef().getOwner(); - if (actorPtr == player) - { - // No point in setting owner to the player - NPCs will not respect this anyway - // Additionally, setting it to "player" would make those items not stack with items that don't have an owner - itemPtr.getCellRef().setOwner(""); - } - else - itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); - - it = addImp(itemPtr, count); - - itemPtr.getCellRef().setOwner(oldOwner); + itemPtr.getCellRef().setOwner(""); } else { - it = addImp(itemPtr, count); + itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId()); } + it = addImp(itemPtr, count); + + itemPtr.getCellRef().setOwner(oldOwner); + // The copy of the original item we just made MWWorld::Ptr item = *it; @@ -258,6 +251,14 @@ pos.pos[1] = 0; pos.pos[2] = 0; item.getCellRef().setPosition(pos); + + // reset ownership stuff, owner was already handled above + item.getCellRef().resetGlobalVariable(); + item.getCellRef().setFaction(""); + item.getCellRef().setFactionRank(-1); + + // must reset the RefNum on the copied item, so that the RefNum on the original item stays unique + // maybe we should do this in the copy constructor instead? item.getCellRef().unsetRefNum(); // destroy link to content file std::string script = item.getClass().getScript(item); @@ -399,19 +400,19 @@ return count - toRemove; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString()); - addInitialItem(id, owner, faction, factionRank, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel, const std::string& levItem) { ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); @@ -423,7 +424,7 @@ if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i 0 ? 1 : -1, true, levItem->mId); + addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId); return; } else @@ -431,7 +432,7 @@ std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); if (id.empty()) return; - addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId); + addInitialItem(id, owner, count, false, levItem->mId); } } else @@ -447,13 +448,11 @@ count = std::abs(count); ref.getPtr().getCellRef().setOwner(owner); - ref.getPtr().getCellRef().setFaction(faction); - ref.getPtr().getCellRef().setFactionRank(factionRank); addImp (ref.getPtr(), count); } } -void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank) +void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner) { // Remove the items already spawned by levelled items that will restock for (std::map::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it) @@ -472,13 +471,13 @@ if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mItem.toString())) { - addInitialItem(item, owner, faction, factionRank, it->mCount, true); + addInitialItem(item, owner, it->mCount, true); } else { int currentCount = count(item); if (currentCount < std::abs(it->mCount)) - addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true); + addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true); } } flagAsModified(); diff -Nru openmw-0.35.0/apps/openmw/mwworld/containerstore.hpp openmw-0.35.1/apps/openmw/mwworld/containerstore.hpp --- openmw-0.35.0/apps/openmw/mwworld/containerstore.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/containerstore.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -75,7 +75,7 @@ mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr, int count); - void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = ""); + void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = ""); template ContainerStoreIterator getState (CellRefList& collection, @@ -112,7 +112,7 @@ /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! /// - /// @param setOwner Set the owner of the added item to \a actorPtr? + /// @param setOwner Set the owner of the added item to \a actorPtr? If false, the owner is reset to "". /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. @@ -151,10 +151,10 @@ virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); ///< @return true if the two specified objects can stack with each other - void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store); + void fill (const ESM::InventoryList& items, const std::string& owner); ///< Insert items into *this. - void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank); + void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner); virtual void clear(); ///< Empty container. diff -Nru openmw-0.35.0/apps/openmw/mwworld/inventorystore.cpp openmw-0.35.1/apps/openmw/mwworld/inventorystore.cpp --- openmw-0.35.0/apps/openmw/mwworld/inventorystore.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/inventorystore.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -133,12 +133,11 @@ const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if ((actorPtr.getRefData().getHandle() != "player") - && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()) - && !actorPtr.getClass().getCreatureStats(actorPtr).isDead()) + if (actorPtr.getRefData().getHandle() != "player" + && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); - if ((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name()) || (type == typeid(ESM::Weapon).name())) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actorPtr); } @@ -234,7 +233,9 @@ // ...unless this is a companion, he should always equip items given to him. if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))) + !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired + ) { continue; } @@ -506,8 +507,7 @@ && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); - if (((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name())) - && !actor.getClass().getCreatureStats(actor).isDead()) + if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actor); } diff -Nru openmw-0.35.0/apps/openmw/mwworld/livecellref.cpp openmw-0.35.1/apps/openmw/mwworld/livecellref.cpp --- openmw-0.35.0/apps/openmw/mwworld/livecellref.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/livecellref.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,6 +1,7 @@ - #include "livecellref.hpp" +#include + #include #include "../mwbase/environment.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwworld/manualref.cpp openmw-0.35.1/apps/openmw/mwworld/manualref.cpp --- openmw-0.35.0/apps/openmw/mwworld/manualref.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/manualref.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,67 @@ +#include "manualref.hpp" + +#include "esmstore.hpp" +#include "cellstore.hpp" + +namespace +{ + + template + void create(const MWWorld::Store& list, const std::string& name, boost::any& refValue, MWWorld::Ptr& ptrValue) + { + const T* base = list.find(name); + + ESM::CellRef cellRef; + cellRef.mRefNum.unset(); + cellRef.mRefID = name; + cellRef.mScale = 1; + cellRef.mFactionRank = 0; + cellRef.mChargeInt = -1; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; + cellRef.mTeleport = false; + cellRef.mLockLevel = 0; + cellRef.mReferenceBlocked = 0; + + MWWorld::LiveCellRef ref(cellRef, base); + + refValue = ref; + ptrValue = MWWorld::Ptr(&boost::any_cast&>(refValue), 0); + } +} + +MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count) +{ + std::string lowerName = Misc::StringUtils::lowerCase(name); + switch (store.find(lowerName)) + { + case ESM::REC_ACTI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ALCH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_APPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_ARMO: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_BOOK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CLOT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CONT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_CREA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_DOOR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_INGR: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LEVI: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LIGH: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_LOCK: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_MISC: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_NPC_: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_PROB: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_REPA: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_STAT: create(store.get(), lowerName, mRef, mPtr); break; + case ESM::REC_WEAP: create(store.get(), lowerName, mRef, mPtr); break; + + case 0: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown ID)"); + + default: + throw std::logic_error("failed to create manual cell ref for " + lowerName + " (unknown type)"); + } + + mPtr.getRefData().setCount(count); +} \ No newline at end of file diff -Nru openmw-0.35.0/apps/openmw/mwworld/manualref.hpp openmw-0.35.1/apps/openmw/mwworld/manualref.hpp --- openmw-0.35.0/apps/openmw/mwworld/manualref.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/manualref.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -3,9 +3,7 @@ #include -#include "esmstore.hpp" #include "ptr.hpp" -#include "cellstore.hpp" namespace MWWorld { @@ -18,66 +16,8 @@ ManualRef (const ManualRef&); ManualRef& operator= (const ManualRef&); - template - void create (const MWWorld::Store& list, const std::string& name) - { - const T* base = list.find(name); - - ESM::CellRef cellRef; - cellRef.mRefNum.unset(); - cellRef.mRefID = name; - cellRef.mScale = 1; - cellRef.mFactionRank = 0; - cellRef.mChargeInt = -1; - cellRef.mGoldValue = 1; - cellRef.mEnchantmentCharge = -1; - cellRef.mTeleport = false; - cellRef.mLockLevel = 0; - cellRef.mReferenceBlocked = 0; - - LiveCellRef ref(cellRef, base); - - mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); - } - public: - - ManualRef (const MWWorld::ESMStore& store, const std::string& name, const int count=1) - { - std::string lowerName = Misc::StringUtils::lowerCase (name); - switch (store.find (lowerName)) - { - case ESM::REC_ACTI: create (store.get(), lowerName); break; - case ESM::REC_ALCH: create (store.get(), lowerName); break; - case ESM::REC_APPA: create (store.get(), lowerName); break; - case ESM::REC_ARMO: create (store.get(), lowerName); break; - case ESM::REC_BOOK: create (store.get(), lowerName); break; - case ESM::REC_CLOT: create (store.get(), lowerName); break; - case ESM::REC_CONT: create (store.get(), lowerName); break; - case ESM::REC_CREA: create (store.get(), lowerName); break; - case ESM::REC_DOOR: create (store.get(), lowerName); break; - case ESM::REC_INGR: create (store.get(), lowerName); break; - case ESM::REC_LEVC: create (store.get(), lowerName); break; - case ESM::REC_LEVI: create (store.get(), lowerName); break; - case ESM::REC_LIGH: create (store.get(), lowerName); break; - case ESM::REC_LOCK: create (store.get(), lowerName); break; - case ESM::REC_MISC: create (store.get(), lowerName); break; - case ESM::REC_NPC_: create (store.get(), lowerName); break; - case ESM::REC_PROB: create (store.get(), lowerName); break; - case ESM::REC_REPA: create (store.get(), lowerName); break; - case ESM::REC_STAT: create (store.get(), lowerName); break; - case ESM::REC_WEAP: create (store.get(), lowerName); break; - - case 0: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown ID)"); - - default: - throw std::logic_error ("failed to create manual cell ref for " + lowerName + " (unknown type)"); - } - - mPtr.getRefData().setCount(count); - } + ManualRef(const MWWorld::ESMStore& store, const std::string& name, const int count = 1); const Ptr& getPtr() const { diff -Nru openmw-0.35.0/apps/openmw/mwworld/player.cpp openmw-0.35.1/apps/openmw/mwworld/player.cpp --- openmw-0.35.0/apps/openmw/mwworld/player.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/player.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -260,9 +260,20 @@ mCellStore = world.getExterior(0,0); } - if (!player.mBirthsign.empty() && - !world.getStore().get().search (player.mBirthsign)) - throw std::runtime_error ("invalid player state record (birthsign)"); + if (!player.mBirthsign.empty()) + { + const ESM::BirthSign* sign = world.getStore().get().search (player.mBirthsign); + if (!sign) + throw std::runtime_error ("invalid player state record (birthsign does not exist)"); + + // To handle the case where a birth sign was edited in between play sessions (does not yet handle removing the old spells) + // Also needed for ess-imported savegames which do not specify the birtsign spells in the player's spell list. + for (std::vector::const_iterator iter (sign->mPowers.mList.begin()); + iter!=sign->mPowers.mList.end(); ++iter) + { + getPlayer().getClass().getCreatureStats(getPlayer()).getSpells().add (*iter); + } + } mCurrentCrimeId = player.mCurrentCrimeId; mPaidCrimeId = player.mPaidCrimeId; diff -Nru openmw-0.35.0/apps/openmw/mwworld/projectilemanager.cpp openmw-0.35.1/apps/openmw/mwworld/projectilemanager.cpp --- openmw-0.35.0/apps/openmw/mwworld/projectilemanager.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/projectilemanager.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -9,6 +9,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwbase/soundmanager.hpp" diff -Nru openmw-0.35.0/apps/openmw/mwworld/refdata.hpp openmw-0.35.1/apps/openmw/mwworld/refdata.hpp --- openmw-0.35.0/apps/openmw/mwworld/refdata.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/refdata.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -33,11 +33,11 @@ MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, // we can make this a pointer later. + bool mDeleted; // separate delete flag used for deletion by a content file bool mHasLocals; bool mEnabled; int mCount; // 0: deleted - bool mDeleted; // separate delete flag used for deletion by a content file ESM::Position mPosition; diff -Nru openmw-0.35.0/apps/openmw/mwworld/scene.cpp openmw-0.35.1/apps/openmw/mwworld/scene.cpp --- openmw-0.35.0/apps/openmw/mwworld/scene.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/scene.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -199,7 +199,7 @@ (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - if (land) + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } @@ -219,6 +219,8 @@ if(result.second) { + std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; @@ -230,7 +232,7 @@ cell->getCell()->getGridX(), cell->getCell()->getGridY() ); - if (land) { + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) { // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; @@ -490,8 +492,6 @@ loadingListener->setProgressRange(refsToLoad); // Load cell. - std::cout << "cellName: " << cell->getCell()->mName << std::endl; - loadCell (cell, loadingListener); changePlayerCell(cell, position, true); diff -Nru openmw-0.35.0/apps/openmw/mwworld/store.hpp openmw-0.35.1/apps/openmw/mwworld/store.hpp --- openmw-0.35.0/apps/openmw/mwworld/store.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/store.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -555,6 +555,9 @@ if (left.first == right.first) return left.second > right.second; + // Exterior cells are listed in descending, row-major order, + // this is a workaround for an ambiguous chargen_plank reference in the vanilla game. + // there is one at -22,16 and one at -2,-9, the latter should be used. return left.first > right.first; } }; diff -Nru openmw-0.35.0/apps/openmw/mwworld/weather.cpp openmw-0.35.1/apps/openmw/mwworld/weather.cpp --- openmw-0.35.0/apps/openmw/mwworld/weather.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/weather.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,6 @@ +#define _USE_MATH_DEFINES +#include + #include "weather.hpp" #include @@ -427,29 +430,35 @@ else mRendering->getSkyManager()->sunEnable(); - // sun angle - float height; - - //Day duration - float dayDuration = (mNightStart - 1) - mSunriseTime; + // Update the sun direction. Run it east to west at a fixed angle from overhead. + // The sun's speed at day and night may differ, since mSunriseTime and mNightStart + // mark when the sun is level with the horizon. + { + // Shift times into a 24-hour window beginning at mSunriseTime... + float adjustedHour = mHour; + float adjustedNightStart = mNightStart; + if ( mHour < mSunriseTime ) + adjustedHour += 24.f; + if ( mNightStart < mSunriseTime ) + adjustedNightStart += 24.f; + + const bool is_night = adjustedHour >= adjustedNightStart; + const float dayDuration = adjustedNightStart - mSunriseTime; + const float nightDuration = 24.f - dayDuration; + + double theta; + if ( !is_night ) { + theta = M_PI * (adjustedHour - mSunriseTime) / dayDuration; + } else { + theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; + } - // rise at 6, set at 20 - if (mHour >= mSunriseTime && mHour <= mNightStart) - height = 1 - std::abs(((mHour - dayDuration) / 7.f)); - else if (mHour > mNightStart) - height = (mHour - mNightStart) / 4.f; - else //if (mHour > 0 && mHour < 6) - height = 1 - (mHour / mSunriseTime); - - int facing = (mHour > 13.f) ? 1 : -1; - - bool sun_is_moon = mHour >= mNightStart || mHour <= mSunriseTime; - - Vector3 final( - (height - 1) * facing, - (height - 1) * facing, - height); - mRendering->setSunDirection(final, sun_is_moon); + Vector3 final( + cos( theta ), + -0.268f, // approx tan( -15 degrees ) + sin( theta ) ); + mRendering->setSunDirection( final, is_night ); + } /* * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish diff -Nru openmw-0.35.0/apps/openmw/mwworld/worldimp.cpp openmw-0.35.1/apps/openmw/mwworld/worldimp.cpp --- openmw-0.35.0/apps/openmw/mwworld/worldimp.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/worldimp.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -44,6 +44,7 @@ #include "player.hpp" #include "manualref.hpp" +#include "cellstore.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" @@ -150,7 +151,8 @@ mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), mGodMode(false), mContentFiles (contentFiles), mGoToJail(false), mDaysInPrison(0), - mStartCell (startCell), mStartupScript(startupScript) + mStartCell (startCell), mStartupScript(startupScript), + mScriptsEnabled(true) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -292,6 +294,7 @@ mDoorStates.clear(); mGodMode = false; + mScriptsEnabled = true; mSky = true; mTeleportEnabled = true; mLevitationEnabled = true; @@ -420,6 +423,19 @@ globals["werewolfclawmult"] = ESM::Variant(25.f); globals["pcknownwerewolf"] = ESM::Variant(0); + // following should exist in all versions of MW, but not necessarily in TCs + globals["gamehour"] = ESM::Variant(0.f); + globals["timescale"] = ESM::Variant(30.f); + globals["day"] = ESM::Variant(1); + globals["month"] = ESM::Variant(1); + globals["year"] = ESM::Variant(1); + globals["pcrace"] = ESM::Variant(0); + globals["pchascrimegold"] = ESM::Variant(0); + globals["pchasgolddiscount"] = ESM::Variant(0); + globals["crimegolddiscount"] = ESM::Variant(0); + globals["crimegoldturnin"] = ESM::Variant(0); + globals["pchasturnin"] = ESM::Variant(0); + for (std::map::iterator it = gmst.begin(); it != gmst.end(); ++it) { if (!mStore.get().search(it->first)) @@ -2383,6 +2399,7 @@ bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) { typedef MWWorld::CellRefList::List DoorList; + typedef MWWorld::CellRefList::List StaticList; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; @@ -2427,6 +2444,13 @@ } } } + // Fall back to the first static location. + const StaticList &statics = cellStore->get().mList; + if ( statics.begin() != statics.end() ) { + pos = statics.begin()->mRef.getPosition(); + return true; + } + return false; } @@ -2578,6 +2602,17 @@ return mGodMode; } + bool World::toggleScripts() + { + mScriptsEnabled = !mScriptsEnabled; + return mScriptsEnabled; + } + + bool World::getScriptsEnabled() const + { + return mScriptsEnabled; + } + void World::loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader) { @@ -2762,18 +2797,45 @@ { if (cell->isExterior()) return false; - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) - { - ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); - return true; + // Search for a 'nearest' exterior, counting each cell between the starting + // cell and the exterior as a distance of 1. Will fail for isolated interiors. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( cell->getCell()->mName ); + + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + if ( !next ) continue; + + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::const_iterator it = refList.begin(); it != refList.end(); ++it) + { + const MWWorld::LiveCellRef& ref = *it; + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + ESM::Position pos = ref.mRef.getDoorDest(); + result = Ogre::Vector3(pos.pos); + return true; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + + checkedCells.insert( *i ); } } @@ -2781,33 +2843,102 @@ return false; } - void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, - const std::string& id) + MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { - Ogre::Vector3 worldPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos)) - worldPos = mPlayer->getLastKnownExteriorPosition(); + if ( ptr.getCell()->isExterior() ) { + return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); + } + // Search for a 'nearest' marker, counting each cell between the starting + // cell and the exterior as a distance of 1. If an exterior is found, jump + // to the nearest exterior marker, without further interior searching. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + MWWorld::Ptr closestMarker; + + nextCells.insert( ptr.getCell()->getCell()->mName ); + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + checkedCells.insert( *i ); + if ( !next ) continue; + + closestMarker = next->search( id ); + if ( !closestMarker.isEmpty() ) + { + return closestMarker; + } + + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& doorList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::const_iterator it = doorList.begin(); it != doorList.end(); ++it) + { + const MWWorld::LiveCellRef& ref = *it; + + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + return getClosestMarkerFromExteriorPosition(worldPos, id); + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + } + } + + return MWWorld::Ptr(); + } + + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; float closestDistance = FLT_MAX; std::vector markers; mCells.getExteriorPtrs(id, markers); - - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) { - ESM::Position pos = it->getRefData().getPosition(); + ESM::Position pos = it2->getRefData().getPosition(); Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); float distance = worldPos.squaredDistance(markerPos); if (distance < closestDistance) { closestDistance = distance; - closestMarker = *it; + closestMarker = *it2; } } - MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition()); + return closestMarker; + } + + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id) + { + MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); + + if ( closestMarker.isEmpty() ) + { + std::cerr << "Failed to teleport: no closest marker found" << std::endl; + return; + } + + std::string cellName; + if ( !closestMarker.mCell->isExterior() ) + cellName = closestMarker.mCell->getCell()->mName; + + MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition()); action.execute(ptr); } @@ -2877,6 +3008,9 @@ } else if (ptr.getClass().getTypeName() != typeid(ESM::Creature).name()) return false; + + if (ptr.getClass().getCreatureStats(ptr).isDead()) + return false; } if (mType == World::Detect_Key && !ptr.getClass().isKey(ptr)) return false; @@ -2953,45 +3087,32 @@ void World::confiscateStolenItems(const Ptr &ptr) { - Ogre::Vector3 playerPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos)) - playerPos = mPlayer->getLastKnownExteriorPosition(); - - MWWorld::Ptr closestChest; - float closestDistance = FLT_MAX; - - //Find closest stolen_goods chest - std::vector chests; - mCells.getInteriorPtrs("stolen_goods", chests); - - Ogre::Vector3 chestPos; - for (std::vector::iterator it = chests.begin(); it != chests.end(); ++it) + MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + if ( prisonMarker.isEmpty() ) { - if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos)) - continue; - - float distance = playerPos.squaredDistance(chestPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestChest = *it; - } + std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; + return; + } + std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + if ( prisonName.empty() ) + { + std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; + return; + } + MWWorld::CellStore *prison = getInterior( prisonName ); + if ( !prison ) + { + std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl; + return; } + MWWorld::Ptr closestChest = prison->search( "stolen_goods" ); if (!closestChest.isEmpty()) //Found a close chest { - ContainerStore& store = ptr.getClass().getContainerStore(ptr); - for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest - { - MWWorld::Ptr dummy; - if (!MWBase::Environment::get().getMechanicsManager()->isAllowedToUse(getPlayerPtr(), *it, dummy)) - { - closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest); - store.remove(*it, it->getRefData().getCount(), ptr); - } - } - closestChest.getClass().lock(closestChest,50); + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); } + else + std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl; } void World::goToJail() @@ -3019,59 +3140,7 @@ MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - MWWorld::Ptr player = getPlayerPtr(); - teleportToClosestMarker(player, "prisonmarker"); - - int days = mDaysInPrison; - advanceTime(days * 24); - for (int i=0; irest (true); - - std::set skills; - for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; - skills.insert(skill); - - MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); - if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) - value.setBase(std::min(100, value.getBase()+1)); - else - value.setBase(value.getBase()-1); - } - - const Store& gmst = getStore().get(); - - std::string message; - if (days == 1) - message = gmst.find("sNotifyMessage42")->getString(); - else - message = gmst.find("sNotifyMessage43")->getString(); - - std::stringstream dayStr; - dayStr << days; - if (message.find("%d") != std::string::npos) - message.replace(message.find("%d"), 2, dayStr.str()); - - for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) - { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString(); - std::stringstream skillValue; - skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); - std::string skillMsg = gmst.find("sNotifyMessage44")->getString(); - if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security) - skillMsg = gmst.find("sNotifyMessage39")->getString(); - - if (skillMsg.find("%s") != std::string::npos) - skillMsg.replace(skillMsg.find("%s"), 2, skillName); - if (skillMsg.find("%d") != std::string::npos) - skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); - message += "\n" + skillMsg; - } - - std::vector buttons; - buttons.push_back("#{sOk}"); - MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); + MWBase::Environment::get().getWindowManager()->goToJail(mDaysInPrison); } } @@ -3143,7 +3212,7 @@ mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3202,7 +3271,7 @@ cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); + cast.inflict(apply->first, caster, effects, rangeType, false, true); } } @@ -3215,12 +3284,17 @@ breakInvisibility(actor); - if (!script.empty()) + if (mScriptsEnabled) { - getLocalScripts().setIgnore (object); - MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + if (!script.empty()) + { + getLocalScripts().setIgnore (object); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + if (!interpreterContext.hasActivationBeenHandled()) + interpreterContext.executeActivation(object, actor); } - if (!interpreterContext.hasActivationBeenHandled()) + else interpreterContext.executeActivation(object, actor); } diff -Nru openmw-0.35.0/apps/openmw/mwworld/worldimp.hpp openmw-0.35.1/apps/openmw/mwworld/worldimp.hpp --- openmw-0.35.0/apps/openmw/mwworld/worldimp.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/apps/openmw/mwworld/worldimp.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -82,6 +82,7 @@ boost::shared_ptr mProjectileManager; bool mGodMode; + bool mScriptsEnabled; std::vector mContentFiles; // not implemented @@ -114,7 +115,6 @@ void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getMaxActivationDistance (); float getNpcActivationDistance (); float getObjectActivationDistance (); @@ -150,6 +150,9 @@ float feetToGameUnits(float feet); + MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); + public: World (OEngine::Render::OgreRenderer& renderer, @@ -362,6 +365,8 @@ virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + virtual float getMaxActivationDistance(); + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; ///< Convert cell numbers to position. @@ -572,6 +577,9 @@ virtual bool toggleGodMode(); + virtual bool toggleScripts(); + virtual bool getScriptsEnabled() const; + /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor @@ -629,7 +637,7 @@ virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); diff -Nru openmw-0.35.0/AUTHORS.md openmw-0.35.1/AUTHORS.md --- openmw-0.35.0/AUTHORS.md 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/AUTHORS.md 2015-03-12 11:06:00.000000000 +0000 @@ -33,12 +33,13 @@ Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) dreamer-dead - dteviot + David Teviotdale (dteviot) Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 Emanuel Guével (potatoesmaster) eroen + Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej gugus/gus @@ -78,18 +79,19 @@ naclander Narmo Nathan Jeffords (blunted2night) + NeveHanter Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) Radu-Marius Popovici (rpopovici) + rdimesio riothamus Robert MacGregor (Ragora) Rohit Nirmal Roman Melnik (Kromgart) Roman Proskuryakov (humbug) - sandstranger Sandy Carter (bwrsandman) Scott Howard Sebastian Wick (swick) diff -Nru openmw-0.35.0/CHANGELOG.md openmw-0.35.1/CHANGELOG.md --- openmw-0.35.0/CHANGELOG.md 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/CHANGELOG.md 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,42 @@ +0.35.1 +------ + + Bug #781: incorrect trajectory of the sun + Bug #1079: Wrong starting position in "Character Stuff Wonderland" + Bug #1443: Repetitive taking of a stolen object is repetitively considered as a crime + Bug #1533: Divine Intervention goes to the wrong place. + Bug #1714: No visual indicator for time passed during training + Bug #1916: Telekinesis does not allow safe opening of traps + Bug #2227: Editor: addon file name inconsistency + Bug #2271: Player can melee enemies from water with impunity + Bug #2275: Objects with bigger scale move further using Move script + Bug #2285: Aryon's Dominator enchantment does not work properly + Bug #2290: No punishment for stealing gold from owned containers + Bug #2328: Launcher does not respond to Ctrl+C + Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items + Bug #2338: Arrows reclaimed from corpses do not stack sometimes + Bug #2344: Launcher - Settings importer running correctly? + Bug #2346: Launcher - Importing plugins into content list screws up the load order + Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list + Bug #2353: Detect Animal detects dead creatures + Bug #2354: Cmake does not respect LIB_SUFFIX + Bug #2356: Active magic set inactive when switching magic items + Bug #2361: ERROR: ESM Error: Previous record contains unread bytes + Bug #2382: Switching spells with "next spell" or "previous spell" while holding shift promps delete spell dialog + Bug #2388: Regression: Can't toggle map on/off + Bug #2392: MOD Shrines - Restore Health and Cancel Options adds 100 health points + Bug #2394: List of Data Files tab in openmw-laucher needs to show all content files. + Bug #2402: Editor: skills saved incorrectly + Bug #2408: Equipping a constant effect Restore Health/Magicka/Fatigue item will permanently boost the stat it's restoring + Bug #2415: It is now possible to fall off the prison ship into the water when starting a new game + Bug #2419: MOD MCA crash to desktop + Bug #2420: Game crashes when character enters a certain area + Bug #2421: infinite loop when using cycle weapon without having a weapon + Feature #2221: Cannot dress dead NPCs + Feature #2349: Check CMake sets correct MSVC compiler settings for release build. + Feature #2397: Set default values for global mandatory records. + Feature #2412: Basic joystick support + 0.35.0 ------ diff -Nru openmw-0.35.0/CI/before_install.osx.sh openmw-0.35.1/CI/before_install.osx.sh --- openmw-0.35.0/CI/before_install.osx.sh 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/CI/before_install.osx.sh 2015-03-12 11:06:00.000000000 +0000 @@ -6,4 +6,4 @@ brew tap openmw/openmw brew update brew unlink boost -brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield +brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg openmw/openmw/qt unshield diff -Nru openmw-0.35.0/CMakeLists.txt openmw-0.35.1/CMakeLists.txt --- openmw-0.35.0/CMakeLists.txt 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/CMakeLists.txt 2015-03-12 11:06:00.000000000 +0000 @@ -1,5 +1,12 @@ project(OpenMW) +# If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." + FORCE) +ENDIF() + if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") @@ -13,7 +20,7 @@ set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 35) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") @@ -368,6 +375,9 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) +configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt") + if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") @@ -377,20 +387,26 @@ # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-unused-but-set-parameter") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) +elseif (MSVC) + # Enable link-time code generation globally for all linking + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") endif (CMAKE_COMPILER_IS_GNUCC) IF(NOT WIN32 AND NOT APPLE) # Linux building # Paths SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") - SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Where to install libraries") + SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Where to install libraries") SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix") SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") @@ -438,23 +454,25 @@ INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) # Install icon and desktop file - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install global configuration files - INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + IF(BUILD_OPENCS) - INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") + INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) # Install resources - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" COMPONENT "Resources") INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") ENDIF(NOT WIN32 AND NOT APPLE) @@ -469,6 +487,7 @@ "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -659,6 +678,7 @@ 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -666,6 +686,7 @@ # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4101 # Unreferenced local variable (-Wunused-variable) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) @@ -684,56 +705,23 @@ set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set_property(GLOBAL APPEND_STRING PROPERTY COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # there's an unreferenced local variable in the ogre platform, suppress it - set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}") - set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") - set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_LAUNCHER) - set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_LAUNCHER) - set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_BSATOOL) - set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_BSATOOL) - if (BUILD_ESMTOOL) - set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_ESMTOOL) - if (BUILD_WIZARD) - set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_WIZARD) + if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) - if (BUILD_MWINIIMPORTER) - set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_MWINIIMPORTER) endif(MSVC) - # Same for MinGW - if (MINGW) - if (USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") - else(USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,windows") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,windows") - endif(USE_DEBUG_CONSOLE) - - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") - endif(MINGW) - # TODO: At some point release builds should not use the console but rather write to a log file #set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") #set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS") @@ -747,6 +735,7 @@ install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) diff -Nru openmw-0.35.0/components/CMakeLists.txt openmw-0.35.1/components/CMakeLists.txt --- openmw-0.35.0/components/CMakeLists.txt 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/CMakeLists.txt 2015-03-12 11:06:00.000000000 +0000 @@ -1,5 +1,4 @@ project (Components) -set (CMAKE_BUILD_TYPE DEBUG) # Version file set (VERSION_HPP_IN ${CMAKE_CURRENT_SOURCE_DIR}/version/version.hpp.cmake) @@ -63,7 +62,7 @@ loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate + aisequence magiceffects util custommarkerstate stolenitems ) add_component_dir (esmterrain diff -Nru openmw-0.35.0/components/compiler/extensions0.cpp openmw-0.35.1/components/compiler/extensions0.cpp --- openmw-0.35.0/components/compiler/extensions0.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/compiler/extensions0.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -303,6 +303,7 @@ extensions.registerInstruction ("sv", "", opcodeShowVars, opcodeShowVarsExplicit); extensions.registerInstruction("tgm", "", opcodeToggleGodMode); extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); + extensions.registerInstruction("togglescripts", "", opcodeToggleScripts); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); diff -Nru openmw-0.35.0/components/compiler/opcodes.hpp openmw-0.35.1/components/compiler/opcodes.hpp --- openmw-0.35.0/components/compiler/opcodes.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/compiler/opcodes.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -278,6 +278,7 @@ const int opcodeShowVars = 0x200021d; const int opcodeShowVarsExplicit = 0x200021e; const int opcodeToggleGodMode = 0x200021f; + const int opcodeToggleScripts = 0x2000301; const int opcodeDisableLevitation = 0x2000220; const int opcodeEnableLevitation = 0x2000221; const int opcodeCast = 0x2000227; diff -Nru openmw-0.35.0/components/config/launchersettings.cpp openmw-0.35.1/components/config/launchersettings.cpp --- openmw-0.35.0/components/config/launchersettings.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/config/launchersettings.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -105,6 +105,12 @@ // obtain content list from game settings (if present) const QStringList files(gameSettings.getContentList()); + // if openmw.cfg has no content, exit so we don't create an empty content list. + if (files.isEmpty()) + { + return; + } + // if any existing profile in launcher matches the content list, make that profile the default foreach(const QString &listName, getContentLists()) { diff -Nru openmw-0.35.0/components/config/launchersettings.hpp openmw-0.35.1/components/config/launchersettings.hpp --- openmw-0.35.0/components/config/launchersettings.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/config/launchersettings.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -17,7 +17,7 @@ /// \return names of all Content Lists in the launcher's .cfg file. QStringList getContentLists(); - /// Set initally selected content list to match values from openmw.cfg, creating if necessary + /// Set initially selected content list to match values from openmw.cfg, creating if necessary void setContentList(const GameSettings& gameSettings); /// Create a Content List (or replace if it already exists) diff -Nru openmw-0.35.0/components/contentselector/model/contentmodel.cpp openmw-0.35.1/components/contentselector/model/contentmodel.cpp --- openmw-0.35.0/components/contentselector/model/contentmodel.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/contentselector/model/contentmodel.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -15,8 +15,7 @@ mMimeType ("application/omwcontent"), mMimeTypes (QStringList() << mMimeType), mColumnCount (1), - mDragDropFlags (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled), - mDropActions (Qt::CopyAction | Qt::MoveAction) + mDropActions (Qt::MoveAction) { setEncoding ("win1252"); uncheckAll(); @@ -104,7 +103,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return Qt::NoItemFlags; + return Qt::ItemIsDropEnabled; const EsmFile *file = item(index.row()); @@ -116,10 +115,10 @@ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; Qt::ItemFlags returnFlags; - bool allDependenciesFound = true; - bool gamefileChecked = false; - //addon can be checked if its gamefile is and all other dependencies exist + // addon can be checked if its gamefile is + // ... special case, addon with no dependency can be used with any gamefile. + bool gamefileChecked = (file->gameFiles().count() == 0); foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; @@ -145,16 +144,11 @@ if (gamefileChecked || !(dependency->isGameFile())) break; } - - allDependenciesFound = allDependenciesFound && depFound; } if (gamefileChecked) { - if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | mDragDropFlags; - else - returnFlags = Qt::ItemIsSelectable; + returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; } return returnFlags; @@ -443,11 +437,6 @@ filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; dir.setNameFilters(filters); - QTextCodec *codec = QTextCodec::codecForName("UTF8"); - - // Create a decoder for non-latin characters in esx metadata - QTextDecoder *decoder = codec->makeDecoder(); - foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); @@ -465,13 +454,21 @@ EsmFile *file = new EsmFile(path); foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) - file->addGameFile(QString::fromStdString(item.name)); + file->addGameFile(QString::fromUtf8(item.name.c_str())); - file->setAuthor (decoder->toUnicode(fileReader.getAuthor().c_str())); + file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); file->setFormat (fileReader.getFormat()); file->setFilePath (info.absoluteFilePath()); - file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); + file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); + + // HACK + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing + // from the file supplied by Bethesda, so we have to add it ourselves + if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) + { + file->addGameFile(QString::fromUtf8("Tribunal.esm")); + } // Put the file in the table addFile(file); @@ -484,11 +481,22 @@ } - delete decoder; - sortFiles(); } +QStringList ContentSelectorModel::ContentModel::gameFiles() const +{ + QStringList gameFiles; + foreach(const ContentSelectorModel::EsmFile *file, mFiles) + { + if (file->isGameFile()) + { + gameFiles.append(file->fileName()); + } + } + return gameFiles; +} + void ContentSelectorModel::ContentModel::sortFiles() { //first, sort the model such that all dependencies are ordered upstream (gamefile) first. @@ -544,13 +552,13 @@ return mPluginsWithLoadOrderError.contains(file->filePath()); } -void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList) { mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { - if (setCheckState(filepath, isChecked)) + if (setCheckState(filepath, true)) { // as necessary, move plug-ins in visible list to match sequence of supplied filelist const EsmFile* file = item(filepath); @@ -589,7 +597,7 @@ QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const { QList errors = QList(); - foreach(QString dependentfileName, file->gameFiles()) + foreach(const QString &dependentfileName, file->gameFiles()) { const EsmFile* dependentFile = item(dependentfileName); diff -Nru openmw-0.35.0/components/contentselector/model/contentmodel.hpp openmw-0.35.1/components/contentselector/model/contentmodel.hpp --- openmw-0.35.0/components/contentselector/model/contentmodel.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/contentselector/model/contentmodel.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -47,11 +47,12 @@ QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; + QStringList gameFiles() const; bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setContentList(const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList); ContentFileList checkedItems() const; void uncheckAll(); @@ -89,7 +90,6 @@ QString mMimeType; QStringList mMimeTypes; int mColumnCount; - Qt::ItemFlags mDragDropFlags; Qt::DropActions mDropActions; }; } diff -Nru openmw-0.35.0/components/contentselector/model/esmfile.cpp openmw-0.35.1/components/contentselector/model/esmfile.cpp --- openmw-0.35.0/components/contentselector/model/esmfile.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/contentselector/model/esmfile.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -62,6 +62,13 @@ return encodedData; } +bool ContentSelectorModel::EsmFile::isGameFile() const +{ + return (mGameFiles.size() == 0) && + (mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive) || + mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive)); +} + QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const { switch (prop) diff -Nru openmw-0.35.0/components/contentselector/model/esmfile.hpp openmw-0.35.1/components/contentselector/model/esmfile.hpp --- openmw-0.35.0/components/contentselector/model/esmfile.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/contentselector/model/esmfile.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -64,7 +64,7 @@ .arg(mGameFiles.join(", ")); } - inline bool isGameFile() const { return (mGameFiles.size() == 0); } + bool isGameFile() const; QByteArray encodedData() const; public: diff -Nru openmw-0.35.0/components/contentselector/view/contentselector.cpp openmw-0.35.1/components/contentselector/view/contentselector.cpp --- openmw-0.35.0/components/contentselector/view/contentselector.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/contentselector/view/contentselector.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,12 +10,14 @@ #include #include #include +#include #include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) { - ui.setupUi (parent); + ui.setupUi(parent); + ui.addonView->setDragDropMode(QAbstractItemView::InternalMove); buildContentModel(); buildGameFileView(); @@ -32,13 +34,7 @@ { ui.gameFileView->setVisible (true); - mGameFileProxyModel = new QSortFilterProxyModel(this); - mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); - mGameFileProxyModel->setFilterRole (Qt::UserRole); - mGameFileProxyModel->setSourceModel (mContentModel); - ui.gameFileView->setPlaceholderText(QString("Select a game file...")); - ui.gameFileView->setModel(mGameFileProxyModel); connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)), this, SLOT (slotCurrentGameFileIndexChanged(int))); @@ -112,7 +108,7 @@ slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setContentList(list, true); + mContentModel->setContentList(list); } ContentSelectorModel::ContentFileList @@ -128,6 +124,15 @@ { mContentModel->addFiles(path); + // add any game files to the combo box + foreach(const QString gameFileName, mContentModel->gameFiles()) + { + if (ui.gameFileView->findText(gameFileName) == -1) + { + ui.gameFileView->addItem(gameFileName); + } + } + if (ui.gameFileView->currentIndex() != -1) ui.gameFileView->setCurrentIndex(-1); @@ -149,31 +154,36 @@ { static int oldIndex = -1; - QAbstractItemModel *const model = ui.gameFileView->model(); - QSortFilterProxyModel *proxy = dynamic_cast(model); - - if (proxy) - proxy->setDynamicSortFilter(false); - if (index != oldIndex) { if (oldIndex > -1) - model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + { + setGameFileSelected(oldIndex, false); + } oldIndex = index; - model->setData(model->index(index, 0), true, Qt::UserRole + 1); + setGameFileSelected(index, true); mContentModel->checkForLoadOrderErrors(); } - if (proxy) - proxy->setDynamicSortFilter(true); - emit signalCurrentGamefileIndexChanged (index); } +void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool selected) +{ + QString fileName = ui.gameFileView->itemText(index); + const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); + if (file != NULL) + { + QModelIndex index(mContentModel->indexFromItem(file)); + mContentModel->setData(index, selected, Qt::UserRole + 1); + } +} + void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) diff -Nru openmw-0.35.0/components/contentselector/view/contentselector.hpp openmw-0.35.1/components/contentselector/view/contentselector.hpp --- openmw-0.35.0/components/contentselector/view/contentselector.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/contentselector/view/contentselector.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -19,7 +19,6 @@ protected: ContentSelectorModel::ContentModel *mContentModel; - QSortFilterProxyModel *mGameFileProxyModel; QSortFilterProxyModel *mAddonProxyModel; public: @@ -52,6 +51,7 @@ void buildContentModel(); void buildGameFileView(); void buildAddonView(); + void setGameFileSelected(int index, bool selected); signals: void signalCurrentGamefileIndexChanged (int); diff -Nru openmw-0.35.0/components/esm/aipackage.cpp openmw-0.35.1/components/esm/aipackage.cpp --- openmw-0.35.0/components/esm/aipackage.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/aipackage.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,38 +11,34 @@ mServices = 0; } - void AIPackageList::load(ESMReader &esm) + void AIPackageList::add(ESMReader &esm) { - mList.clear(); - while (esm.hasMoreSubs()) { - // initialize every iteration - AIPackage pack; - esm.getSubName(); - if (esm.retSubName() == 0x54444e43) { // CNDT - mList.back().mCellName = esm.getHString(); - } else if (esm.retSubName() == AI_Wander) { - pack.mType = AI_Wander; - esm.getHExact(&pack.mWander, 14); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Travel) { - pack.mType = AI_Travel; - esm.getHExact(&pack.mTravel, 16); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Escort || - esm.retSubName() == AI_Follow) - { - pack.mType = - (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; - esm.getHExact(&pack.mTarget, 48); - mList.push_back(pack); - } else if (esm.retSubName() == AI_Activate) { - pack.mType = AI_Activate; - esm.getHExact(&pack.mActivate, 33); - mList.push_back(pack); - } else { // not AI package related data, so leave - return; - } + AIPackage pack; + if (esm.retSubName() == AI_CNDT) { + mList.back().mCellName = esm.getHString(); + } else if (esm.retSubName() == AI_Wander) { + pack.mType = AI_Wander; + esm.getHExact(&pack.mWander, 14); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Travel) { + pack.mType = AI_Travel; + esm.getHExact(&pack.mTravel, 16); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Escort || + esm.retSubName() == AI_Follow) + { + pack.mType = + (esm.retSubName() == AI_Escort) ? AI_Escort : AI_Follow; + esm.getHExact(&pack.mTarget, 48); + mList.push_back(pack); + } else if (esm.retSubName() == AI_Activate) { + pack.mType = AI_Activate; + esm.getHExact(&pack.mActivate, 33); + mList.push_back(pack); + } else { // not AI package related data, so leave + return; } + } void AIPackageList::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/aipackage.hpp openmw-0.35.1/components/esm/aipackage.hpp --- openmw-0.35.0/components/esm/aipackage.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/aipackage.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -63,7 +63,8 @@ AI_Travel = 0x545f4941, AI_Follow = 0x465f4941, AI_Escort = 0x455f4941, - AI_Activate = 0x415f4941 + AI_Activate = 0x415f4941, + AI_CNDT = 0x54444e43 }; /// \note Used for storaging packages in a single container @@ -90,11 +91,9 @@ { std::vector mList; - /// \note This breaks consistency of subrecords reading: - /// after calling it subrecord name is already read, so - /// it needs to use retSubName() if needed. But, hey, there - /// is only one field left (XSCL) and only two records uses AI - void load(ESMReader &esm); + /// Add a single AIPackage, assumes subrecord name was already read + void add(ESMReader &esm); + void save(ESMWriter &esm) const; }; } diff -Nru openmw-0.35.0/components/esm/cellref.hpp openmw-0.35.1/components/esm/cellref.hpp --- openmw-0.35.0/components/esm/cellref.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/cellref.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -59,10 +59,12 @@ // For weapon or armor, this is the remaining item health. // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + // For lights it is remaining time. + // This could be -1 if the charge was not touched yet (i.e. full). union { - int mChargeInt; - float mChargeFloat; + int mChargeInt; // Used by everything except lights + float mChargeFloat; // Used only by lights }; // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). diff -Nru openmw-0.35.0/components/esm/defs.hpp openmw-0.35.1/components/esm/defs.hpp --- openmw-0.35.0/components/esm/defs.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/defs.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -117,6 +117,7 @@ REC_MARK = FourCC<'M','A','R','K'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value, + REC_STLN = FourCC<'S','T','L','N'>::value, // format 1 REC_FILT = FourCC<'F','I','L','T'>::value, diff -Nru openmw-0.35.0/components/esm/effectlist.cpp openmw-0.35.1/components/esm/effectlist.cpp --- openmw-0.35.0/components/esm/effectlist.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/effectlist.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,13 +8,18 @@ void EffectList::load(ESMReader &esm) { mList.clear(); - ENAMstruct s; while (esm.isNextSub("ENAM")) { - esm.getHT(s, 24); - mList.push_back(s); + add(esm); } } +void EffectList::add(ESMReader &esm) +{ + ENAMstruct s; + esm.getHT(s, 24); + mList.push_back(s); +} + void EffectList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff -Nru openmw-0.35.0/components/esm/effectlist.hpp openmw-0.35.1/components/esm/effectlist.hpp --- openmw-0.35.0/components/esm/effectlist.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/effectlist.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -29,11 +29,15 @@ }; #pragma pack(pop) + /// EffectList, ENAM subrecord struct EffectList { - std::vector mList; + /// Load one effect, assumes subrecord name was already read + void add(ESMReader &esm); + + /// Load all effects void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff -Nru openmw-0.35.0/components/esm/loadacti.cpp openmw-0.35.1/components/esm/loadacti.cpp --- openmw-0.35.0/components/esm/loadacti.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadacti.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,18 +8,34 @@ { unsigned int Activator::sRecordId = REC_ACTI; -void Activator::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); -} -void Activator::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); -} + void Activator::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } + void Activator::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + } void Activator::blank() { diff -Nru openmw-0.35.0/components/esm/loadalch.cpp openmw-0.35.1/components/esm/loadalch.cpp --- openmw-0.35.0/components/esm/loadalch.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadalch.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,24 +8,51 @@ { unsigned int Potion::sRecordId = REC_ALCH; -void Potion::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason - mScript = esm.getHNOString("SCRI"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "ALDT", 12); - mEffects.load(esm); -} -void Potion::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("TEXT", mIcon); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("ALDT", mData, 12); - mEffects.save(esm); -} + void Potion::load(ESMReader &esm) + { + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason + mIcon = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','L','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing ALDT"); + } + void Potion::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("TEXT", mIcon); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("ALDT", mData, 12); + mEffects.save(esm); + } void Potion::blank() { diff -Nru openmw-0.35.0/components/esm/loadappa.cpp openmw-0.35.1/components/esm/loadappa.cpp --- openmw-0.35.0/components/esm/loadappa.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadappa.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,25 +10,35 @@ void Apparatus::load(ESMReader &esm) { - // we will not treat duplicated subrecords as errors here + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - NAME subName = esm.retSubName(); - - if (subName == "MODL") - mModel = esm.getHString(); - else if (subName == "FNAM") - mName = esm.getHString(); - else if (subName == "AADT") - esm.getHT(mData); - else if (subName == "SCRI") - mScript = esm.getHString(); - else if (subName == "ITEX") - mIcon = esm.getHString(); - else - esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing AADT"); } void Apparatus::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/loadarmo.cpp openmw-0.35.1/components/esm/loadarmo.cpp --- openmw-0.35.0/components/esm/loadarmo.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadarmo.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -7,52 +7,87 @@ namespace ESM { -void PartReferenceList::load(ESMReader &esm) -{ - mParts.clear(); - while (esm.isNextSub("INDX")) + void PartReferenceList::add(ESMReader &esm) { PartReference pr; esm.getHT(pr.mPart); // The INDX byte pr.mMale = esm.getHNOString("BNAM"); pr.mFemale = esm.getHNOString("CNAM"); mParts.push_back(pr); + } -} -void PartReferenceList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + void PartReferenceList::load(ESMReader &esm) { - esm.writeHNT("INDX", it->mPart); - esm.writeHNOString("BNAM", it->mMale); - esm.writeHNOString("CNAM", it->mFemale); + mParts.clear(); + while (esm.isNextSub("INDX")) + { + add(esm); + } } -} -unsigned int Armor::sRecordId = REC_ARMO; + void PartReferenceList::save(ESMWriter &esm) const + { + for (std::vector::const_iterator it = mParts.begin(); it != mParts.end(); ++it) + { + esm.writeHNT("INDX", it->mPart); + esm.writeHNOString("BNAM", it->mMale); + esm.writeHNOString("CNAM", it->mFemale); + } + } -void Armor::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - esm.getHNT(mData, "AODT", 24); - mIcon = esm.getHNOString("ITEX"); - mParts.load(esm); - mEnchant = esm.getHNOString("ENAM"); -} + unsigned int Armor::sRecordId = REC_ARMO; -void Armor::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("AODT", mData, 24); - esm.writeHNOCString("ITEX", mIcon); - mParts.save(esm); - esm.writeHNOCString("ENAM", mEnchant); -} + void Armor::load(ESMReader &esm) + { + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','O','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); + } + + void Armor::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("AODT", mData, 24); + esm.writeHNOCString("ITEX", mIcon); + mParts.save(esm); + esm.writeHNOCString("ENAM", mEnchant); + } void Armor::blank() { diff -Nru openmw-0.35.0/components/esm/loadarmo.hpp openmw-0.35.1/components/esm/loadarmo.hpp --- openmw-0.35.0/components/esm/loadarmo.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadarmo.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -55,6 +55,10 @@ { std::vector mParts; + /// Load one part, assumes the subrecord name was already read + void add(ESMReader &esm); + + /// TODO: remove this method. The ESM format does not guarantee that all Part subrecords follow one another. void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff -Nru openmw-0.35.0/components/esm/loadbody.cpp openmw-0.35.1/components/esm/loadbody.cpp --- openmw-0.35.0/components/esm/loadbody.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadbody.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,9 +11,30 @@ void BodyPart::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mRace = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BYDT", 4); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { diff -Nru openmw-0.35.0/components/esm/loadbook.cpp openmw-0.35.1/components/esm/loadbook.cpp --- openmw-0.35.0/components/esm/loadbook.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadbook.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,26 +8,54 @@ { unsigned int Book::sRecordId = REC_BOOK; -void Book::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BKDT", 20); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mText = esm.getHNOString("TEXT"); - mEnchant = esm.getHNOString("ENAM"); -} -void Book::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("BKDT", mData, 20); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOString("TEXT", mText); - esm.writeHNOCString("ENAM", mEnchant); -} + void Book::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'B','K','D','T'>::value: + esm.getHT(mData, 20); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: + mText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing BKDT subrecord"); + } + void Book::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("BKDT", mData, 20); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOString("TEXT", mText); + esm.writeHNOCString("ENAM", mEnchant); + } void Book::blank() { diff -Nru openmw-0.35.0/components/esm/loadbsgn.cpp openmw-0.35.1/components/esm/loadbsgn.cpp --- openmw-0.35.0/components/esm/loadbsgn.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadbsgn.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,11 +10,29 @@ void BirthSign::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - mTexture = esm.getHNOString("TNAM"); - mDescription = esm.getHNOString("DESC"); - - mPowers.load(esm); + mPowers.mList.clear(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } } void BirthSign::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/loadclas.cpp openmw-0.35.1/components/esm/loadclas.cpp --- openmw-0.35.0/components/esm/loadclas.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadclas.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,17 +10,17 @@ { unsigned int Class::sRecordId = REC_CLAS; -const Class::Specialization Class::sSpecializationIds[3] = { - Class::Combat, - Class::Magic, - Class::Stealth -}; - -const char *Class::sGmstSpecializationIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" -}; + const Class::Specialization Class::sSpecializationIds[3] = { + Class::Combat, + Class::Magic, + Class::Stealth + }; + + const char *Class::sGmstSpecializationIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; int& Class::CLDTstruct::getSkill (int index, bool major) @@ -39,22 +39,40 @@ return mSkills[index][major ? 1 : 0]; } -void Class::load(ESMReader &esm) -{ - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CLDT", 60); - - if (mData.mIsPlayable > 1) - esm.fail("Unknown bool value"); - - mDescription = esm.getHNOString("DESC"); -} -void Class::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CLDT", mData, 60); - esm.writeHNOString("DESC", mDescription); -} + void Class::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','L','D','T'>::value: + esm.getHT(mData, 60); + if (mData.mIsPlayable > 1) + esm.fail("Unknown bool value"); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CLDT subrecord"); + } + void Class::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CLDT", mData, 60); + esm.writeHNOString("DESC", mDescription); + } void Class::blank() { diff -Nru openmw-0.35.0/components/esm/loadclot.cpp openmw-0.35.1/components/esm/loadclot.cpp --- openmw-0.35.0/components/esm/loadclot.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadclot.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,17 +10,42 @@ void Clothing::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CTDT", 12); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - - mParts.load(esm); - - - mEnchant = esm.getHNOString("ENAM"); + mParts.mParts.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','T','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + case ESM::FourCC<'I','N','D','X'>::value: + mParts.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CTDT subrecord"); } void Clothing::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/loadcont.cpp openmw-0.35.1/components/esm/loadcont.cpp --- openmw-0.35.0/components/esm/loadcont.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadcont.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -7,55 +7,79 @@ namespace ESM { -void InventoryList::load(ESMReader &esm) -{ - mList.clear(); - ContItem ci; - while (esm.isNextSub("NPCO")) + void InventoryList::add(ESMReader &esm) { + ContItem ci; esm.getHT(ci, 36); mList.push_back(ci); } -} -void InventoryList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + void InventoryList::save(ESMWriter &esm) const { - esm.writeHNT("NPCO", *it, 36); + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("NPCO", *it, 36); + } } -} unsigned int Container::sRecordId = REC_CONT; -void Container::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mWeight, "CNDT", 4); - esm.getHNT(mFlags, "FLAG", 4); - - if (mFlags & 0xf4) - esm.fail("Unknown flags"); - if (!(mFlags & 0x8)) - esm.fail("Flag 8 not set"); - - mScript = esm.getHNOString("SCRI"); - - mInventory.load(esm); -} + void Container::load(ESMReader &esm) + { + mInventory.mList.clear(); + bool hasWeight = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','N','D','T'>::value: + esm.getHT(mWeight, 4); + hasWeight = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags, 4); + if (mFlags & 0xf4) + esm.fail("Unknown flags"); + if (!(mFlags & 0x8)) + esm.fail("Flag 8 not set"); + hasFlags = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasWeight) + esm.fail("Missing CNDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); + } -void Container::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CNDT", mWeight, 4); - esm.writeHNT("FLAG", mFlags, 4); + void Container::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CNDT", mWeight, 4); + esm.writeHNT("FLAG", mFlags, 4); - esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SCRI", mScript); - mInventory.save(esm); -} + mInventory.save(esm); + } void Container::blank() { diff -Nru openmw-0.35.0/components/esm/loadcont.hpp openmw-0.35.1/components/esm/loadcont.hpp --- openmw-0.35.0/components/esm/loadcont.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadcont.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -22,11 +22,14 @@ NAME32 mItem; }; +/// InventoryList, NPCO subrecord struct InventoryList { std::vector mList; - void load(ESMReader &esm); + /// Load one item, assumes subrecord name is already read + void add(ESMReader &esm); + void save(ESMWriter &esm) const; }; diff -Nru openmw-0.35.0/components/esm/loadcrea.cpp openmw-0.35.1/components/esm/loadcrea.cpp --- openmw-0.35.0/components/esm/loadcrea.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadcrea.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,55 +8,94 @@ unsigned int Creature::sRecordId = REC_CREA; -void Creature::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNString("MODL"); - mOriginal = esm.getHNOString("CNAM"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - - esm.getHNT(mData, "NPDT", 96); - - esm.getHNT(mFlags, "FLAG"); - mScale = 1.0; - esm.getHNOT(mScale, "XSCL"); + void Creature::load(ESMReader &esm) + { + mPersistent = esm.getRecordFlags() & 0x0400; - mInventory.load(esm); - mSpells.load(esm); + mAiPackage.mList.clear(); + mInventory.mList.clear(); + mSpells.mList.clear(); - if (esm.isNextSub("AIDT")) - { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; - } - else + mScale = 1.f; mHasAI = false; - - mAiPackage.load(esm); - esm.skipRecord(); -} - -void Creature::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("CNAM", mOriginal); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("NPDT", mData, 96); - esm.writeHNT("FLAG", mFlags); - if (mScale != 1.0) { - esm.writeHNT("XSCL", mScale); + bool hasNpdt = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mOriginal = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + esm.getHT(mData, 96); + hasNpdt = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + hasFlags = true; + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI = true; + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + void Creature::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("CNAM", mOriginal); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("NPDT", mData, 96); + esm.writeHNT("FLAG", mFlags); + if (mScale != 1.0) { + esm.writeHNT("XSCL", mScale); + } + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} void Creature::blank() { diff -Nru openmw-0.35.0/components/esm/loaddoor.cpp openmw-0.35.1/components/esm/loaddoor.cpp --- openmw-0.35.0/components/esm/loaddoor.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loaddoor.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,23 +8,43 @@ { unsigned int Door::sRecordId = REC_DOOR; -void Door::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - mOpenSound = esm.getHNOString("SNAM"); - mCloseSound = esm.getHNOString("ANAM"); -} + void Door::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mOpenSound = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mCloseSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } -void Door::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mOpenSound); - esm.writeHNOCString("ANAM", mCloseSound); -} + void Door::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mOpenSound); + esm.writeHNOCString("ANAM", mCloseSound); + } void Door::blank() { diff -Nru openmw-0.35.0/components/esm/loadench.cpp openmw-0.35.1/components/esm/loadench.cpp --- openmw-0.35.0/components/esm/loadench.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadench.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,8 +10,28 @@ void Enchantment::load(ESMReader &esm) { - esm.getHNT(mData, "ENDT", 16); - mEffects.load(esm); + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + if (!hasData) + esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/loadfact.cpp openmw-0.35.1/components/esm/loadfact.cpp --- openmw-0.35.0/components/esm/loadfact.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadfact.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -28,27 +28,46 @@ void Faction::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); - // Read rank names. These are optional. - int i = 0; - while (esm.isNextSub("RNAM") && i < 10) - mRanks[i++] = esm.getHString(); - - // Main data struct - esm.getHNT(mData, "FADT", 240); - - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - - // Read faction response values + int rankCounter=0; + bool hasData = false; while (esm.hasMoreSubs()) { - std::string faction = esm.getHNString("ANAM"); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { diff -Nru openmw-0.35.0/components/esm/loadingr.cpp openmw-0.35.1/components/esm/loadingr.cpp --- openmw-0.35.0/components/esm/loadingr.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadingr.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,45 +8,71 @@ { unsigned int Ingredient::sRecordId = REC_INGR; -void Ingredient::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "IRDT", 56); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - // horrible hack to fix broken data in records - for (int i=0; i<4; ++i) + void Ingredient::load(ESMReader &esm) { - if (mData.mEffectID[i] != 85 && - mData.mEffectID[i] != 22 && - mData.mEffectID[i] != 17 && - mData.mEffectID[i] != 79 && - mData.mEffectID[i] != 74) + bool hasData = false; + while (esm.hasMoreSubs()) { - mData.mAttributes[i] = -1; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','R','D','T'>::value: + esm.getHT(mData, 56); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - // is this relevant in cycle from 0 to 4? - if (mData.mEffectID[i] != 89 && - mData.mEffectID[i] != 26 && - mData.mEffectID[i] != 21 && - mData.mEffectID[i] != 83 && - mData.mEffectID[i] != 78) + if (!hasData) + esm.fail("Missing IRDT subrecord"); + + // horrible hack to fix broken data in records + for (int i=0; i<4; ++i) { - mData.mSkills[i] = -1; + if (mData.mEffectID[i] != 85 && + mData.mEffectID[i] != 22 && + mData.mEffectID[i] != 17 && + mData.mEffectID[i] != 79 && + mData.mEffectID[i] != 74) + { + mData.mAttributes[i] = -1; + } + + // is this relevant in cycle from 0 to 4? + if (mData.mEffectID[i] != 89 && + mData.mEffectID[i] != 26 && + mData.mEffectID[i] != 21 && + mData.mEffectID[i] != 83 && + mData.mEffectID[i] != 78) + { + mData.mSkills[i] = -1; + } } } -} -void Ingredient::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("IRDT", mData, 56); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Ingredient::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("IRDT", mData, 56); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Ingredient::blank() { diff -Nru openmw-0.35.0/components/esm/loadlevlist.cpp openmw-0.35.1/components/esm/loadlevlist.cpp --- openmw-0.35.0/components/esm/loadlevlist.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadlevlist.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -7,47 +7,53 @@ namespace ESM { -void LeveledListBase::load(ESMReader &esm) -{ - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); - - if (esm.isNextSub("INDX")) + void LevelledListBase::load(ESMReader &esm) { - int len; - esm.getHT(len); - mList.resize(len); - } - else - return; - - // TODO: Merge with an existing lists here. This can be done - // simply by adding the lists together, making sure that they are - // sorted by level. A better way might be to exclude repeated - // items. Also, some times we don't want to merge lists, just - // overwrite. Figure out a way to give the user this option. + esm.getHNT(mFlags, "DATA"); + esm.getHNT(mChanceNone, "NNAM"); - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); + if (esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + mList.resize(len); + } + else + { + // Original engine ignores rest of the record, even if there are items following + mList.clear(); + esm.skipRecord(); + return; + } + + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. + + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } } -} -void LeveledListBase::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mFlags); - esm.writeHNT("NNAM", mChanceNone); - esm.writeHNT("INDX", mList.size()); - - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + void LevelledListBase::save(ESMWriter &esm) const { - esm.writeHNCString(mRecName, it->mId); - esm.writeHNT("INTV", it->mLevel); + esm.writeHNT("DATA", mFlags); + esm.writeHNT("NNAM", mChanceNone); + esm.writeHNT("INDX", mList.size()); + + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNCString(mRecName, it->mId); + esm.writeHNT("INTV", it->mLevel); + } } -} - void LeveledListBase::blank() + void LevelledListBase::blank() { mFlags = 0; mChanceNone = 0; diff -Nru openmw-0.35.0/components/esm/loadlevlist.hpp openmw-0.35.1/components/esm/loadlevlist.hpp --- openmw-0.35.0/components/esm/loadlevlist.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadlevlist.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,14 +11,14 @@ class ESMWriter; /* - * Leveled lists. Since these have identical layout, I only bothered + * Levelled lists. Since these have identical layout, I only bothered * to implement it once. * - * We should later implement the ability to merge leveled lists from + * We should later implement the ability to merge levelled lists from * several files. */ -struct LeveledListBase +struct LevelledListBase { int mFlags; unsigned char mChanceNone; // Chance that none are selected (0-100) @@ -43,7 +43,7 @@ ///< Set record to default state (does not touch the ID). }; -struct CreatureLevList: LeveledListBase +struct CreatureLevList: LevelledListBase { static unsigned int sRecordId; @@ -61,7 +61,7 @@ } }; -struct ItemLevList: LeveledListBase +struct ItemLevList: LevelledListBase { static unsigned int sRecordId; @@ -72,7 +72,7 @@ // list is instantiated, instead of // giving several identical items // (used when a container has more - // than one instance of one leveled + // than one instance of one levelled // list.) AllLevels = 0x02 // Calculate from all levels <= player // level, not just the closest below diff -Nru openmw-0.35.0/components/esm/loadligh.cpp openmw-0.35.1/components/esm/loadligh.cpp --- openmw-0.35.0/components/esm/loadligh.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadligh.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,25 +8,50 @@ { unsigned int Light::sRecordId = REC_LIGH; -void Light::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - mIcon = esm.getHNOString("ITEX"); - assert(sizeof(mData) == 24); - esm.getHNT(mData, "LHDT", 24); - mScript = esm.getHNOString("SCRI"); - mSound = esm.getHNOString("SNAM"); -} -void Light::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNT("LHDT", mData, 24); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mSound); -} + void Light::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'L','H','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LHDT subrecord"); + } + void Light::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNT("LHDT", mData, 24); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mSound); + } void Light::blank() { diff -Nru openmw-0.35.0/components/esm/loadlock.cpp openmw-0.35.1/components/esm/loadlock.cpp --- openmw-0.35.0/components/esm/loadlock.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadlock.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,26 +8,48 @@ { unsigned int Lockpick::sRecordId = REC_LOCK; -void Lockpick::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "LKDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} + void Lockpick::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'L','K','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LKDT subrecord"); + } -void Lockpick::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + void Lockpick::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("LKDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Lockpick::blank() { diff -Nru openmw-0.35.0/components/esm/loadmgef.cpp openmw-0.35.1/components/esm/loadmgef.cpp --- openmw-0.35.0/components/esm/loadmgef.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadmgef.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -191,33 +191,64 @@ void MagicEffect::load(ESMReader &esm) { - esm.getHNT(mIndex, "INDX"); + esm.getHNT(mIndex, "INDX"); mId = indexToId (mIndex); - esm.getHNT(mData, "MEDT", 36); - if (esm.getFormat() == 0) - { - // don't allow mods to change fixed flags in the legacy format - mData.mFlags &= (AllowSpellmaking | AllowEnchanting | NegativeLight); - if (mIndex>=0 && mIndex=0 && mIndex::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'P','T','E','X'>::value: + mParticle = esm.getHString(); + break; + case ESM::FourCC<'B','S','N','D'>::value: + mBoltSound = esm.getHString(); + break; + case ESM::FourCC<'C','S','N','D'>::value: + mCastSound = esm.getHString(); + break; + case ESM::FourCC<'H','S','N','D'>::value: + mHitSound = esm.getHString(); + break; + case ESM::FourCC<'A','S','N','D'>::value: + mAreaSound = esm.getHString(); + break; + case ESM::FourCC<'C','V','F','X'>::value: + mCasting = esm.getHString(); + break; + case ESM::FourCC<'B','V','F','X'>::value: + mBolt = esm.getHString(); + break; + case ESM::FourCC<'H','V','F','X'>::value: + mHit = esm.getHString(); + break; + case ESM::FourCC<'A','V','F','X'>::value: + mArea = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } } void MagicEffect::save(ESMWriter &esm) const { diff -Nru openmw-0.35.0/components/esm/loadmgef.hpp openmw-0.35.1/components/esm/loadmgef.hpp --- openmw-0.35.0/components/esm/loadmgef.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadmgef.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -57,9 +57,9 @@ // Glow color for enchanted items with this effect int mRed, mGreen, mBlue; - float mUnknown1; + float mUnknown1; // Called "Size X" in CS float mSpeed; // Speed of fired projectile - float mUnknown2; + float mUnknown2; // Called "Size Cap" in CS }; // 36 bytes static const std::map sNames; diff -Nru openmw-0.35.0/components/esm/loadmisc.cpp openmw-0.35.1/components/esm/loadmisc.cpp --- openmw-0.35.0/components/esm/loadmisc.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadmisc.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,22 +8,45 @@ { unsigned int Miscellaneous::sRecordId = REC_MISC; -void Miscellaneous::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "MCDT", 12); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} -void Miscellaneous::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("MCDT", mData, 12); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Miscellaneous::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'M','C','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + } + } + if (!hasData) + esm.fail("Missing MCDT subrecord"); + } + + void Miscellaneous::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("MCDT", mData, 12); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Miscellaneous::blank() { diff -Nru openmw-0.35.0/components/esm/loadnpc.cpp openmw-0.35.1/components/esm/loadnpc.cpp --- openmw-0.35.0/components/esm/loadnpc.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadnpc.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,92 +8,136 @@ { unsigned int NPC::sRecordId = REC_NPC_; -void NPC::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - - mRace = esm.getHNString("RNAM"); - mClass = esm.getHNString("CNAM"); - mFaction = esm.getHNString("ANAM"); - mHead = esm.getHNString("BNAM"); - mHair = esm.getHNString("KNAM"); - - mScript = esm.getHNOString("SCRI"); - - esm.getSubNameIs("NPDT"); - esm.getSubHeader(); - if (esm.getSubSize() == 52) - { - mNpdtType = NPC_DEFAULT; - esm.getExact(&mNpdt52, 52); - } - else if (esm.getSubSize() == 12) + void NPC::load(ESMReader &esm) { - mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - esm.getExact(&mNpdt12, 12); - } - else - esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + mPersistent = esm.getRecordFlags() & 0x0400; - esm.getHNT(mFlags, "FLAG"); + mSpells.mList.clear(); + mInventory.mList.clear(); + mTransport.clear(); + mAiPackage.mList.clear(); - mInventory.load(esm); - mSpells.load(esm); - - if (esm.isNextSub("AIDT")) - { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; - } - else + bool hasNpdt = false; + bool hasFlags = false; mHasAI = false; - - mTransport.clear(); - while (esm.isNextSub("DODT") || esm.isNextSub("DNAM")) { - if (esm.retSubName() == 0x54444f44) { // DODT struct - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - } else if (esm.retSubName() == 0x4d414e44) { // DNAM struct - mTransport.back().mCellName = esm.getHString(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mClass = esm.getHString(); + break; + case ESM::FourCC<'A','N','A','M'>::value: + mFaction = esm.getHString(); + break; + case ESM::FourCC<'B','N','A','M'>::value: + mHead = esm.getHString(); + break; + case ESM::FourCC<'K','N','A','M'>::value: + mHair = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + hasNpdt = true; + esm.getSubHeader(); + if (esm.getSubSize() == 52) + { + mNpdtType = NPC_DEFAULT; + esm.getExact(&mNpdt52, 52); + } + else if (esm.getSubSize() == 12) + { + mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; + esm.getExact(&mNpdt12, 12); + } + else + esm.fail("NPC_NPDT must be 12 or 52 bytes long"); + break; + case ESM::FourCC<'F','L','A','G'>::value: + hasFlags = true; + esm.getHT(mFlags); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI= true; + break; + case ESM::FourCC<'D','O','D','T'>::value: + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mTransport.push_back(dodt); + break; + } + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.back().mCellName = esm.getHString(); + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mAiPackage.load(esm); -} -void NPC::save(ESMWriter &esm) const -{ - esm.writeHNOCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNCString("RNAM", mRace); - esm.writeHNCString("CNAM", mClass); - esm.writeHNCString("ANAM", mFaction); - esm.writeHNCString("BNAM", mHead); - esm.writeHNCString("KNAM", mHair); - esm.writeHNOCString("SCRI", mScript); - - if (mNpdtType == NPC_DEFAULT) - esm.writeHNT("NPDT", mNpdt52, 52); - else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) - esm.writeHNT("NPDT", mNpdt12, 12); - - esm.writeHNT("FLAG", mFlags); - - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + void NPC::save(ESMWriter &esm) const + { + esm.writeHNOCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNCString("RNAM", mRace); + esm.writeHNCString("CNAM", mClass); + esm.writeHNCString("ANAM", mFaction); + esm.writeHNCString("BNAM", mHead); + esm.writeHNCString("KNAM", mHair); + esm.writeHNOCString("SCRI", mScript); + + if (mNpdtType == NPC_DEFAULT) + esm.writeHNT("NPDT", mNpdt52, 52); + else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) + esm.writeHNT("NPDT", mNpdt12, 12); + + esm.writeHNT("FLAG", mFlags); + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); + typedef std::vector::const_iterator DestIter; + for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + mAiPackage.save(esm); } - mAiPackage.save(esm); -} bool NPC::isMale() const { return (mFlags & Female) == 0; diff -Nru openmw-0.35.0/components/esm/loadprob.cpp openmw-0.35.1/components/esm/loadprob.cpp --- openmw-0.35.0/components/esm/loadprob.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadprob.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,26 +8,48 @@ { unsigned int Probe::sRecordId = REC_PROB; -void Probe::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "PBDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} + void Probe::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'P','B','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing PBDT subrecord"); + } -void Probe::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); + void Probe::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - esm.writeHNT("PBDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Probe::blank() { diff -Nru openmw-0.35.0/components/esm/loadrace.cpp openmw-0.35.1/components/esm/loadrace.cpp --- openmw-0.35.0/components/esm/loadrace.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadrace.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -20,10 +20,34 @@ void Race::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "RADT", 140); - mPowers.load(esm); - mDescription = esm.getHNOString("DESC"); + mPowers.mList.clear(); + + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','A','D','T'>::value: + esm.getHT(mData, 140); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RADT subrecord"); } void Race::save(ESMWriter &esm) const { diff -Nru openmw-0.35.0/components/esm/loadrepa.cpp openmw-0.35.1/components/esm/loadrepa.cpp --- openmw-0.35.0/components/esm/loadrepa.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadrepa.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -10,13 +10,35 @@ void Repair::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "RIDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/loadscpt.cpp openmw-0.35.1/components/esm/loadscpt.cpp --- openmw-0.35.0/components/esm/loadscpt.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadscpt.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -9,17 +9,7 @@ unsigned int Script::sRecordId = REC_SCPT; -void Script::load(ESMReader &esm) -{ - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - mVarNames.clear(); - - // List of local variables - if (esm.isNextSub("SCVR")) + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -66,58 +56,70 @@ } } - // Script mData - if (esm.isNextSub("SCDT")) + void Script::load(ESMReader &esm) { - mScriptData.resize(mData.mScriptDataSize); - esm.getHExact(&mScriptData[0], mScriptData.size()); - } + SCHD data; + esm.getHNT(data, "SCHD", 52); + mData = data.mData; + mId = data.mName.toString(); - // Script text - mScriptText = esm.getHNOString("SCTX"); + mVarNames.clear(); - // NOTE: A minor hack/workaround... - // - // MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records - // at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords - // for variable names just skip these as a quick fix. An alternative - // solution would be to decode and validate SCVR subrecords even if they - // appear here. - if (esm.isNextSub("SCVR")) { - esm.skipHSub(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'S','C','V','R'>::value: + // list of local variables + loadSCVR(esm); + break; + case ESM::FourCC<'S','C','D','T'>::value: + // compiled script + mScriptData.resize(mData.mScriptDataSize); + esm.getHExact(&mScriptData[0], mScriptData.size()); + break; + case ESM::FourCC<'S','C','T','X'>::value: + mScriptText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } } -} -void Script::save(ESMWriter &esm) const -{ - std::string varNameString; - if (!mVarNames.empty()) - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) - varNameString.append(*it); - - SCHD data; - memset(&data, 0, sizeof(data)); - data.mData = mData; - memcpy(data.mName.name, mId.c_str(), mId.size()); + void Script::save(ESMWriter &esm) const + { + std::string varNameString; + if (!mVarNames.empty()) + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + varNameString.append(*it); - esm.writeHNT("SCHD", data, 52); + SCHD data; + memset(&data, 0, sizeof(data)); - if (!mVarNames.empty()) - { - esm.startSubRecord("SCVR"); - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + data.mData = mData; + memcpy(data.mName.name, mId.c_str(), mId.size()); + + esm.writeHNT("SCHD", data, 52); + + if (!mVarNames.empty()) { - esm.writeHCString(*it); + esm.startSubRecord("SCVR"); + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + { + esm.writeHCString(*it); + } + esm.endRecord("SCVR"); } - esm.endRecord("SCVR"); - } - esm.startSubRecord("SCDT"); - esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); - esm.endRecord("SCDT"); + esm.startSubRecord("SCDT"); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); + esm.endRecord("SCDT"); - esm.writeHNOString("SCTX", mScriptText); -} + esm.writeHNOString("SCTX", mScriptText); + } void Script::blank() { diff -Nru openmw-0.35.0/components/esm/loadscpt.hpp openmw-0.35.1/components/esm/loadscpt.hpp --- openmw-0.35.0/components/esm/loadscpt.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadscpt.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -53,6 +53,9 @@ void blank(); ///< Set record to default state (does not touch the ID/index). + +private: + void loadSCVR(ESMReader &esm); }; } #endif diff -Nru openmw-0.35.0/components/esm/loadskil.cpp openmw-0.35.1/components/esm/loadskil.cpp --- openmw-0.35.0/components/esm/loadskil.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadskil.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -129,23 +129,47 @@ unsigned int Skill::sRecordId = REC_SKIL; -void Skill::load(ESMReader &esm) -{ - esm.getHNT(mIndex, "INDX"); - esm.getHNT(mData, "SKDT", 24); - mDescription = esm.getHNOString("DESC"); + void Skill::load(ESMReader &esm) + { + bool hasIndex = false; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'S','K','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasIndex) + esm.fail("Missing INDX"); + if (!hasData) + esm.fail("Missing SKDT"); - // create an ID from the index and the name (only used in the editor and likely to change in the - // future) - mId = indexToId (mIndex); -} + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + mId = indexToId (mIndex); + } -void Skill::save(ESMWriter &esm) const -{ - esm.writeHNT("INDX", mIndex); - esm.writeHNT("SKDT", mData, 24); - esm.writeHNOString("DESC", mDescription); -} + void Skill::save(ESMWriter &esm) const + { + esm.writeHNT("INDX", mIndex); + esm.writeHNT("SKDT", mData, 24); + esm.writeHNOString("DESC", mDescription); + } void Skill::blank() { diff -Nru openmw-0.35.0/components/esm/loadsndg.cpp openmw-0.35.1/components/esm/loadsndg.cpp --- openmw-0.35.0/components/esm/loadsndg.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadsndg.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,19 +8,38 @@ { unsigned int SoundGenerator::sRecordId = REC_SNDG; -void SoundGenerator::load(ESMReader &esm) -{ - esm.getHNT(mType, "DATA", 4); - - mCreature = esm.getHNOString("CNAM"); - mSound = esm.getHNOString("SNAM"); -} -void SoundGenerator::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mType, 4); - esm.writeHNOCString("CNAM", mCreature); - esm.writeHNOCString("SNAM", mSound); -} + void SoundGenerator::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mType, 4); + hasData = true; + break; + case ESM::FourCC<'C','N','A','M'>::value: + mCreature = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + void SoundGenerator::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mType, 4); + esm.writeHNOCString("CNAM", mCreature); + esm.writeHNOCString("SNAM", mSound); + } void SoundGenerator::blank() { diff -Nru openmw-0.35.0/components/esm/loadsoun.cpp openmw-0.35.1/components/esm/loadsoun.cpp --- openmw-0.35.0/components/esm/loadsoun.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadsoun.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,22 +8,35 @@ { unsigned int Sound::sRecordId = REC_SOUN; -void Sound::load(ESMReader &esm) -{ - mSound = esm.getHNOString("FNAM"); - esm.getHNT(mData, "DATA", 3); - /* - cout << "vol=" << (int)data.volume - << " min=" << (int)data.minRange - << " max=" << (int)data.maxRange - << endl; - */ -} -void Sound::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mSound); - esm.writeHNT("DATA", mData, 3); -} + void Sound::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 3); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + + void Sound::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mSound); + esm.writeHNT("DATA", mData, 3); + } void Sound::blank() { diff -Nru openmw-0.35.0/components/esm/loadspel.cpp openmw-0.35.1/components/esm/loadspel.cpp --- openmw-0.35.0/components/esm/loadspel.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadspel.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,19 +8,41 @@ { unsigned int Spell::sRecordId = REC_SPEL; -void Spell::load(ESMReader &esm) -{ - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "SPDT", 12); - mEffects.load(esm); -} + void Spell::load(ESMReader &esm) + { + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t val = esm.retSubName().val; -void Spell::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("SPDT", mData, 12); - mEffects.save(esm); -} + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } + } + if (!hasData) + esm.fail("Missing SPDT subrecord"); + } + + void Spell::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("SPDT", mData, 12); + mEffects.save(esm); + } void Spell::blank() { diff -Nru openmw-0.35.0/components/esm/loadsscr.cpp openmw-0.35.1/components/esm/loadsscr.cpp --- openmw-0.35.0/components/esm/loadsscr.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadsscr.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,15 +8,37 @@ { unsigned int StartScript::sRecordId = REC_SSCR; -void StartScript::load(ESMReader &esm) -{ - mData = esm.getHNString("DATA"); - mScript = esm.getHNString("NAME"); -} -void StartScript::save(ESMWriter &esm) const -{ - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); -} + void StartScript::load(ESMReader &esm) + { + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mScript = esm.getHString(); + hasName = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + if (!hasName) + esm.fail("Missing NAME"); + } + void StartScript::save(ESMWriter &esm) const + { + esm.writeHNString("DATA", mData); + esm.writeHNString("NAME", mScript); + } } diff -Nru openmw-0.35.0/components/esm/loadstat.cpp openmw-0.35.1/components/esm/loadstat.cpp --- openmw-0.35.0/components/esm/loadstat.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadstat.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,15 +8,16 @@ { unsigned int Static::sRecordId = REC_STAT; -void Static::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - mModel = esm.getHNString("MODL"); -} -void Static::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); -} + void Static::load(ESMReader &esm) + { + mPersistent = esm.getRecordFlags() & 0x0400; + + mModel = esm.getHNString("MODL"); + } + void Static::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + } void Static::blank() { diff -Nru openmw-0.35.0/components/esm/loadtes3.hpp openmw-0.35.1/components/esm/loadtes3.hpp --- openmw-0.35.0/components/esm/loadtes3.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadtes3.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -50,8 +50,8 @@ NAME32 mPlayerName; }; GMDT mGameData; // Used in .ess savegames only - std::vector mSCRD; // Used in .ess savegames only, screenshot? - std::vector mSCRS; // Used in .ess savegames only, screenshot? + std::vector mSCRD; // Used in .ess savegames only, unknown + std::vector mSCRS; // Used in .ess savegames only, screenshot Data mData; int mFormat; diff -Nru openmw-0.35.0/components/esm/loadweap.cpp openmw-0.35.1/components/esm/loadweap.cpp --- openmw-0.35.0/components/esm/loadweap.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/loadweap.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -8,24 +8,50 @@ { unsigned int Weapon::sRecordId = REC_WEAP; -void Weapon::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "WPDT", 32); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - mEnchant = esm.getHNOString("ENAM"); -} -void Weapon::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("WPDT", mData, 32); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNOCString("ENAM", mEnchant); -} + void Weapon::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'W','P','D','T'>::value: + esm.getHT(mData, 32); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEnchant = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing WPDT subrecord"); + } + void Weapon::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("WPDT", mData, 32); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNOCString("ENAM", mEnchant); + } void Weapon::blank() { diff -Nru openmw-0.35.0/components/esm/spelllist.cpp openmw-0.35.1/components/esm/spelllist.cpp --- openmw-0.35.0/components/esm/spelllist.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/spelllist.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -5,12 +5,9 @@ namespace ESM { -void SpellList::load(ESMReader &esm) +void SpellList::add(ESMReader &esm) { - mList.clear(); - while (esm.isNextSub("NPCS")) { - mList.push_back(esm.getHString()); - } + mList.push_back(esm.getHString()); } void SpellList::save(ESMWriter &esm) const diff -Nru openmw-0.35.0/components/esm/spelllist.hpp openmw-0.35.1/components/esm/spelllist.hpp --- openmw-0.35.0/components/esm/spelllist.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esm/spelllist.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -11,6 +11,7 @@ /** A list of references to spells and spell effects. This is shared between the records BSGN, NPC and RACE. + NPCS subrecord. */ struct SpellList { @@ -19,7 +20,9 @@ /// Is this spell ID in mList? bool exists(const std::string& spell) const; - void load(ESMReader &esm); + /// Load one spell, assumes the subrecord name was already read + void add(ESMReader &esm); + void save(ESMWriter &esm) const; }; } diff -Nru openmw-0.35.0/components/esm/stolenitems.cpp openmw-0.35.1/components/esm/stolenitems.cpp --- openmw-0.35.0/components/esm/stolenitems.cpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/components/esm/stolenitems.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,47 @@ +#include "stolenitems.hpp" + +#include +#include + +namespace ESM +{ + + void StolenItems::write(ESMWriter &esm) const + { + for (StolenItemsMap::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it) + { + esm.writeHNString("NAME", it->first); + for (std::map, int>::const_iterator ownerIt = it->second.begin(); + ownerIt != it->second.end(); ++ownerIt) + { + if (ownerIt->first.second) + esm.writeHNString("FNAM", ownerIt->first.first); + else + esm.writeHNString("ONAM", ownerIt->first.first); + esm.writeHNT("COUN", ownerIt->second); + } + } + } + + void StolenItems::load(ESMReader &esm) + { + while (esm.isNextSub("NAME")) + { + std::string itemid = esm.getHString(); + + std::map, int> ownerMap; + while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM")) + { + std::string subname = esm.retSubName().toString(); + std::string owner = esm.getHString(); + bool isFaction = (subname == "FNAM"); + int count; + esm.getHNT(count, "COUN"); + ownerMap.insert(std::make_pair(std::make_pair(owner, isFaction), count)); + } + + mStolenItems[itemid] = ownerMap; + } + } + +} diff -Nru openmw-0.35.0/components/esm/stolenitems.hpp openmw-0.35.1/components/esm/stolenitems.hpp --- openmw-0.35.0/components/esm/stolenitems.hpp 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/components/esm/stolenitems.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,24 @@ +#ifndef OPENMW_COMPONENTS_ESM_STOLENITEMS_H +#define OPENMW_COMPONENTS_ESM_STOLENITEMS_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + struct StolenItems + { + typedef std::map, int> > StolenItemsMap; + StolenItemsMap mStolenItems; + + void load(ESM::ESMReader& esm); + void write(ESM::ESMWriter& esm) const; + }; + +} + +#endif diff -Nru openmw-0.35.0/components/esmterrain/storage.cpp openmw-0.35.1/components/esmterrain/storage.cpp --- openmw-0.35.0/components/esmterrain/storage.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/esmterrain/storage.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -383,7 +383,7 @@ int cellY = std::floor(worldPos.y / 8192.f); ESM::Land* land = getLand(cellX, cellY); - if (!land) + if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition @@ -465,8 +465,9 @@ Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) { // Already have this cached? - if (mLayerInfoMap.find(texture) != mLayerInfoMap.end()) - return mLayerInfoMap[texture]; + std::map::iterator found = mLayerInfoMap.find(texture); + if (found != mLayerInfoMap.end()) + return found->second; Terrain::LayerInfo info; info.mParallax = false; diff -Nru openmw-0.35.0/components/files/androidpath.cpp openmw-0.35.1/components/files/androidpath.cpp --- openmw-0.35.0/components/files/androidpath.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/files/androidpath.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -27,7 +27,7 @@ } -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); diff -Nru openmw-0.35.0/components/files/androidpath.h openmw-0.35.1/components/files/androidpath.h --- openmw-0.35.0/components/files/androidpath.h 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/files/androidpath.h 2015-03-12 11:06:00.000000000 +0000 @@ -1,8 +1,8 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include -#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni -#define _Included_org_libsdl_app_SDLActivity_getPathToJni +#ifndef _Included_ui_activity_GameActivity_getPathToJni +#define _Included_ui_activity_GameActivity_getPathToJni #ifdef __cplusplus extern "C" { #endif @@ -11,7 +11,7 @@ * Method: getPathToJni * Signature: (I)I */ -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); #ifdef __cplusplus } diff -Nru openmw-0.35.0/components/nif/.gitignore openmw-0.35.1/components/nif/.gitignore --- openmw-0.35.0/components/nif/.gitignore 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/nif/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -old_d diff -Nru openmw-0.35.0/components/nifbullet/bulletnifloader.cpp openmw-0.35.1/components/nifbullet/bulletnifloader.cpp --- openmw-0.35.0/components/nifbullet/bulletnifloader.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/nifbullet/bulletnifloader.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -274,10 +274,12 @@ // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers) - // Marker objects. These are only visible in the - // editor. + else if (sd->string == "MRK" && !mShowMarkers && raycasting) + { + // Marker objects should be invisible, but still have collision. + // Except in the editor, the marker objects are visible. return; + } } } diff -Nru openmw-0.35.0/components/settings/settings.cpp openmw-0.35.1/components/settings/settings.cpp --- openmw-0.35.0/components/settings/settings.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/settings/settings.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,95 +1,144 @@ #include "settings.hpp" #include -#include -#include -#include #include -#include -#include - -using namespace Settings; +#include +#include +#include -namespace bfs = boost::filesystem; +namespace Settings +{ -Ogre::ConfigFile Manager::mFile = Ogre::ConfigFile(); -Ogre::ConfigFile Manager::mDefaultFile = Ogre::ConfigFile(); +CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); +CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); -CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap(); - -void Manager::loadUser (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mFile.load(stream); -} -void Manager::loadDefault (const std::string& file) -{ - Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); - mDefaultFile.load(stream); -} -void Manager::saveUser(const std::string& file) +class SettingsFileParser { - bfs::ofstream fout((bfs::path(file))); +public: + SettingsFileParser() : mLine(0) {} - Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); - - while (seci.hasMoreElements()) + void loadSettingsFile (const std::string& file, CategorySettingValueMap& settings) { - Ogre::String sectionName = seci.peekNextKey(); + mFile = file; + boost::filesystem::ifstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + mLine = 0; + while (!stream.eof() && !stream.fail()) + { + ++mLine; + std::string line; + std::getline( stream, line ); + + size_t i = 0; + if (!skipWhiteSpace(i, line)) + continue; - if (sectionName.length() > 0) - fout << '\n' << '[' << seci.peekNextKey() << ']' << '\n'; + if (line[i] == '#') // skip comment + continue; - Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); - Ogre::ConfigFile::SettingsMultiMap::iterator i; - for (i = settings->begin(); i != settings->end(); ++i) - { - fout << i->first.c_str() << " = " << i->second.c_str() << '\n'; - } - - CategorySettingValueMap::iterator it = mNewSettings.begin(); - while (it != mNewSettings.end()) - { - if (it->first.first == sectionName) + if (line[i] == '[') { - fout << it->first.second << " = " << it->second << '\n'; - mNewSettings.erase(it++); + size_t end = line.find(']', i); + if (end == std::string::npos) + fail("unterminated category"); + + currentCategory = line.substr(i+1, end - (i+1)); + boost::algorithm::trim(currentCategory); + i = end+1; } - else - ++it; + + if (!skipWhiteSpace(i, line)) + continue; + + if (currentCategory.empty()) + fail("empty category name"); + + size_t settingEnd = line.find('=', i); + if (settingEnd == std::string::npos) + fail("unterminated setting name"); + + std::string setting = line.substr(i, (settingEnd-i)); + boost::algorithm::trim(setting); + + size_t valueBegin = settingEnd+1; + std::string value = line.substr(valueBegin); + boost::algorithm::trim(value); + + if (settings.insert(std::make_pair(std::make_pair(currentCategory, setting), value)).second == false) + fail(std::string("duplicate setting: [" + currentCategory + "] " + setting)); } } - std::string category = ""; - for (CategorySettingValueMap::iterator it = mNewSettings.begin(); - it != mNewSettings.end(); ++it) +private: + /// Increment i until it longer points to a whitespace character + /// in the string or has reached the end of the string. + /// @return false if we have reached the end of the string + bool skipWhiteSpace(size_t& i, std::string& str) { - if (category != it->first.first) + while (i < str.size() && std::isspace(str[i], std::locale::classic())) { - category = it->first.first; - fout << '\n' << '[' << category << ']' << '\n'; + ++i; } - fout << it->first.second << " = " << it->second << '\n'; + return i < str.size(); + } + + void fail(const std::string& message) + { + std::stringstream error; + error << "Error on line " << mLine << " in " << mFile << ":\n" << message; + throw std::runtime_error(error.str()); } - fout.close(); + std::string mFile; + int mLine; +}; + +void Manager::loadDefault(const std::string &file) +{ + SettingsFileParser parser; + parser.loadSettingsFile(file, mDefaultSettings); } -std::string Manager::getString (const std::string& setting, const std::string& category) +void Manager::loadUser(const std::string &file) { - if (mNewSettings.find(std::make_pair(category, setting)) != mNewSettings.end()) - return mNewSettings[std::make_pair(category, setting)]; + SettingsFileParser parser; + parser.loadSettingsFile(file, mUserSettings); +} - std::string defaultval = mDefaultFile.getSetting(setting, category, "NOTFOUND"); - std::string val = mFile.getSetting(setting, category, defaultval); +void Manager::saveUser(const std::string &file) +{ + boost::filesystem::ofstream stream; + stream.open(boost::filesystem::path(file)); + std::string currentCategory; + for (CategorySettingValueMap::iterator it = mUserSettings.begin(); it != mUserSettings.end(); ++it) + { + if (it->first.first != currentCategory) + { + currentCategory = it->first.first; + stream << "\n[" << currentCategory << "]\n"; + } + stream << it->first.second << " = " << it->second << "\n"; + } +} - if (val == "NOTFOUND") - throw std::runtime_error("Trying to retrieve a non-existing setting: " + setting + " Make sure the settings-default.cfg file was properly installed."); - return val; +std::string Manager::getString(const std::string &setting, const std::string &category) +{ + CategorySettingValueMap::key_type key = std::make_pair(category, setting); + CategorySettingValueMap::iterator it = mUserSettings.find(key); + if (it != mUserSettings.end()) + return it->second; + + it = mDefaultSettings.find(key); + if (it != mDefaultSettings.end()) + return it->second; + + throw std::runtime_error(std::string("Trying to retrieve a non-existing setting: ") + setting + + ".\nMake sure the settings-default.cfg file file was properly installed."); } float Manager::getFloat (const std::string& setting, const std::string& category) @@ -107,51 +156,20 @@ return Ogre::StringConverter::parseBool( getString(setting, category) ); } -void Manager::setString (const std::string& setting, const std::string& category, const std::string& value) +void Manager::setString(const std::string &setting, const std::string &category, const std::string &value) { - CategorySetting s = std::make_pair(category, setting); + CategorySettingValueMap::key_type key = std::make_pair(category, setting); - bool found=false; - try + CategorySettingValueMap::iterator found = mUserSettings.find(key); + if (found != mUserSettings.end()) { - Ogre::ConfigFile::SettingsIterator it = mFile.getSettingsIterator(category); - while (it.hasMoreElements()) - { - Ogre::ConfigFile::SettingsMultiMap::iterator i = it.current(); - - if ((*i).first == setting) - { - if ((*i).second != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - (*i).second = value; - } - found = true; - } - - it.getNext(); - } + if (found->second == value) + return; } - catch (Ogre::Exception&) - {} - if (!found) - { - if (mNewSettings.find(s) != mNewSettings.end()) - { - if (mNewSettings[s] != value) - { - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } - else - { - if (mDefaultFile.getSetting(setting, category) != value) - mChangedSettings.push_back(std::make_pair(category, setting)); - mNewSettings[s] = value; - } - } + mUserSettings[key] = value; + + mChangedSettings.insert(key); } void Manager::setInt (const std::string& setting, const std::string& category, const int value) @@ -159,12 +177,12 @@ setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setFloat (const std::string& setting, const std::string& category, const float value) +void Manager::setFloat (const std::string &setting, const std::string &category, const float value) { setString(setting, category, Ogre::StringConverter::toString(value)); } -void Manager::setBool (const std::string& setting, const std::string& category, const bool value) +void Manager::setBool(const std::string &setting, const std::string &category, const bool value) { setString(setting, category, Ogre::StringConverter::toString(value)); } @@ -175,3 +193,5 @@ mChangedSettings.clear(); return vec; } + +} diff -Nru openmw-0.35.0/components/settings/settings.hpp openmw-0.35.1/components/settings/settings.hpp --- openmw-0.35.0/components/settings/settings.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/settings/settings.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,12 +1,14 @@ #ifndef COMPONENTS_SETTINGS_H #define COMPONENTS_SETTINGS_H -#include +#include +#include +#include namespace Settings { typedef std::pair < std::string, std::string > CategorySetting; - typedef std::vector< std::pair > CategorySettingVector; + typedef std::set< std::pair > CategorySettingVector; typedef std::map < CategorySetting, std::string > CategorySettingValueMap; /// @@ -15,15 +17,12 @@ class Manager { public: - static Ogre::ConfigFile mFile; - static Ogre::ConfigFile mDefaultFile; + static CategorySettingValueMap mDefaultSettings; + static CategorySettingValueMap mUserSettings; static CategorySettingVector mChangedSettings; ///< tracks all the settings that were changed since the last apply() call - static CategorySettingValueMap mNewSettings; - ///< tracks all the settings that are in the default file, but not in user file yet - void loadDefault (const std::string& file); ///< load file as the default settings (can be overridden by user settings) diff -Nru openmw-0.35.0/components/terrain/buffercache.cpp openmw-0.35.1/components/terrain/buffercache.cpp --- openmw-0.35.0/components/terrain/buffercache.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/buffercache.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "buffercache.hpp" #include diff -Nru openmw-0.35.0/components/terrain/buffercache.hpp openmw-0.35.1/components/terrain/buffercache.hpp --- openmw-0.35.0/components/terrain/buffercache.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/buffercache.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H #define COMPONENTS_TERRAIN_BUFFERCACHE_H diff -Nru openmw-0.35.0/components/terrain/chunk.cpp openmw-0.35.1/components/terrain/chunk.cpp --- openmw-0.35.0/components/terrain/chunk.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/chunk.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "chunk.hpp" #include diff -Nru openmw-0.35.0/components/terrain/chunk.hpp openmw-0.35.1/components/terrain/chunk.hpp --- openmw-0.35.0/components/terrain/chunk.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/chunk.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINBATCH_H #define COMPONENTS_TERRAIN_TERRAINBATCH_H diff -Nru openmw-0.35.0/components/terrain/defaultworld.cpp openmw-0.35.1/components/terrain/defaultworld.cpp --- openmw-0.35.0/components/terrain/defaultworld.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/defaultworld.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "defaultworld.hpp" #include diff -Nru openmw-0.35.0/components/terrain/defaultworld.hpp openmw-0.35.1/components/terrain/defaultworld.hpp --- openmw-0.35.0/components/terrain/defaultworld.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/defaultworld.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_H #define COMPONENTS_TERRAIN_H diff -Nru openmw-0.35.0/components/terrain/defs.hpp openmw-0.35.1/components/terrain/defs.hpp --- openmw-0.35.0/components/terrain/defs.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/defs.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_DEFS_HPP #define COMPONENTS_TERRAIN_DEFS_HPP diff -Nru openmw-0.35.0/components/terrain/material.cpp openmw-0.35.1/components/terrain/material.cpp --- openmw-0.35.0/components/terrain/material.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/material.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "material.hpp" #include diff -Nru openmw-0.35.0/components/terrain/material.hpp openmw-0.35.1/components/terrain/material.hpp --- openmw-0.35.0/components/terrain/material.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/material.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_MATERIAL_H #define COMPONENTS_TERRAIN_MATERIAL_H diff -Nru openmw-0.35.0/components/terrain/quadtreenode.cpp openmw-0.35.1/components/terrain/quadtreenode.cpp --- openmw-0.35.0/components/terrain/quadtreenode.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/quadtreenode.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "quadtreenode.hpp" #include diff -Nru openmw-0.35.0/components/terrain/quadtreenode.hpp openmw-0.35.1/components/terrain/quadtreenode.hpp --- openmw-0.35.0/components/terrain/quadtreenode.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/quadtreenode.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_QUADTREENODE_H #define COMPONENTS_TERRAIN_QUADTREENODE_H @@ -98,7 +119,6 @@ DefaultWorld* getTerrain() { return mTerrain; } /// Adjust LODs for the given camera position, possibly splitting up chunks or merging them. - /// @param force Always choose to render this node, even if not the perfect LOD. /// @return Did we (or all of our children) choose to render? bool update (const Ogre::Vector3& cameraPos); @@ -124,7 +144,6 @@ /// call this method on their children. /// @note Do not call this before World::areLayersLoaded() == true /// @param area area in image space to put the quad - /// @param quads collect quads here so they can be deleted later void prepareForCompositeMap(Ogre::TRect area); /// Create a chunk for this node from the given data. diff -Nru openmw-0.35.0/components/terrain/storage.cpp openmw-0.35.1/components/terrain/storage.cpp --- openmw-0.35.0/components/terrain/storage.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/storage.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff -Nru openmw-0.35.0/components/terrain/storage.hpp openmw-0.35.1/components/terrain/storage.hpp --- openmw-0.35.0/components/terrain/storage.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/storage.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H diff -Nru openmw-0.35.0/components/terrain/terraingrid.cpp openmw-0.35.1/components/terrain/terraingrid.cpp --- openmw-0.35.0/components/terrain/terraingrid.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/terraingrid.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "terraingrid.hpp" #include diff -Nru openmw-0.35.0/components/terrain/terraingrid.hpp openmw-0.35.1/components/terrain/terraingrid.hpp --- openmw-0.35.0/components/terrain/terraingrid.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/terraingrid.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_TERRAINGRID_H #define COMPONENTS_TERRAIN_TERRAINGRID_H diff -Nru openmw-0.35.0/components/terrain/world.cpp openmw-0.35.1/components/terrain/world.cpp --- openmw-0.35.0/components/terrain/world.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/world.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #include "world.hpp" #include diff -Nru openmw-0.35.0/components/terrain/world.hpp openmw-0.35.1/components/terrain/world.hpp --- openmw-0.35.0/components/terrain/world.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/terrain/world.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef COMPONENTS_TERRAIN_WORLD_H #define COMPONENTS_TERRAIN_WORLD_H diff -Nru openmw-0.35.0/components/widgets/list.cpp openmw-0.35.1/components/widgets/list.cpp --- openmw-0.35.0/components/widgets/list.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/widgets/list.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -152,9 +152,9 @@ eventWidgetSelected(_sender); } - MyGUI::Widget* MWList::getItemWidget(const std::string& name) + MyGUI::Button *MWList::getItemWidget(const std::string& name) { - return mScrollView->findWidget (getName() + "_item_" + name); + return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } } diff -Nru openmw-0.35.0/components/widgets/list.hpp openmw-0.35.1/components/widgets/list.hpp --- openmw-0.35.0/components/widgets/list.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/components/widgets/list.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -43,7 +43,7 @@ std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); - MyGUI::Widget* getItemWidget(const std::string& name); + MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff -Nru openmw-0.35.0/debian/changelog openmw-0.35.1/debian/changelog --- openmw-0.35.0/debian/changelog 2015-02-16 11:07:38.000000000 +0000 +++ openmw-0.35.1/debian/changelog 2015-03-16 09:17:05.000000000 +0000 @@ -1,10 +1,8 @@ -openmw (0.35.0-1~utopic1) utopic; urgency=low +openmw (0.35.1-1~utopic1) utopic; urgency=low - * New release: OpenMW-0.35.0 - * Renamed components to reflect upstream changes. - * Removed system-font patch, we use symlinks now. + * New release: OpenMW-0.35.1 - -- Bret Curtis Thu, 12 Feb 2015 08:14:09 +0200 + -- Bret Curtis Fri, 13 Mar 2015 08:14:09 +0200 openmw (0.35.0-1) experimental; urgency=low diff -Nru openmw-0.35.0/extern/oics/ICSControl.cpp openmw-0.35.1/extern/oics/ICSControl.cpp --- openmw-0.35.0/extern/oics/ICSControl.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/oics/ICSControl.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -43,10 +43,10 @@ , mAxisBindable(axisBindable) , currentChangingDirection(STOP) { - + } - Control::~Control() + Control::~Control() { mAttachedChannels.clear(); } @@ -92,7 +92,7 @@ } void Control::setChangingDirection(ControlChangingDirection direction) - { + { currentChangingDirection = direction; mPendingActions.push_back(direction); } @@ -102,9 +102,9 @@ if(!mPendingActions.empty()) { size_t timedActionsCount = 0; - + std::list::iterator cached_end = mPendingActions.end(); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) @@ -112,14 +112,14 @@ timedActionsCount++; } } - + float timeSinceLastFramePart = timeSinceLastFrame / std::max(1, timedActionsCount); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)(*it)) * mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) @@ -141,7 +141,7 @@ } else if( currentChangingDirection != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)currentChangingDirection) * mStepSize * mStepsPerSeconds * (timeSinceLastFrame))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) diff -Nru openmw-0.35.0/extern/oics/ICSControl.h openmw-0.35.1/extern/oics/ICSControl.h --- openmw-0.35.0/extern/oics/ICSControl.h 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/oics/ICSControl.h 2015-03-12 11:06:00.000000000 +0000 @@ -34,7 +34,7 @@ namespace ICS { - + class DllExport Control { public: @@ -52,9 +52,10 @@ void setValue(float value); inline float getValue(){ return mValue; }; - inline float getInitialValue(){ return mInitialValue; }; + inline float getInitialValue(){ return mInitialValue; }; + inline void setInitialValue(float i) {mInitialValue = i;}; - void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); + void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); std::list getAttachedChannels(){ return mAttachedChannels; }; inline float getStepSize(){ return mStepSize; }; diff -Nru openmw-0.35.0/extern/oics/ICSInputControlSystem.cpp openmw-0.35.1/extern/oics/ICSInputControlSystem.cpp --- openmw-0.35.0/extern/oics/ICSInputControlSystem.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/oics/ICSInputControlSystem.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -60,10 +60,10 @@ xmlDoc = new TiXmlDocument(file.c_str()); xmlDoc->LoadFile(); - if(xmlDoc->Error()) + if(xmlDoc->Error()) { - std::ostringstream message; - message << "TinyXml reported an error reading \""+ file + "\". Row " << + std::ostringstream message; + message << "TinyXml reported an error reading \""+ file + "\". Row " << (int)xmlDoc->ErrorRow() << ", Col " << (int)xmlDoc->ErrorCol() << ": " << xmlDoc->ErrorDesc() ; ICS_LOG(message.str()); @@ -81,10 +81,10 @@ TiXmlElement* xmlControl = xmlRoot->FirstChildElement("Control"); - size_t controlChannelCount = 0; - while(xmlControl) + size_t controlChannelCount = 0; + while(xmlControl) { - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { controlChannelCount = std::max(channelCount, FromString(xmlChannel->Attribute("number"))+1); @@ -111,7 +111,7 @@ // // - TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); + TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); while(xmlChannelFilter) { int ch = FromString(xmlChannelFilter->Attribute("number")); @@ -133,12 +133,12 @@ float step = FromString(xmlInterval->Attribute("step")); ICS_LOG("Applying Bezier filter to channel [number=" - + ToString(ch) + ", startX=" - + ToString(startX) + ", startY=" - + ToString(startY) + ", midX=" - + ToString(midX) + ", midY=" - + ToString(midY) + ", endX=" - + ToString(endX) + ", endY=" + + ToString(ch) + ", startX=" + + ToString(startX) + ", startY=" + + ToString(startY) + ", midX=" + + ToString(midX) + ", midY=" + + ToString(midY) + ", endX=" + + ToString(endX) + ", endY=" + ToString(endY) + ", step=" + ToString(step) + "]"); @@ -152,8 +152,8 @@ xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); } - xmlControl = xmlRoot->FirstChildElement("Control"); - while(xmlControl) + xmlControl = xmlRoot->FirstChildElement("Control"); + while(xmlControl) { bool axisBindable = true; if(xmlControl->Attribute("axisBindable")) @@ -176,11 +176,11 @@ std::string value(xmlControl->Attribute("stepSize")); if(value == "MAX") { - _stepSize = ICS_MAX; + _stepSize = ICS_MAX; } else { - _stepSize = FromString(value.c_str()); + _stepSize = FromString(value.c_str()); } } else @@ -194,7 +194,7 @@ std::string value(xmlControl->Attribute("stepsPerSeconds")); if(value == "MAX") { - _stepsPerSeconds = ICS_MAX; + _stepsPerSeconds = ICS_MAX; } else { @@ -224,12 +224,8 @@ loadJoystickButtonBinders(xmlControl); - loadJoystickPOVBinders(xmlControl); - - loadJoystickSliderBinders(xmlControl); - // Attach controls to channels - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { ICS_LOG("\tAttaching control to channel [number=" @@ -250,7 +246,7 @@ { percentage = val; } - } + } else { ICS_LOG("ERROR: attaching percentage value range is [0,1]"); @@ -338,7 +334,7 @@ for(std::vector::const_iterator o = mChannels.begin() ; o != mChannels.end(); ++o) { ICS::IntervalList intervals = (*o)->getIntervals(); - + if(intervals.size() > 1) // all channels have a default linear filter { TiXmlElement ChannelFilter( "ChannelFilter" ); @@ -371,7 +367,7 @@ ChannelFilter.InsertEndChild(XMLInterval); } - + ++interval; } @@ -401,7 +397,7 @@ control.SetAttribute( "autoReverseToInitialValue", "false" ); } control.SetAttribute( "initialValue", ToString((*o)->getInitialValue()).c_str() ); - + if((*o)->getStepSize() == ICS_MAX) { control.SetAttribute( "stepSize", "MAX" ); @@ -445,12 +441,12 @@ control.InsertEndChild(keyBinder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -469,12 +465,12 @@ control.InsertEndChild(binder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -493,7 +489,7 @@ control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -519,7 +515,7 @@ control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -543,153 +539,72 @@ } binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); - } - - JoystickIDList::const_iterator it = mJoystickIDList.begin(); - while(it != mJoystickIDList.end()) - { - int deviceId = *it; - - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); - - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); - - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); - - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, *it, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); - - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); - - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - ++it; - } + } + JoystickIDList::const_iterator it = mJoystickIDList.begin(); + while(it!=mJoystickIDList.end()) + { + int deviceID = *it; + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); + + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability + + control.InsertEndChild(binder); + } + + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); + + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability + + control.InsertEndChild(binder); + } + + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); + + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability + + control.InsertEndChild(binder); + } + + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); + + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability + + control.InsertEndChild(binder); + } + it++; + } std::list channels = (*o)->getAttachedChannels(); @@ -700,19 +615,19 @@ binder.SetAttribute( "number", ToString((*it)->getNumber()).c_str() ); - Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; + Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; if(direction == Channel/*::ChannelDirection*/::DIRECT) { binder.SetAttribute( "direction", "DIRECT" ); - } + } else { binder.SetAttribute( "direction", "INVERSE" ); } - + float percentage = (*it)->getAttachedControlBinding(*o).percentage; binder.SetAttribute( "percentage", ToString(percentage).c_str() ); - + control.InsertEndChild(binder); } @@ -734,7 +649,7 @@ } } - //! @todo Future versions should consider channel exponentials and mixtures, so + //! @todo Future versions should consider channel exponentials and mixtures, so // after updating Controls, Channels should be updated according to their values } @@ -748,24 +663,6 @@ return mControls[i]->getValue(); } - void InputControlSystem::addJoystick(int deviceId) - { - ICS_LOG("Adding joystick (device id: " + ToString(deviceId) + ")"); - - for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) - { - if(mControlsJoystickAxisBinderMap[deviceId].find(j) == mControlsJoystickAxisBinderMap[deviceId].end()) - { - ControlAxisBinderItem controlJoystickBinderItem; - controlJoystickBinderItem.direction = Control::STOP; - controlJoystickBinderItem.control = NULL; - mControlsJoystickAxisBinderMap[deviceId][j] = controlJoystickBinderItem; - } - } - - mJoystickIDList.push_back(deviceId); - } - Control* InputControlSystem::findControl(std::string name) { if(mActive) diff -Nru openmw-0.35.0/extern/oics/ICSInputControlSystem.h openmw-0.35.1/extern/oics/ICSInputControlSystem.h --- openmw-0.35.0/extern/oics/ICSInputControlSystem.h 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/oics/ICSInputControlSystem.h 2015-03-12 11:06:00.000000000 +0000 @@ -32,7 +32,9 @@ #include "ICSControl.h" #include "ICSChannel.h" -#include "../sdl4ogre/events.h" +#include "../sdl4ogre/events.h" + +#include "boost/lexical_cast.hpp" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 @@ -43,16 +45,16 @@ namespace ICS { - class DllExport InputControlSystemLog + class DllExport InputControlSystemLog { public: virtual void logMessage(const char* text) = 0; }; - class DllExport InputControlSystem : + class DllExport InputControlSystem : public SFO::MouseListener, public SFO::KeyListener, - public SFO::JoyListener + public SFO::ControllerListener { public: @@ -62,6 +64,7 @@ typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions + typedef std::map JoystickInstanceMap; typedef std::list JoystickIDList; typedef struct @@ -72,7 +75,7 @@ InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, size_t channelCount = 16); + , InputControlSystemLog* log = NULL, size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; @@ -98,50 +101,43 @@ inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void addJoystick(int deviceId); - JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; - + void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); + void controllerRemoved(const SDL_ControllerDeviceEvent &args); + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickInstanceMap& getJoystickInstanceMap(){ return mJoystickInstanceMap; }; + // MouseListener void mouseMoved(const SFO::MouseMotionEvent &evt); void mousePressed(const SDL_MouseButtonEvent &evt, Uint8); void mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); - + // KeyListener void keyPressed(const SDL_KeyboardEvent &evt); void keyReleased(const SDL_KeyboardEvent &evt); - - // JoyStickListener - void buttonPressed(const SDL_JoyButtonEvent &evt, int button); - void buttonReleased(const SDL_JoyButtonEvent &evt, int button); - void axisMoved(const SDL_JoyAxisEvent &evt, int axis); - void povMoved(const SDL_JoyHatEvent &evt, int index); - //TODO: does this have an SDL equivalent? - //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); + + // ControllerListener + void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt); + void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt); + void axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); bool isMouseButtonBound(unsigned int button) const; - void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); - void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); - void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); - void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction); void removeKeyBinding(SDL_Scancode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); - void removeJoystickAxisBinding(int deviceId, int axis); - void removeJoystickButtonBinding(int deviceId, unsigned int button); - void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); - void removeJoystickSliderBinding(int deviceId, int index); + void removeJoystickAxisBinding(int deviceID, int axis); + void removeJoystickButtonBinding(int deviceID, unsigned int button); SDL_Scancode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); - int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - unsigned int getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); std::string scancodeToString(SDL_Scancode key); @@ -189,21 +185,15 @@ typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // - typedef std::map ControlsButtonBinderMapType; // - typedef std::map ControlsPOVBinderMapType; // - typedef std::map ControlsSliderBinderMapType; // - - typedef std::map JoystickAxisBinderMapType; // > - typedef std::map JoystickButtonBinderMapType; // > - typedef std::map > JoystickPOVBinderMapType; // > > - typedef std::map JoystickSliderBinderMapType; // > + typedef std::map ControlsButtonBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > + typedef std::map JoystickButtonBinderMapType; // > ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // - JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // > - JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // > - JoystickPOVBinderMapType mControlsJoystickPOVBinderMap; // > > - JoystickSliderBinderMapType mControlsJoystickSliderBinderMap; // > + JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // + JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // std::vector mControls; std::vector mChannels; @@ -212,7 +202,7 @@ bool mActive; InputControlSystemLog* mLog; - + DetectingBindingListener* mDetectingBindingListener; Control* mDetectingBindingControl; Control::ControlChangingDirection mDetectingBindingDirection; @@ -220,7 +210,8 @@ bool mXmouseAxisBinded; bool mYmouseAxisBinded; - JoystickIDList mJoystickIDList; + JoystickIDList mJoystickIDList; + JoystickInstanceMap mJoystickInstanceMap; int mMouseAxisBindingInitialValues[3]; @@ -242,17 +233,12 @@ virtual void mouseButtonBindingDetected(InputControlSystem* ICS, Control* control , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction); - - virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction); + virtual void joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control + , int axis, Control::ControlChangingDirection direction); - virtual void joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction); + virtual void joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control + , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction); }; static const float ICS_MAX = std::numeric_limits::max(); diff -Nru openmw-0.35.0/extern/oics/ICSInputControlSystem_joystick.cpp openmw-0.35.1/extern/oics/ICSInputControlSystem_joystick.cpp --- openmw-0.35.0/extern/oics/ICSInputControlSystem_joystick.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/oics/ICSInputControlSystem_joystick.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -27,14 +27,15 @@ #include "ICSInputControlSystem.h" #define SDL_JOY_AXIS_MIN -32768 -#define SDL_JOY_AXIS_MAX 32767 +#define SDL_JOY_AXIS_MAX 32767 +#define DEADZONE 0.1f namespace ICS { // load xml void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); + TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); while(xmlJoystickBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -47,8 +48,7 @@ dir = Control::DECREASE; } - addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")) - , FromString(xmlJoystickBinder->Attribute("axis")), dir); + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")), FromString(xmlJoystickBinder->Attribute("axis")), dir); xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); } @@ -56,7 +56,7 @@ void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); + TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); while(xmlJoystickButtonBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -69,335 +69,194 @@ dir = Control::DECREASE; } - addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")) - , FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); } } - void InputControlSystem::loadJoystickPOVBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickPOVBinder = xmlControlNode->FirstChildElement("JoystickPOVBinder"); - while(xmlJoystickPOVBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - InputControlSystem::POVAxis axis = /*POVAxis::*/NorthSouth; - if(std::string(xmlJoystickPOVBinder->Attribute("axis")) == "EastWest") - { - axis = /*POVAxis::*/EastWest; - } - - addJoystickPOVBinding(mControls.back(), FromString(xmlJoystickPOVBinder->Attribute("deviceId")) - , FromString(xmlJoystickPOVBinder->Attribute("pov")), axis, dir); - - xmlJoystickPOVBinder = xmlJoystickPOVBinder->NextSiblingElement("JoystickPOVBinder"); - } - } - - void InputControlSystem::loadJoystickSliderBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickSliderBinder = xmlControlNode->FirstChildElement("JoystickSliderBinder"); - while(xmlJoystickSliderBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - addJoystickSliderBinding(mControls.back(), FromString(xmlJoystickSliderBinder->Attribute("deviceId")) - , FromString(xmlJoystickSliderBinder->Attribute("slider")), dir); - - xmlJoystickSliderBinder = xmlJoystickSliderBinder->NextSiblingElement("JoystickSliderBinder"); - } - } - // add bindings - void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding AxisBinder [deviceid=" - + ToString(deviceId) + ", axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); + ICS_LOG("\tAdding AxisBinder [axis=" + + ToString(axis) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); + + control->setValue(0.5f); //all joystick axis start at .5, so do that ControlAxisBinderItem controlAxisBinderItem; controlAxisBinderItem.control = control; controlAxisBinderItem.direction = direction; - mControlsJoystickAxisBinderMap[ deviceId ][ axis ] = controlAxisBinderItem; + mControlsJoystickAxisBinderMap[deviceID][axis] = controlAxisBinderItem; } - void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding JoystickButtonBinder [deviceId=" - + ToString(deviceId) + ", button=" - + ToString(button) + ", direction=" - + ToString(direction) + "]"); + ICS_LOG("\tAdding JoystickButtonBinder [button=" + + ToString(button) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); ControlButtonBinderItem controlJoystickButtonBinderItem; controlJoystickButtonBinderItem.direction = direction; controlJoystickButtonBinderItem.control = control; - mControlsJoystickButtonBinderMap[ deviceId ][ button ] = controlJoystickButtonBinderItem; - } - - void InputControlSystem::addJoystickPOVBinding(Control* control, int deviceId, int index, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickPOVBinder [deviceId=" - + ToString(deviceId) + ", pov=" - + ToString(index) + ", axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); - - ControlPOVBinderItem ControlPOVBinderItem; - ControlPOVBinderItem.direction = direction; - ControlPOVBinderItem.control = control; - mControlsJoystickPOVBinderMap[ deviceId ][ index ][ axis ] = ControlPOVBinderItem; - } - - void InputControlSystem::addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickSliderBinder [deviceId=" - + ToString(deviceId) + ", direction=" - + ToString(index) + ", direction=" - + ToString(direction) + "]"); - - ControlSliderBinderItem ControlSliderBinderItem; - ControlSliderBinderItem.direction = direction; - ControlSliderBinderItem.control = control; - mControlsJoystickSliderBinderMap[ deviceId ][ index ] = ControlSliderBinderItem; + mControlsJoystickButtonBinderMap[deviceID][button] = controlJoystickButtonBinderItem; } // get bindings - int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) - { - ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].begin(); - while(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - if(it->first >= 0 && it->second.control == control && it->second.direction == direction) - { - return it->first; - } + int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].begin(); + while(it != mControlsJoystickAxisBinderMap[deviceID].end()) + { + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } ++it; - } - } + } + } return /*NamedAxis::*/UNASSIGNED; } - unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].begin(); - while(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].begin(); + while(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } ++it; - } - } + } + } return ICS_MAX_DEVICE_BUTTONS; } - InputControlSystem::POVBindingPair InputControlSystem::getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - POVBindingPair result; - result.index = -1; - - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - //ControlsAxisBinderMapType::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - while(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - ControlsPOVBinderMapType::const_iterator it2 = it->second.begin(); - while(it2 != it->second.end()) - { - if(it2->second.control == control && it2->second.direction == direction) - { - result.index = it->first; - result.axis = (POVAxis)it2->first; - return result; - } - it2++; - } - - it++; - } - } - - return result; - } - - int InputControlSystem::getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].begin(); - while(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } - it++; - } - } - - return /*NamedAxis::*/UNASSIGNED; - } - // remove bindings - void InputControlSystem::removeJoystickAxisBinding(int deviceId, int axis) - { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].find(axis); - if(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - mControlsJoystickAxisBinderMap[deviceId].erase(it); - } - } - } - - void InputControlSystem::removeJoystickButtonBinding(int deviceId, unsigned int button) - { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].find(button); - if(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - mControlsJoystickButtonBinderMap[deviceId].erase(it); - } - } - } - - void InputControlSystem::removeJoystickPOVBinding(int deviceId, int index, POVAxis axis) - { - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].find(index); - if(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - if(it->second.find(axis) != it->second.end()) - { - it->second.erase( it->second.find(axis) ); - } - } - } - } - - void InputControlSystem::removeJoystickSliderBinding(int deviceId, int index) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].find(index); - if(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - mControlsJoystickSliderBinderMap[deviceId].erase(it); - } - } + void InputControlSystem::removeJoystickAxisBinding(int deviceID, int axis) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].find(axis); + if(it != mControlsJoystickAxisBinderMap[deviceID].end()) + { + mControlsJoystickAxisBinderMap[deviceID].erase(it); + } + } + } + + void InputControlSystem::removeJoystickButtonBinding(int deviceID, unsigned int button) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].find(button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + mControlsJoystickButtonBinderMap[deviceID].erase(it); + } + } } // joyStick listeners - void InputControlSystem::buttonPressed(const SDL_JoyButtonEvent &evt, int button) + void InputControlSystem::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) { - if(mActive) + if(mActive) { if(!mDetectingBindingControl) - { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - } - else if(mDetectingBindingListener) - { - mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.which, button, mDetectingBindingDirection); + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } } } } - void InputControlSystem::buttonReleased(const SDL_JoyButtonEvent &evt, int button) + void InputControlSystem::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) { if(mActive) - { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + } + else if(mDetectingBindingListener) { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setChangingDirection(Control::STOP); - } + mDetectingBindingListener->joystickButtonBindingDetected(this, deviceID, + mDetectingBindingControl, evt.button, mDetectingBindingDirection); } } } - void InputControlSystem::axisMoved(const SDL_JoyAxisEvent &evt, int axis) + void InputControlSystem::axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt) { if(mActive) { if(!mDetectingBindingControl) - { - if(mControlsJoystickAxisBinderMap.find(evt.which) != mControlsJoystickAxisBinderMap.end()) - { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - - float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; - float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); - - if(joystickBinderItem.direction == Control::INCREASE) - { - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[deviceID][evt.axis]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) + { + ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen + if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center + percent = .5; + else if(percent > .5) + percent -= DEADZONE; + else + percent += DEADZONE; + + if(joystickBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( percent ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - ( percent ) ); + } + } + } } else if(mDetectingBindingListener) { @@ -408,250 +267,76 @@ { if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { - mDetectingBindingListener->joystickAxisBindingDetected(this, - mDetectingBindingControl, evt.which, axis, mDetectingBindingDirection); - } - } - } - } - } - - //Here be dragons, apparently - void InputControlSystem::povMoved(const SDL_JoyHatEvent &evt, int index) - { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickPOVBinderMap.find(evt.which) != mControlsJoystickPOVBinderMap.end()) - { - std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.which ].find(index); - if(i != mControlsJoystickPOVBinderMap[ evt.which ].end()) - { - if(evt.value != SDL_HAT_LEFT - && evt.value != SDL_HAT_RIGHT - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_LEFTUP - || evt.value == SDL_HAT_RIGHTUP) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value != SDL_HAT_UP - && evt.value != SDL_HAT_DOWN - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_RIGHTUP - || evt.value == SDL_HAT_RIGHTDOWN) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value == SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - - it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_DOWN) - { - POVAxis povAxis = NorthSouth; - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT) - { - povAxis = EastWest; - } - - mDetectingBindingListener->joystickPOVBindingDetected(this, - mDetectingBindingControl, evt.which, index, povAxis, mDetectingBindingDirection); - } - } - } - } - } - - //TODO: does this have an SDL equivalent? - /* - void InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) - { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) - { - ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - if(joystickBinderItem.direction == Control::INCREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)( evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)(evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN) - { - mDetectingBindingListener->joystickSliderBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), index, mDetectingBindingDirection); + mDetectingBindingListener->joystickAxisBindingDetected(this, deviceID, + mDetectingBindingControl, evt.axis, mDetectingBindingDirection); } } } } + } + + void InputControlSystem::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &args) + { + ICS_LOG("Adding joystick (index: " + ToString(args.which) + ")"); + SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); + int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); + if(std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID)==mJoystickIDList.end()) + { + for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) + { + if(mControlsJoystickAxisBinderMap[deviceID].find(j) == mControlsJoystickAxisBinderMap[deviceID].end()) + { + ControlAxisBinderItem controlJoystickBinderItem; + controlJoystickBinderItem.direction = Control::STOP; + controlJoystickBinderItem.control = NULL; + mControlsJoystickAxisBinderMap[deviceID][j] = controlJoystickBinderItem; + } + } + mJoystickIDList.push_front(deviceID); + } + + mJoystickInstanceMap[instanceID] = cntrl; + } + void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) + { + ICS_LOG("Removing joystick (instance id: " + ToString(args.which) + ")"); + if(mJoystickInstanceMap.count(args.which)!=0) + { + SDL_GameControllerClose(mJoystickInstanceMap.at(args.which)); + mJoystickInstanceMap.erase(args.which); + } } - */ // joystick auto bindings - void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control, int axis, Control::ControlChangingDirection direction) { // if the joystick axis is used by another control, remove it - ICS->removeJoystickAxisBinding(deviceId, axis); + ICS->removeJoystickAxisBinding(deviceID, axis); // if the control has an axis assigned, remove it - int oldAxis = ICS->getJoystickAxisBinding(control, deviceId, direction); - if(oldAxis != InputControlSystem::UNASSIGNED) + int oldAxis = ICS->getJoystickAxisBinding(control, deviceID, direction); + if(oldAxis != InputControlSystem::UNASSIGNED) { - ICS->removeJoystickAxisBinding(deviceId, oldAxis); + ICS->removeJoystickAxisBinding(deviceID, oldAxis); } - ICS->addJoystickAxisBinding(control, deviceId, axis, direction); + ICS->addJoystickAxisBinding(control, deviceID, axis, direction); ICS->cancelDetectingBindingState(); } - void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control + , unsigned int button, Control::ControlChangingDirection direction) { // if the joystick button is used by another control, remove it - ICS->removeJoystickButtonBinding(deviceId, button); + ICS->removeJoystickButtonBinding(deviceID, button); // if the control has a joystick button assigned, remove it - unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceId, direction); + unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceID, direction); if(oldButton != ICS_MAX_DEVICE_BUTTONS) { - ICS->removeJoystickButtonBinding(deviceId, oldButton); - } - - ICS->addJoystickButtonBinding(control, deviceId, button, direction); - ICS->cancelDetectingBindingState(); - } - - - void DetectingBindingListener::joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickPOVBinding(deviceId, pov, axis); - - // if the control has a joystick button assigned, remove it - ICS::InputControlSystem::POVBindingPair oldPOV = ICS->getJoystickPOVBinding(control, deviceId, direction); - if(oldPOV.index >= 0 && oldPOV.axis == axis) - { - ICS->removeJoystickPOVBinding(deviceId, oldPOV.index, oldPOV.axis); - } - - ICS->addJoystickPOVBinding(control, deviceId, pov, axis, direction); - ICS->cancelDetectingBindingState(); - } - - void DetectingBindingListener::joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickSliderBinding(deviceId, slider); - - // if the control has a joystick slider assigned, remove it - int oldSlider = ICS->getJoystickSliderBinding(control, deviceId, direction); - if(oldSlider != InputControlSystem::/*NamedAxis::*/UNASSIGNED) - { - ICS->removeJoystickSliderBinding(deviceId, oldSlider); + ICS->removeJoystickButtonBinding(deviceID, oldButton); } - ICS->addJoystickSliderBinding(control, deviceId, slider, direction); + ICS->addJoystickButtonBinding(control, deviceID, button, direction); ICS->cancelDetectingBindingState(); } } diff -Nru openmw-0.35.0/extern/sdl4ogre/events.h openmw-0.35.1/extern/sdl4ogre/events.h --- openmw-0.35.0/extern/sdl4ogre/events.h 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/sdl4ogre/events.h 2015-03-12 11:06:00.000000000 +0000 @@ -1,8 +1,8 @@ #ifndef _SFO_EVENTS_H #define _SFO_EVENTS_H -#include - +#include +#include //////////// // Events // @@ -40,23 +40,25 @@ virtual void keyReleased(const SDL_KeyboardEvent &arg) = 0; }; -class JoyListener +class ControllerListener { public: - virtual ~JoyListener() {} + virtual ~ControllerListener() {} /** @remarks Joystick button down event */ - virtual void buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick button up event */ - virtual void buttonReleased( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick axis moved event */ - virtual void axisMoved( const SDL_JoyAxisEvent &arg, int axis ) = 0; + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg) = 0; + + /** @remarks Joystick Added **/ + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) = 0; - //-- Not so common control events, so are not required --// + /** @remarks Joystick Removed **/ + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg) = 0; - //! Joystick Event, and povID - virtual void povMoved( const SDL_JoyHatEvent &arg, int index) {} }; class WindowListener @@ -65,7 +67,7 @@ virtual ~WindowListener() {} /** @remarks The window's visibility changed */ - virtual void windowVisibilityChange( bool visible ) {}; + virtual void windowVisibilityChange( bool visible ) {} /** @remarks The window got / lost input focus */ virtual void windowFocusChange( bool have_focus ) {} diff -Nru openmw-0.35.0/extern/sdl4ogre/sdlcursormanager.cpp openmw-0.35.1/extern/sdl4ogre/sdlcursormanager.cpp --- openmw-0.35.0/extern/sdl4ogre/sdlcursormanager.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/sdl4ogre/sdlcursormanager.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -4,6 +4,9 @@ #include #include +#include +#include + #include namespace SFO diff -Nru openmw-0.35.0/extern/sdl4ogre/sdlcursormanager.hpp openmw-0.35.1/extern/sdl4ogre/sdlcursormanager.hpp --- openmw-0.35.0/extern/sdl4ogre/sdlcursormanager.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/sdl4ogre/sdlcursormanager.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -1,11 +1,12 @@ #ifndef SDL4OGRE_CURSORMANAGER_H #define SDL4OGRE_CURSORMANAGER_H -#include - #include "cursormanager.hpp" #include +struct SDL_Cursor; +struct SDL_Surface; + namespace SFO { class SDLCursorManager : diff -Nru openmw-0.35.0/extern/sdl4ogre/sdlinputwrapper.cpp openmw-0.35.1/extern/sdl4ogre/sdlinputwrapper.cpp --- openmw-0.35.0/extern/sdl4ogre/sdlinputwrapper.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/sdl4ogre/sdlinputwrapper.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -20,7 +20,7 @@ mMouseY(0), mMouseX(0), mMouseInWindow(true), - mJoyListener(NULL), + mConListener(NULL), mKeyboardListener(NULL), mMouseListener(NULL), mWindowListener(NULL), @@ -91,24 +91,32 @@ case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; + case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: - if (mJoyListener) - mJoyListener->axisMoved(evt.jaxis, evt.jaxis.axis); - break; case SDL_JOYBUTTONDOWN: - if (mJoyListener) - mJoyListener->buttonPressed(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYBUTTONUP: - if (mJoyListener) - mJoyListener->buttonReleased(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYDEVICEADDED: - //SDL_JoystickOpen(evt.jdevice.which); - //std::cout << "Detected a new joystick: " << SDL_JoystickNameForIndex(evt.jdevice.which) << std::endl; - break; case SDL_JOYDEVICEREMOVED: - //std::cout << "A joystick has been removed" << std::endl; + break; + case SDL_CONTROLLERDEVICEADDED: + if(mConListener) + mConListener->controllerAdded(1, evt.cdevice); //We only support one joystick, so give everything a generic deviceID + break; + case SDL_CONTROLLERDEVICEREMOVED: + if(mConListener) + mConListener->controllerRemoved(evt.cdevice); + break; + case SDL_CONTROLLERBUTTONDOWN: + if(mConListener) + mConListener->buttonPressed(1, evt.cbutton); + break; + case SDL_CONTROLLERBUTTONUP: + if(mConListener) + mConListener->buttonReleased(1, evt.cbutton); + break; + case SDL_CONTROLLERAXISMOTION: + if(mConListener) + mConListener->axisMoved(1, evt.caxis); break; case SDL_WINDOWEVENT: handleWindowEvent(evt); diff -Nru openmw-0.35.0/extern/sdl4ogre/sdlinputwrapper.hpp openmw-0.35.1/extern/sdl4ogre/sdlinputwrapper.hpp --- openmw-0.35.0/extern/sdl4ogre/sdlinputwrapper.hpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/extern/sdl4ogre/sdlinputwrapper.hpp 2015-03-12 11:06:00.000000000 +0000 @@ -24,7 +24,7 @@ void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } - void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; } + void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); bool isModifierHeld(SDL_Keymod mod); @@ -54,7 +54,7 @@ SFO::MouseListener* mMouseListener; SFO::KeyListener* mKeyboardListener; SFO::WindowListener* mWindowListener; - SFO::JoyListener* mJoyListener; + SFO::ControllerListener* mConListener; typedef boost::unordered_map KeyMap; KeyMap mKeyMap; diff -Nru openmw-0.35.0/files/gamecontrollerdb.txt openmw-0.35.1/files/gamecontrollerdb.txt --- openmw-0.35.0/files/gamecontrollerdb.txt 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/files/gamecontrollerdb.txt 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,101 @@ +# from https://github.com/gabomdq/SDL_GameControllerDB +# License: +# Simple DirectMedia Layer +# Copyright (C) 1997-2013 Sam Lantinga +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. + +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,Platform:Mac OS X, +5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8tart:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, diff -Nru openmw-0.35.0/files/materials/atmosphere.shader openmw-0.35.1/files/materials/atmosphere.shader --- openmw-0.35.0/files/materials/atmosphere.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/atmosphere.shader 2015-03-12 11:06:00.000000000 +0000 @@ -11,7 +11,7 @@ SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff -Nru openmw-0.35.0/files/materials/clouds.shader openmw-0.35.1/files/materials/clouds.shader --- openmw-0.35.0/files/materials/clouds.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/clouds.shader 2015-03-12 11:06:00.000000000 +0000 @@ -13,7 +13,7 @@ { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff -Nru openmw-0.35.0/files/materials/moon.shader openmw-0.35.1/files/materials/moon.shader --- openmw-0.35.0/files/materials/moon.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/moon.shader 2015-03-12 11:06:00.000000000 +0000 @@ -12,7 +12,7 @@ SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff -Nru openmw-0.35.0/files/materials/objects.shader openmw-0.35.1/files/materials/objects.shader --- openmw-0.35.0/files/materials/objects.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/objects.shader 2015-03-12 11:06:00.000000000 +0000 @@ -166,7 +166,7 @@ #if VIEWPROJ_FIX float4x4 vpFixed = vpMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; @@ -243,7 +243,9 @@ } #else - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose( mat3 m); +#endif // ----------------------------------- FRAGMENT ------------------------------------------ #if UNDERWATER @@ -376,13 +378,13 @@ float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2 - 1 )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - 1.0 )); #endif #if ENV_MAP || SPECULAR || PARALLAX @@ -576,5 +578,14 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); } +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff -Nru openmw-0.35.0/files/materials/ripples.particle openmw-0.35.1/files/materials/ripples.particle --- openmw-0.35.0/files/materials/ripples.particle 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/ripples.particle 2015-03-12 11:06:00.000000000 +0000 @@ -1,8 +1,8 @@ particle_system openmw/Ripples { material openmw/Ripple - particle_width 50 - particle_height 50 + particle_width 30 + particle_height 30 // To make the particles move with the scene node when the waterlevel changes local_space true quota 300 @@ -17,7 +17,7 @@ affector Scaler { - rate 100 + rate 120 } affector Rotator diff -Nru openmw-0.35.0/files/materials/stars.shader openmw-0.35.1/files/materials/stars.shader --- openmw-0.35.0/files/materials/stars.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/stars.shader 2015-03-12 11:06:00.000000000 +0000 @@ -13,7 +13,7 @@ SH_START_PROGRAM { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff -Nru openmw-0.35.0/files/materials/sun.shader openmw-0.35.1/files/materials/sun.shader --- openmw-0.35.0/files/materials/sun.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/sun.shader 2015-03-12 11:06:00.000000000 +0000 @@ -12,7 +12,7 @@ SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff -Nru openmw-0.35.0/files/materials/terrain.shader openmw-0.35.1/files/materials/terrain.shader --- openmw-0.35.0/files/materials/terrain.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/terrain.shader 2015-03-12 11:06:00.000000000 +0000 @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2015 scrawl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "core.h" #define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) @@ -114,7 +136,7 @@ #if NEED_DEPTH #if VIEWPROJ_FIX float4x4 vpFixed = viewProjMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; @@ -199,6 +221,9 @@ #if UNDERWATER #include "underwater.h" #endif +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m); +#endif SH_BEGIN_PROGRAM @@ -297,7 +322,7 @@ // derive final matrix float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif #endif @@ -470,5 +495,13 @@ shOutputColour(0).a = 1.0-previousAlpha; #endif } - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff -Nru openmw-0.35.0/files/materials/underwater.h openmw-0.35.1/files/materials/underwater.h --- openmw-0.35.0/files/materials/underwater.h 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/underwater.h 2015-03-12 11:06:00.000000000 +0000 @@ -93,7 +93,7 @@ // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2.0 - 1.0; causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); @@ -111,7 +111,7 @@ //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; - caustics *= 3; + caustics *= 3.0; // shore transition caustics = shLerp (float3(1,1,1), caustics, waterDepth); diff -Nru openmw-0.35.0/files/materials/water.shader openmw-0.35.1/files/materials/water.shader --- openmw-0.35.0/files/materials/water.shader 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/materials/water.shader 2015-03-12 11:06:00.000000000 +0000 @@ -4,7 +4,7 @@ #define SIMPLE_WATER @shGlobalSettingBool(simple_water) #if SIMPLE_WATER - // --------------------------------------- SIMPLE WATER --------------------------------------------------- + // --------------------------------------- SIMPLE WATER --------------------------------------------------- #define FOG @shGlobalSettingBool(fog) @@ -42,7 +42,7 @@ { shOutputColour(0).xyz = shSample(animatedTexture, UV * float2(15.0, 15.0)).xyz * float3(1.0, 1.0, 1.0); shOutputColour(0).w = 0.7; - + #if FOG float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); @@ -70,7 +70,7 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - + shOutput(float3, screenCoordsPassthrough) shOutput(float4, position) shOutput(float, depthPassthrough) @@ -95,25 +95,25 @@ SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - - - #if !SH_GLSL + + + #if !SH_GLSL && !SH_GLSLES float4x4 scalemat = float4x4( 0.5, 0.0, 0.0, 0.5, 0.0, -0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 ); - #else - mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, + #else + mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0); #endif - + float4 texcoordProj = shMatrixMult(scalemat, shOutputPosition); screenCoordsPassthrough = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); - + position = shInputPosition; - + depthPassthrough = shOutputPosition.z; @@ -134,29 +134,28 @@ #define VISIBILITY 1500.0 // how far you can look through water - #define BIG_WAVES_X 0.3 // strength of big waves - #define BIG_WAVES_Y 0.3 - - #define MID_WAVES_X 0.3 // strength of middle sized waves - #define MID_WAVES_Y 0.15 - - #define SMALL_WAVES_X 0.15 // strength of small waves - #define SMALL_WAVES_Y 0.1 - - #define WAVE_CHOPPYNESS 0.15 // wave choppyness - #define WAVE_SCALE 75.0 // overall wave scale + #define BIG_WAVES_X 0.1 // strength of big waves + #define BIG_WAVES_Y 0.1 + + #define MID_WAVES_X 0.1 // strength of middle sized waves + #define MID_WAVES_Y 0.1 + + #define SMALL_WAVES_X 0.1 // strength of small waves + #define SMALL_WAVES_Y 0.1 - #define BUMP 1.5 // overall water surface bumpiness - #define REFL_BUMP 0.08 // reflection distortion amount + #define WAVE_CHOPPYNESS 0.05 // wave choppyness + #define WAVE_SCALE 75.0 // overall wave scale + + #define BUMP 0.5 // overall water surface bumpiness + #define REFL_BUMP 0.15 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount #define SCATTER_AMOUNT 0.3 // amount of sunlight scattering #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering - #define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction - - #define SPEC_HARDNESS 256.0 // specular highlights hardness - + #define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction + + #define SPEC_HARDNESS 256.0 // specular highlights hardness // --------------------------------------------------------------- @@ -186,9 +185,9 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) - + shUniform(float, far) @shAutoConstant(far, far_clip_distance) - + shSampler2D(reflectionMap) #if REFRACTION shSampler2D(refractionMap) @@ -197,23 +196,22 @@ shSampler2D(normalMap) shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z #define WIND_DIR windDir_windSpeed.xy - + shUniform(float, waterTimer) @shSharedParameter(waterTimer) shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) - + shUniform(float4, sunPosition) @shAutoConstant(sunPosition, light_position, 0) shUniform(float4, sunSpecular) @shAutoConstant(sunSpecular, light_specular_colour, 0) - + shUniform(float, renderTargetFlipping) @shAutoConstant(renderTargetFlipping, render_target_flipping) - - + + shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) - + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position_object_space) @@ -234,7 +232,7 @@ #if SHADOWS || SHADOWS_PSSM shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) #endif - + SH_START_PROGRAM { @@ -269,19 +267,19 @@ float3 normal0 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; float3 normal1 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; - + nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; float3 normal2 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; float3 normal3 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; - + nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; - float3 normal4 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; + float3 normal4 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; float3 normal5 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - + + float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); @@ -289,25 +287,25 @@ normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); - // normal for sunlight scattering + // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = float3(lNormal.x, lNormal.y, -lNormal.z); - + float3 lVec = normalize(sunPosition.xyz); float3 vVec = normalize(position.xyz - cameraPos.xyz); - - + + float isUnderwater = (cameraPos.z > 0.0) ? 0.0 : 1.0; - + // sunlight scattering float3 pNormal = float3(0,0,1); float3 lR = reflect(lVec, lNormal); float3 llR = reflect(lVec, pNormal); - + float s = shSaturate(dot(lR, vVec)*2.0-1.2); float lightScatter = shadow * shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); @@ -315,12 +313,12 @@ // fresnel float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air float fresnel = fresnel_dielectric(-vVec, normal, ior); - + fresnel = shSaturate(fresnel); - + // reflection float3 reflection = shSample(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; - + // refraction float3 R = reflect(vVec, normal); diff -Nru openmw-0.35.0/files/mygui/CMakeLists.txt openmw-0.35.1/files/mygui/CMakeLists.txt --- openmw-0.35.0/files/mygui/CMakeLists.txt 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/CMakeLists.txt 2015-03-12 11:06:00.000000000 +0000 @@ -86,6 +86,7 @@ openmw_edit_note.layout openmw_debug_window.layout openmw_debug_window.skin.xml + openmw_jail_screen.layout DejaVuLGCSansMono.ttf ../launcher/images/openmw.png OpenMWResourcePlugin.xml diff -Nru openmw-0.35.0/files/mygui/openmw_enchanting_dialog.layout openmw-0.35.1/files/mygui/openmw_enchanting_dialog.layout --- openmw-0.35.0/files/mygui/openmw_enchanting_dialog.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_enchanting_dialog.layout 2015-03-12 11:06:00.000000000 +0000 @@ -117,7 +117,7 @@ - + @@ -141,8 +141,6 @@ - - diff -Nru openmw-0.35.0/files/mygui/openmw_hud.layout openmw-0.35.1/files/mygui/openmw_hud.layout --- openmw-0.35.0/files/mygui/openmw_hud.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_hud.layout 2015-03-12 11:06:00.000000000 +0000 @@ -112,7 +112,8 @@ - + + @@ -126,35 +127,35 @@ - + - + - + - + - - + + - - + + - + diff -Nru openmw-0.35.0/files/mygui/openmw_jail_screen.layout openmw-0.35.1/files/mygui/openmw_jail_screen.layout --- openmw-0.35.0/files/mygui/openmw_jail_screen.layout 1970-01-01 00:00:00.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_jail_screen.layout 2015-03-12 11:06:00.000000000 +0000 @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff -Nru openmw-0.35.0/files/mygui/openmw_journal.skin.xml openmw-0.35.1/files/mygui/openmw_journal.skin.xml --- openmw-0.35.0/files/mygui/openmw_journal.skin.xml 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_journal.skin.xml 2015-03-12 11:06:00.000000000 +0000 @@ -28,9 +28,9 @@ - - - + + + diff -Nru openmw-0.35.0/files/mygui/openmw_levelup_dialog.layout openmw-0.35.1/files/mygui/openmw_levelup_dialog.layout --- openmw-0.35.0/files/mygui/openmw_levelup_dialog.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_levelup_dialog.layout 2015-03-12 11:06:00.000000000 +0000 @@ -50,7 +50,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + diff -Nru openmw-0.35.0/files/mygui/openmw_loading_screen.layout openmw-0.35.1/files/mygui/openmw_loading_screen.layout --- openmw-0.35.0/files/mygui/openmw_loading_screen.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_loading_screen.layout 2015-03-12 11:06:00.000000000 +0000 @@ -10,7 +10,7 @@ - + diff -Nru openmw-0.35.0/files/mygui/openmw_merchantrepair.layout openmw-0.35.1/files/mygui/openmw_merchantrepair.layout --- openmw-0.35.0/files/mygui/openmw_merchantrepair.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_merchantrepair.layout 2015-03-12 11:06:00.000000000 +0000 @@ -4,7 +4,6 @@ - @@ -20,10 +19,10 @@ - + - + diff -Nru openmw-0.35.0/files/mygui/openmw_persuasion_dialog.layout openmw-0.35.1/files/mygui/openmw_persuasion_dialog.layout --- openmw-0.35.0/files/mygui/openmw_persuasion_dialog.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_persuasion_dialog.layout 2015-03-12 11:06:00.000000000 +0000 @@ -1,17 +1,13 @@ - + - + - - - - @@ -39,7 +35,11 @@ - + + + + + diff -Nru openmw-0.35.0/files/mygui/openmw_settings_window.layout openmw-0.35.1/files/mygui/openmw_settings_window.layout --- openmw-0.35.0/files/mygui/openmw_settings_window.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_settings_window.layout 2015-03-12 11:06:00.000000000 +0000 @@ -4,7 +4,7 @@ - + @@ -172,15 +172,21 @@ - + + + + + + + - + - + @@ -190,10 +196,10 @@ - + - + @@ -203,11 +209,11 @@ - + - + diff -Nru openmw-0.35.0/files/mygui/openmw_spell_buying_window.layout openmw-0.35.1/files/mygui/openmw_spell_buying_window.layout --- openmw-0.35.0/files/mygui/openmw_spell_buying_window.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_spell_buying_window.layout 2015-03-12 11:06:00.000000000 +0000 @@ -1,10 +1,9 @@ - + - @@ -14,14 +13,12 @@ - - diff -Nru openmw-0.35.0/files/mygui/openmw_spellcreation_dialog.layout openmw-0.35.1/files/mygui/openmw_spellcreation_dialog.layout --- openmw-0.35.0/files/mygui/openmw_spellcreation_dialog.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_spellcreation_dialog.layout 2015-03-12 11:06:00.000000000 +0000 @@ -1,10 +1,9 @@ - + - @@ -16,9 +15,7 @@ - - - + @@ -33,7 +30,6 @@ - @@ -46,7 +42,6 @@ - @@ -70,7 +65,7 @@ - + diff -Nru openmw-0.35.0/files/mygui/openmw_stats_window.layout openmw-0.35.1/files/mygui/openmw_stats_window.layout --- openmw-0.35.0/files/mygui/openmw_stats_window.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_stats_window.layout 2015-03-12 11:06:00.000000000 +0000 @@ -235,7 +235,9 @@ - + + + diff -Nru openmw-0.35.0/files/mygui/openmw_text.skin.xml openmw-0.35.1/files/mygui/openmw_text.skin.xml --- openmw-0.35.0/files/mygui/openmw_text.skin.xml 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_text.skin.xml 2015-03-12 11:06:00.000000000 +0000 @@ -19,9 +19,11 @@ - + + + diff -Nru openmw-0.35.0/files/mygui/openmw_travel_window.layout openmw-0.35.1/files/mygui/openmw_travel_window.layout --- openmw-0.35.0/files/mygui/openmw_travel_window.layout 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/mygui/openmw_travel_window.layout 2015-03-12 11:06:00.000000000 +0000 @@ -1,10 +1,9 @@ - + - @@ -21,11 +20,10 @@ - - + diff -Nru openmw-0.35.0/files/settings-default.cfg openmw-0.35.1/files/settings-default.cfg --- openmw-0.35.0/files/settings-default.cfg 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/settings-default.cfg 2015-03-12 11:06:00.000000000 +0000 @@ -173,9 +173,9 @@ # Volumes. master volume affects all other volumes. master volume = 1.0 sfx volume = 1.0 -music volume = 0.4 -footsteps volume = 0.15 -voice volume = 1.0 +music volume = 0.5 +footsteps volume = 0.2 +voice volume = 0.8 [Input] diff -Nru openmw-0.35.0/files/ui/settingspage.ui openmw-0.35.1/files/ui/settingspage.ui --- openmw-0.35.0/files/ui/settingspage.ui 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/files/ui/settingspage.ui 2015-03-12 11:06:00.000000000 +0000 @@ -131,6 +131,13 @@ + + + + 4 + + + diff -Nru openmw-0.35.0/libs/openengine/bullet/physic.cpp openmw-0.35.1/libs/openengine/bullet/physic.cpp --- openmw-0.35.0/libs/openengine/bullet/physic.cpp 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/libs/openengine/bullet/physic.cpp 2015-03-12 11:06:00.000000000 +0000 @@ -414,13 +414,17 @@ + boost::lexical_cast(x) + "_" + boost::lexical_cast(y); - HeightField hf = mHeightFieldMap [name]; + HeightFieldContainer::iterator it = mHeightFieldMap.find(name); + if (it == mHeightFieldMap.end()) + return; + + const HeightField& hf = it->second; mDynamicsWorld->removeRigidBody(hf.mBody); delete hf.mShape; delete hf.mBody; - mHeightFieldMap.erase(name); + mHeightFieldMap.erase(it); } void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, diff -Nru openmw-0.35.0/README.md openmw-0.35.1/README.md --- openmw-0.35.0/README.md 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/README.md 2015-03-12 11:06:00.000000000 +0000 @@ -1,12 +1,12 @@ OpenMW ====== -[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) +[![Build Status](https://img.shields.io/travis/OpenMW/openmw.svg?style=plastic)](https://travis-ci.org/OpenMW/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740) OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -* Version: 0.35.0 +* Version: 0.35.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -69,6 +69,9 @@ --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting --load-savegame arg load a save game file on game startup + (specify an absolute filename or a + filename relative to the current + working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) diff -Nru openmw-0.35.0/.travis.yml openmw-0.35.1/.travis.yml --- openmw-0.35.0/.travis.yml 2015-02-16 10:07:57.000000000 +0000 +++ openmw-0.35.1/.travis.yml 2015-03-12 11:06:00.000000000 +0000 @@ -31,6 +31,7 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: