diff --git a/CMakeLists.txt b/CMakeLists.txt index 338a5e7e7..e8152f2f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 12) +set (OPENMW_VERSION_MINOR 13) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -185,6 +185,11 @@ endif (APPLE) # Dependencies +# Fix for not visible pthreads functions for linker with glibc 2.15 +if (UNIX AND NOT APPLE) +find_package (Threads) +endif() + find_package(OGRE REQUIRED) find_package(MyGUI REQUIRED) find_package(Boost REQUIRED COMPONENTS system filesystem program_options thread) @@ -315,7 +320,7 @@ if(DPKG_PROGRAM) SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher") - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libogre-1.7.3 (>= 1.7.3), libbullet0 (>= 2.77), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "nvidia-cg-toolkit (>= 2.1), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") @@ -451,7 +456,9 @@ if (WIN32) endforeach(d) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) - set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) + if (BUILD_LAUNCHER) + set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif(MSVC) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 054cbf141..c96fc2c7b 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -222,7 +222,7 @@ void DataFilesPage::setupDataFiles() QMessageBox msgBox; msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Critical); + msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Cancel); msgBox.setText(tr("
Could not find the Data Files location

\ The directory containing the Data Files was not found.

\ @@ -279,72 +279,79 @@ void DataFilesPage::setupDataFiles() const Files::MultiDirCollection &esp = fileCollections.getCollection(".esp"); for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter) { - ESMReader fileReader; - QStringList availableMasters; // Will contain all found masters - fileReader.setEncoding(variables["encoding"].as()); - fileReader.open(iter->second.string()); + try { + ESMReader fileReader; + QStringList availableMasters; // Will contain all found masters + + fileReader.setEncoding(variables["encoding"].as()); + fileReader.open(iter->second.string()); - // First we fill the availableMasters and the mMastersWidget - ESMReader::MasterList mlist = fileReader.getMasters(); + // First we fill the availableMasters and the mMastersWidget + ESMReader::MasterList mlist = fileReader.getMasters(); - for (unsigned int i = 0; i < mlist.size(); ++i) { - const QString currentMaster = QString::fromStdString(mlist[i].name); - availableMasters.append(currentMaster); + for (unsigned int i = 0; i < mlist.size(); ++i) { + const QString currentMaster = QString::fromStdString(mlist[i].name); + availableMasters.append(currentMaster); - const QList itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly); + const QList itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly); - if (itemList.isEmpty()) { // Master is not yet in the widget - mMastersWidget->insertRow(i); + if (itemList.isEmpty()) { // Master is not yet in the widget + mMastersWidget->insertRow(i); - QTableWidgetItem *item = new QTableWidgetItem(currentMaster); - item->setForeground(Qt::red); - item->setFlags(item->flags() & ~(Qt::ItemIsSelectable)); + QTableWidgetItem *item = new QTableWidgetItem(currentMaster); + item->setForeground(Qt::red); + item->setFlags(item->flags() & ~(Qt::ItemIsSelectable)); - mMastersWidget->setItem(i, 0, item); + mMastersWidget->setItem(i, 0, item); + } } - } - availableMasters.sort(); // Sort the masters alphabetically + availableMasters.sort(); // Sort the masters alphabetically - // Now we put the current plugin in the mDataFilesModel under its masters - QStandardItem *parent = new QStandardItem(availableMasters.join(",")); + // Now we put the current plugin in the mDataFilesModel under its masters + QStandardItem *parent = new QStandardItem(availableMasters.join(",")); - QString fileName = QString::fromStdString(boost::filesystem::path (iter->second.filename()).string()); - QStandardItem *child = new QStandardItem(fileName); + QString fileName = QString::fromStdString(boost::filesystem::path (iter->second.filename()).string()); + QStandardItem *child = new QStandardItem(fileName); - // Tooltip information - QString author = QString::fromStdString(fileReader.getAuthor()); - float version = fileReader.getFVer(); - QString description = QString::fromStdString(fileReader.getDesc()); + // Tooltip information + QString author = QString::fromStdString(fileReader.getAuthor()); + float version = fileReader.getFVer(); + QString description = QString::fromStdString(fileReader.getDesc()); - // For the date created/modified - QFileInfo fi(QString::fromStdString(iter->second.string())); + // For the date created/modified + QFileInfo fi(QString::fromStdString(iter->second.string())); - QString toolTip= QString("Author: %1
\ - Version: %2

\ - Description:
\ - %3

\ - Created on: %4
\ - Last modified: %5") - .arg(author) - .arg(version) - .arg(description) - .arg(fi.created().toString(Qt::TextDate)) - .arg(fi.lastModified().toString(Qt::TextDate)); + QString toolTip= QString("Author: %1
\ + Version: %2

\ + Description:
\ + %3

\ + Created on: %4
\ + Last modified: %5") + .arg(author) + .arg(version) + .arg(description) + .arg(fi.created().toString(Qt::TextDate)) + .arg(fi.lastModified().toString(Qt::TextDate)); - child->setToolTip(toolTip); + child->setToolTip(toolTip); - const QList masterList = mDataFilesModel->findItems(availableMasters.join(",")); + const QList masterList = mDataFilesModel->findItems(availableMasters.join(",")); - if (masterList.isEmpty()) { // Masters node not yet in the mDataFilesModel - parent->appendRow(child); - mDataFilesModel->appendRow(parent); - } else { - // Masters node exists, append current plugin - foreach (QStandardItem *currentItem, masterList) { - currentItem->appendRow(child); + if (masterList.isEmpty()) { // Masters node not yet in the mDataFilesModel + parent->appendRow(child); + mDataFilesModel->appendRow(parent); + } else { + // Masters node exists, append current plugin + foreach (QStandardItem *currentItem, masterList) { + currentItem->appendRow(child); + } } + + } catch(std::runtime_error &e) { + // An error occurred while reading the .esp + continue; } } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d6101c919..929b579b8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -81,7 +81,7 @@ add_definitions(${SOUND_DEFINE}) target_link_libraries(openmw ${OGRE_LIBRARIES} - ${OGRE_STATIC_PLUGINS} + ${OGRE_STATIC_PLUGINS} ${OIS_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} @@ -92,6 +92,11 @@ target_link_libraries(openmw components ) +# Fix for not visible pthreads functions for linker with glibc 2.15 +if (UNIX AND NOT APPLE) +target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) +endif() + if(APPLE) find_library(CARBON_FRAMEWORK Carbon) target_link_libraries(openmw ${CARBON_FRAMEWORK}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fcdd0bf99..89068ce53 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -60,7 +60,7 @@ void OMW::Engine::executeLocalScripts() MWScript::InterpreterContext interpreterContext (mEnvironment, &script.second.getRefData().getLocals(), script.second); - mScriptManager->run (script.first, interpreterContext); + mEnvironment.mScriptManager->run (script.first, interpreterContext); if (mEnvironment.mWorld->hasCellChanged()) break; @@ -182,7 +182,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mCompileAll (false) , mReportFocus (false) , mFocusTDiff (0) - , mScriptManager (0) , mScriptContext (0) , mFSStrict (false) , mCfgMgr(configurationManager) @@ -199,7 +198,7 @@ OMW::Engine::~Engine() delete mEnvironment.mMechanicsManager; delete mEnvironment.mDialogueManager; delete mEnvironment.mJournal; - delete mScriptManager; + delete mEnvironment.mScriptManager; delete mScriptContext; delete mOgre; } @@ -348,18 +347,18 @@ void OMW::Engine::go() mEnvironment); mScriptContext->setExtensions (&mExtensions); - mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), mVerboseScripts, - *mScriptContext); + mEnvironment.mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), + mVerboseScripts, *mScriptContext); mEnvironment.mGlobalScripts = new MWScript::GlobalScripts (mEnvironment.mWorld->getStore(), - *mScriptManager); + *mEnvironment.mScriptManager); // Create game mechanics system mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment); // Create dialog system mEnvironment.mJournal = new MWDialogue::Journal (mEnvironment); - mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment); + mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment,mExtensions); // load cell ESM::Position pos; @@ -393,7 +392,7 @@ void OMW::Engine::go() // scripts if (mCompileAll) { - std::pair result = mScriptManager->compileAll(); + std::pair result = mEnvironment.mScriptManager->compileAll(); if (result.first) std::cout @@ -438,7 +437,7 @@ void OMW::Engine::activate() if (!script.empty()) { mEnvironment.mWorld->getLocalScripts().setIgnore (ptr); - mScriptManager->run (script, interpreterContext); + mEnvironment.mScriptManager->run (script, interpreterContext); } if (!interpreterContext.hasActivationBeenHandled()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 5c5cdc018..690430784 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -78,10 +78,9 @@ namespace OMW std::string mFocusName; MWWorld::Environment mEnvironment; - MWScript::ScriptManager *mScriptManager; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; - + Files::Collections mFileCollections; bool mFSStrict; diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index f78160cd7..50549f4a5 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -9,16 +9,36 @@ #include + #include "../mwworld/class.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/refdata.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwinput/inputmanager.hpp" +#include "../mwgui/dialogue.hpp" +#include "../mwgui/window_manager.hpp" + +#include "journal.hpp" #include +#include "../mwscript/extensions.hpp" +#include "../mwscript/scriptmanager.hpp" + +#include +#include +#include +#include +#include +#include + +#include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" +#include + namespace { std::string toLower (const std::string& name) @@ -31,17 +51,18 @@ namespace return lowerCase; } + template bool selectCompare (char comp, T1 value1, T2 value2) { switch (comp) { - case '0': return value1==value2; - case '1': return value1!=value2; - case '2': return value1>value2; - case '3': return value1>=value2; - case '4': return value1value2; + case '3': return value1>=value2; + case '4': return value1::const_iterator iter (info.selects.begin()); + iter != info.selects.end(); ++iter) + { + ESM::DialInfo::SelectStruct select = *iter; + char type = select.selectRule[1]; + if(type == '1') + { + char comp = select.selectRule[4]; + std::string name = select.selectRule.substr (5); + std::string function = select.selectRule.substr(2,2); + + int ifunction; + std::istringstream iss(function); + iss >> ifunction; + switch(ifunction) + { + case 39://PC Expelled + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 40://PC Common Disease + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 41://PC Blight Disease + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 43://PC Crime level + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 46://Same faction + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 48://Detected + if(!selectCompare(comp,1,select.i)) return false; + break; + + case 49://Alarmed + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 50://choice + + if(choice) + { + if(!selectCompare(comp,mChoice,select.i)) return false; + } + break; + + case 60://PC Vampire + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 61://Level + if(!selectCompare(comp,1,select.i)) return false; + break; + + case 62://Attacked + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 63://Talked to PC + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 64://PC Health + if(!selectCompare(comp,50,select.i)) return false; + break; + + case 65://Creature target + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 66://Friend hit + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 67://Fight + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 68://Hello???? + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 69://Alarm + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 70://Flee + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 71://Should Attack + if(!selectCompare(comp,0,select.i)) return false; + break; + + default: + break; + + } + } + } + + return true; + } + bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const { @@ -124,58 +264,173 @@ namespace MWDialogue { char comp = select.selectRule[4]; std::string name = select.selectRule.substr (5); - - // TODO types 4, 5, 6, 7, 8, 9, A, B, C + std::string function = select.selectRule.substr(1,2); switch (type) { - case '1': // function + case '1': // function - return false; // TODO implement functions + return true; // TODO implement functions - case '2': // global + case '2': // global - if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || - select.type==ESM::VT_Long) - { - if (!checkGlobal (comp, toLower (name), select.i, *mEnvironment.mWorld)) - return false; - } - else if (select.type==ESM::VT_Float) - { - if (!checkGlobal (comp, toLower (name), select.f, *mEnvironment.mWorld)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (!checkGlobal (comp, toLower (name), select.i, *mEnvironment.mWorld)) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (!checkGlobal (comp, toLower (name), select.f, *mEnvironment.mWorld)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); - return true; + return true; - case '3': // local + case '3': // local - if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || - select.type==ESM::VT_Long) - { - if (!checkLocal (comp, toLower (name), select.i, actor, - mEnvironment.mWorld->getStore())) - return false; - } - else if (select.type==ESM::VT_Float) - { - if (!checkLocal (comp, toLower (name), select.f, actor, - mEnvironment.mWorld->getStore())) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (!checkLocal (comp, toLower (name), select.i, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (!checkLocal (comp, toLower (name), select.f, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); - return true; + return true; - default: + case '4'://journal + if(select.type==ESM::VT_Int) + { + if(!selectCompare(comp,mEnvironment.mJournal->getJournalIndex(toLower(name)),select.i)) return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case '5'://item + { + MWWorld::Ptr player = mEnvironment.mWorld->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); + + int sum = 0; + + for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) + if (iter->getCellRef().refID==name) + sum += iter->getRefData().getCount(); + if(!selectCompare(comp,sum,select.i)) return false; + } + + return true; + + + case '6'://dead + if(!selectCompare(comp,0,select.i)) return false; + + case '7':// not ID + if(select.type==ESM::VT_String ||select.type==ESM::VT_Int)//bug in morrowind here? it's not a short, it's a string + { + int isID = int(toLower(name)==toLower(MWWorld::Class::get (actor).getId (actor))); + if (selectCompare(comp,!isID,select.i)) return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case '8':// not faction + if(select.type==ESM::VT_Int) + { + ESMS::LiveCellRef* npc = actor.get(); + int isFaction = int(toLower(npc->base->faction) == toLower(name)); + if(selectCompare(comp,!isFaction,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case '9':// not class + if(select.type==ESM::VT_Int) + { + ESMS::LiveCellRef* npc = actor.get(); + int isClass = int(toLower(npc->base->cls) == toLower(name)); + if(selectCompare(comp,!isClass,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case 'A'://not Race + if(select.type==ESM::VT_Int) + { + ESMS::LiveCellRef* npc = actor.get(); + int isRace = int(toLower(npc->base->race) == toLower(name)); + if(selectCompare(comp,!isRace,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; - std::cout << "unchecked select: " << type << " " << comp << " " << name << std::endl; + case 'B'://not Cell + if(select.type==ESM::VT_Int) + { + int isCell = int(toLower(actor.getCell()->cell->name) == toLower(name)); + if(selectCompare(comp,!isCell,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + return true; + + case 'C'://not local + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (checkLocal (comp, toLower (name), select.i, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (checkLocal (comp, toLower (name), select.f, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + return true; + + + default: + + std::cout << "unchecked select: " << type << " " << comp << " " << name << std::endl; } } @@ -189,6 +444,10 @@ namespace MWDialogue if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) return false; + //PC Faction + if(!info.pcFaction.empty()) return false; + + //NPC race if (!info.race.empty()) { ESMS::LiveCellRef *cellRef = actor.get(); @@ -200,6 +459,7 @@ namespace MWDialogue return false; } + //NPC class if (!info.clas.empty()) { ESMS::LiveCellRef *cellRef = actor.get(); @@ -211,6 +471,7 @@ namespace MWDialogue return false; } + //NPC faction if (!info.npcFaction.empty()) { ESMS::LiveCellRef *cellRef = actor.get(); @@ -220,66 +481,320 @@ namespace MWDialogue if (toLower (info.npcFaction)!=toLower (cellRef->base->faction)) return false; + + //check NPC rank + if(cellRef->base->npdt52.gold != -10) + { + if(cellRef->base->npdt52.rank < info.data.rank) return false; + } + else + { + if(cellRef->base->npdt12.rank < info.data.rank) return false; + } } // TODO check player faction + //check gender + ESMS::LiveCellRef* npc = actor.get(); + if(npc->base->flags&npc->base->Female) + { + if(static_cast (info.data.gender)==0) return false; + } + else + { + if(static_cast (info.data.gender)==1) return false; + } + + // check cell if (!info.cell.empty()) if (mEnvironment.mWorld->getPlayer().getPlayer().getCell()->cell->name != info.cell) return false; // TODO check DATAstruct - for (std::vector::const_iterator iter (info.selects.begin()); iter != info.selects.end(); ++iter) if (!isMatching (actor, *iter)) return false; - std::cout - << "unchecked entries:" << std::endl - << " player faction: " << info.pcFaction << std::endl - << " disposition: " << info.data.disposition << std::endl - << " NPC rank: " << static_cast (info.data.rank) << std::endl - << " gender: " << static_cast (info.data.gender) << std::endl - << " PC rank: " << static_cast (info.data.PCrank) << std::endl; - return true; } - DialogueManager::DialogueManager (MWWorld::Environment& environment) : mEnvironment (environment) {} + DialogueManager::DialogueManager (MWWorld::Environment& environment,const Compiler::Extensions& extensions) : + mEnvironment (environment),mCompilerContext (MWScript::CompilerContext::Type_Dialgoue, environment), + mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) + { + mChoice = -1; + mIsInChoice = false; + mCompilerContext.setExtensions (&extensions); + } + + void DialogueManager::addTopic(std::string topic) + { + knownTopics[toLower(topic)] = true; + } + + void DialogueManager::parseText(std::string text) + { + std::list::iterator it; + for(it = actorKnownTopics.begin();it != actorKnownTopics.end();it++) + { + size_t pos = find_str_ci(text,*it,0); + if(pos !=std::string::npos) + { + if(pos==0) + { + knownTopics[*it] = true; + } + else if(text.substr(pos -1,1) == " ") + { + knownTopics[*it] = true; + } + } + } + updateTopics(); + } void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { - std::cout << "talking with " << MWWorld::Class::get (actor).getName (actor) << std::endl; + mChoice = -1; + mIsInChoice = false; - const ESM::Dialogue *dialogue = mEnvironment.mWorld->getStore().dialogs.find ("hello"); + mActor = actor; - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); - iter!=dialogue->mInfo.end(); ++iter) + mDialogueMap.clear(); + actorKnownTopics.clear(); + ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { - if (isMatching (actor, *iter)) + mDialogueMap[it->first] = it->second; + } + + //initialise the GUI + mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue); + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->startDialogue(MWWorld::Class::get (actor).getName (actor)); + + //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI + updateTopics(); + + //greeting + bool greetingFound = false; + //ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + { + ESM::Dialogue ndialogue = it->second; + if(ndialogue.type == ESM::Dialogue::Greeting) { - // start dialogue - std::cout << "found matching info record" << std::endl; + if (greetingFound) break; + for (std::vector::const_iterator iter (it->second.mInfo.begin()); + iter!=it->second.mInfo.end(); ++iter) + { + if (isMatching (actor, *iter) && functionFilter(mActor,*iter,true)) + { + if (!iter->sound.empty()) + { + // TODO play sound + } + + std::string text = iter->response; + parseText(text); + win->addText(iter->response); + executeScript(iter->resultScript); + greetingFound = true; + mLastTopic = it->first; + mLastDialogue = *iter; + break; + } + } + } + } + } + + bool DialogueManager::compile (const std::string& cmd,std::vector& code) + { + try + { + mErrorHandler.reset(); + + std::istringstream input (cmd + "\n"); + + Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions()); + + Compiler::Locals locals; + + std::string actorScript = MWWorld::Class::get (mActor).getScript (mActor); + + if (!actorScript.empty()) + { + // grab local variables from actor's script, if available. + locals = mEnvironment.mScriptManager->getLocals (actorScript); + } + + Compiler::ScriptParser parser(mErrorHandler,mCompilerContext, locals, false); + + scanner.scan (parser); + if(mErrorHandler.isGood()) + { + parser.getCode(code); + return true; + } + return false; + } + catch (const Compiler::SourceException& error) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } - std::cout << "response: " << iter->response << std::endl; + return false; + } - if (!iter->sound.empty()) + void DialogueManager::executeScript(std::string script) + { + std::vector code; + if(compile(script,code)) + { + try + { + MWScript::InterpreterContext interpreterContext(mEnvironment,&mActor.getRefData().getLocals(),mActor); + Interpreter::Interpreter interpreter; + MWScript::installOpcodes (interpreter); + interpreter.run (&code[0], code.size(), interpreterContext); + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + } + } + + void DialogueManager::updateTopics() + { + std::list keywordList; + int choice = mChoice; + mChoice = -1; + actorKnownTopics.clear(); + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + { + ESM::Dialogue ndialogue = it->second; + if(ndialogue.type == ESM::Dialogue::Topic) + { + for (std::vector::const_iterator iter (it->second.mInfo.begin()); + iter!=it->second.mInfo.end(); ++iter) { - // TODO play sound + if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) + { + actorKnownTopics.push_back(it->first); + //does the player know the topic? + if(knownTopics.find(toLower(it->first)) != knownTopics.end()) + { + keywordList.push_back(it->first); + break; + } + } } + } + } + win->setKeywords(keywordList); + mChoice = choice; + } - if (!iter->resultScript.empty()) + void DialogueManager::keywordSelected(std::string keyword) + { + if(!mIsInChoice) + { + if(mDialogueMap.find(keyword) != mDialogueMap.end()) + { + ESM::Dialogue ndialogue = mDialogueMap[keyword]; + if(ndialogue.type == ESM::Dialogue::Topic) { - std::cout << "script: " << iter->resultScript << std::endl; - // TODO execute script + for (std::vector::const_iterator iter = ndialogue.mInfo.begin(); + iter!=ndialogue.mInfo.end(); ++iter) + { + if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) + { + std::string text = iter->response; + std::string script = iter->resultScript; + + parseText(text); + + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->addTitle(keyword); + win->addText(iter->response); + + executeScript(script); + + mLastTopic = keyword; + mLastDialogue = *iter; + break; + } + } } + } + } - mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue); - break; + updateTopics(); + } + + void DialogueManager::goodbyeSelected() + { + mEnvironment.mInputManager->setGuiMode(MWGui::GM_Game); + } + + void DialogueManager::questionAnswered(std::string answere) + { + if(mChoiceMap.find(answere) != mChoiceMap.end()) + { + mChoice = mChoiceMap[answere]; + + std::vector::const_iterator iter; + if(mDialogueMap.find(mLastTopic) != mDialogueMap.end()) + { + ESM::Dialogue ndialogue = mDialogueMap[mLastTopic]; + if(ndialogue.type == ESM::Dialogue::Topic) + { + for (std::vector::const_iterator iter = ndialogue.mInfo.begin(); + iter!=ndialogue.mInfo.end(); ++iter) + { + if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) + { + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + std::string text = iter->response; + parseText(text); + win->addText(text); + executeScript(iter->resultScript); + mLastTopic = mLastTopic; + mLastDialogue = *iter; + break; + } + } + } } + updateTopics(); } } + void DialogueManager::printError(std::string error) + { + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->addText(error); + } + + void DialogueManager::askQuestion(std::string question, int choice) + { + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->askQuestion(question); + mChoiceMap[question] = choice; + mIsInChoice = true; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index 5b6b26240..260d8e339 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -3,7 +3,13 @@ #include +#include +#include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" +#include + #include "../mwworld/ptr.hpp" +#include namespace MWWorld { @@ -20,12 +26,48 @@ namespace MWDialogue bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const; + bool functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice); + + void parseText(std::string text); + + void updateTopics(); + + std::map mDialogueMap; + std::map knownTopics;// Those are the topics the player knows. + std::list actorKnownTopics; + + MWScript::CompilerContext mCompilerContext; + std::ostream mErrorStream; + Compiler::StreamErrorHandler mErrorHandler; + + + bool compile (const std::string& cmd,std::vector& code); + void executeScript(std::string script); + MWWorld::Ptr mActor; + + void printError(std::string error); + + int mChoice; + std::map mChoiceMap; + std::string mLastTopic; + ESM::DialInfo mLastDialogue; + bool mIsInChoice; + public: - DialogueManager (MWWorld::Environment& environment); + DialogueManager (MWWorld::Environment& environment,const Compiler::Extensions& extensions); void startDialogue (const MWWorld::Ptr& actor); + void addTopic(std::string topic); + + void askQuestion(std::string question,int choice); + + //calbacks for the GUI + void keywordSelected(std::string keyword); + void goodbyeSelected(); + void questionAnswered(std::string answere); + }; } diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 42cce5cf5..0715214eb 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -3,6 +3,9 @@ #include "../mwworld/environment.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/messagebox.hpp" + namespace MWDialogue { Quest& Journal::getQuest (const std::string& id) @@ -34,6 +37,10 @@ namespace MWDialogue Quest& quest = getQuest (id); quest.addEntry (entry, *mEnvironment.mWorld); // we are doing slicing on purpose here + + std::vector empty; + std::string notification = "Your Journal has been updated."; + mEnvironment.mWindowManager->messageBox (notification, empty); } void Journal::setJournalIndex (const std::string& id, int index) @@ -60,7 +67,12 @@ namespace MWDialogue int Journal::getJournalIndex (const std::string& id) const { - return 0; + TQuestContainer::const_iterator iter = mQuests.find (id); + + if (iter==mQuests.end()) + return 0; + + return iter->second.getIndex(); } Journal::TEntryIter Journal::begin() const diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 3fd6e7892..0a5197c60 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -139,6 +139,9 @@ namespace MWGui void Console::disable() { setVisible(false); + // Remove keyboard focus from the console input whenever the + // console is turned off + MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL); } void Console::setFont(const std::string &fntName) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e48c142aa..cef47d074 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,8 @@ #include "window_manager.hpp" #include "widgets.hpp" #include "components/esm_store/store.hpp" +#include "../mwworld/environment.hpp" +#include "../mwdialogue/dialoguemanager.hpp" #include #include @@ -14,32 +16,54 @@ using namespace MWGui; using namespace Widgets; -DialogueWindow::DialogueWindow(WindowManager& parWindowManager) - : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) +/** +*Copied from the internet. +*/ + +std::string lower_string(const std::string& str) +{ + std::string lowerCase; + + std::transform (str.begin(), str.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; +} + +std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) +{ + return lower_string(str).find(lower_string(substr),pos); +} + + +DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) + : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager), + mEnvironment(environment) { // Centre dialog center(); //WindowManager *wm = environment.mWindowManager; setText("NpcName", "Name of character"); - + //History view getWidget(history, "History"); history->setOverflowToTheLeft(true); history->getClient()->eventMouseButtonClick = MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); - - //Topics list + history->setMaxTextLength(1000000); + //Topics list getWidget(topicsList, "TopicsList"); topicsList->setScrollVisible(true); - topicsList->eventListSelectAccept = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + //topicsList->eventListSelectAccept = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); topicsList->eventListMouseItemActivate = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - topicsList->eventListChangePosition = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + //topicsList->eventListChangePosition = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick = MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - updateOptions(); + getWidget(pDispositionBar, "Disposition"); + getWidget(pDispositionText,"DispositionText"); } void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) @@ -51,70 +75,126 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) const IntPoint& lastPressed = InputManager::getInstance().getLastLeftPressed(); size_t cursorPosition = t->getCursorPosition(lastPressed); - if(history->getColorAtPos(cursorPosition) != "#FFFFFF") + MyGUI::UString color = history->getColorAtPos(cursorPosition); + if(color != "#B29154") { UString key = history->getColorTextAt(cursorPosition); - std::cout << "Clicked on key: " << key << std::endl; - //eventTopicSelected(key); + if(color == "#686EBA") mEnvironment.mDialogueManager->keywordSelected(lower_string(key)); + + if(color == "#572D21") mEnvironment.mDialogueManager->questionAnswered(key); } } void DialogueWindow::open() { + topicsList->removeAllItems(); + pTopicsText.clear(); + history->eraseText(0,history->getTextLength()); updateOptions(); setVisible(true); } void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - eventBye(); + mEnvironment.mDialogueManager->goodbyeSelected(); } void DialogueWindow::onSelectTopic(MyGUI::List* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) return; + std::string topic = _sender->getItemNameAt(_index); + mEnvironment.mDialogueManager->keywordSelected(lower_string(topic)); +} - //const std::string* theTopic = topicsList->getItemDataAt(_index); - //std::cout << "Selected: "<< theTopic << std::endl; - //eventTopicSelected(key); +void DialogueWindow::startDialogue(std::string npcName) +{ + setText("NpcName", npcName); } +void DialogueWindow::setKeywords(std::list keyWords) +{ + topicsList->removeAllItems(); + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); it++) + { + topicsList->addItem(*it); + } +} -void DialogueWindow::updateOptions() +void DialogueWindow::removeKeyword(std::string keyWord) +{ + if(topicsList->findItemIndexWith(keyWord) != MyGUI::ITEM_NONE) + { + topicsList->removeItemAt(topicsList->findItemIndexWith(keyWord)); + pTopicsText.erase(keyWord); + } +} + +void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) +{ + size_t pos = 0; + while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) + { + if(pos==0) + { + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); + } + else + { + if(str.substr(pos -1,1) == " ") + { + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); + } + else + { + pos += keyword.length(); + } + } + } +} + +std::string DialogueWindow::parseText(std::string text) { - //FIXME Add this properly - history->addDialogText("Through the translucent surface of the orb, you see shifting images of distant locations..."); - for(int z = 0; z < 10; z++) + for(unsigned int i = 0;igetItemCount();i++) { - history->addDialogHeading("Fort Frostmoth"); - history->addDialogText("The image in the orb flickers, and you see.... The cold courtyard of #FF0000Fort Frostmoth#FFFFFF, battered bu werewolf attack, but still standing, still projecting Imperial might even to this distant and cold corner of the world."); + std::string keyWord = topicsList->getItemNameAt(i); + addColorInString(text,keyWord,"#686EBA","#B29154"); } + return text; +} +void DialogueWindow::addText(std::string text) +{ + history->addDialogText("#B29154"+parseText(text)+"#B29154"); +} + +void DialogueWindow::addTitle(std::string text) +{ + history->addDialogHeading(text); +} + +void DialogueWindow::askQuestion(std::string question) +{ + history->addDialogText("#572D21"+question+"#B29154"+" "); +} + +void DialogueWindow::updateOptions() +{ //Clear the list of topics topicsList->removeAllItems(); - int i = 0; - topicsList->addItem("Ald'ruhn", i++); - topicsList->addItem("Balmora", i++); - topicsList->addItem("Sadrith Mora", i++); - topicsList->addItem("Vivec", i++); - topicsList->addItem("Ald Velothi", i++); - topicsList->addItem("Caldera", i++); - topicsList->addItem("Dagon Fel ", i++); - topicsList->addItem("Gnaar Mok", i++); - topicsList->addItem("Gnisis", i++); - topicsList->addItem("Hla Oad", i++); - topicsList->addItem("Khuul", i++); - topicsList->addItem("Maar Gan", i++); - topicsList->addItem("Molag Mar", i++); - topicsList->addItem("Pelagiad", i++); - topicsList->addItem("Seyda Neen", i++); - topicsList->addItem("Suran", i++); - topicsList->addItem("Tel Aruhn", i++); - topicsList->addItem("Tel Branora", i++); - topicsList->addItem("Tel Fyr", i++); - topicsList->addItem("Tel Mora", i++); - topicsList->addItem("Tel Vos", i++); - topicsList->addItem("Vos", i++); -} + pTopicsText.clear(); + history->eraseText(0,history->getTextLength()); + pDispositionBar->setProgressRange(100); + pDispositionBar->setProgressPosition(40); + pDispositionText->eraseText(0,pDispositionText->getTextLength()); + pDispositionText->addText("#B29154"+std::string("40/100")+"#B29154"); +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index ddb6f8a4c..7dfd7bb7f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -9,6 +9,11 @@ namespace MWGui class WindowManager; } +namespace MWWorld +{ + class Environment; +} + /* This file contains the dialouge window Layout is defined by resources/mygui/openmw_dialogue_window_layout.xml. @@ -23,7 +28,7 @@ namespace MWGui class DialogueWindow: public WindowBase { public: - DialogueWindow(WindowManager& parWindowManager); + DialogueWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); void open(); @@ -35,6 +40,14 @@ namespace MWGui */ EventHandle_Void eventBye; + void startDialogue(std::string npcName); + void stopDialogue(); + void setKeywords(std::list keyWord); + void removeKeyword(std::string keyWord); + void addText(std::string text); + void addTitle(std::string text); + void askQuestion(std::string question); + protected: void onSelectTopic(MyGUI::List* _sender, size_t _index); void onByeClicked(MyGUI::Widget* _sender); @@ -42,9 +55,18 @@ namespace MWGui private: void updateOptions(); + /** + *Helper function that add topic keyword in blue in a text. + */ + std::string parseText(std::string text); DialogeHistory* history; MyGUI::ListPtr topicsList; + MyGUI::ProgressPtr pDispositionBar; + MyGUI::EditPtr pDispositionText; + std::map pTopicsText;// this map links keyword and "real" text. + + MWWorld::Environment& mEnvironment; }; } #endif diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp index aaa559d24..ceb904528 100644 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ b/apps/openmw/mwgui/dialogue_history.cpp @@ -61,9 +61,9 @@ UString DialogeHistory::getColorTextAt(size_t _pos) void DialogeHistory::addDialogHeading(const UString& parText) { - UString head("\n#00FF00"); + UString head("\n#D8C09A"); head.append(parText); - head.append("#FFFFFF\n"); + head.append("#B29154\n"); addText(head); } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index f0745bbbe..cd32fc40f 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -19,7 +19,7 @@ void MessageBoxManager::onFrame (float frameDuration) if(it->current >= it->max) { it->messageBox->mMarkedToDelete = true; - + if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one { // collect all with mMarkedToDelete and delete them. @@ -47,7 +47,7 @@ void MessageBoxManager::onFrame (float frameDuration) it++; } } - + if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { delete mInterMessageBoxe; mInterMessageBoxe = NULL; @@ -57,20 +57,18 @@ void MessageBoxManager::onFrame (float frameDuration) void MessageBoxManager::createMessageBox (const std::string& message) { - std::cout << "MessageBox: " << message << std::endl; - MessageBox *box = new MessageBox(*this, message); - + removeMessageBox(message.length()*mMessageBoxSpeed, box); - + mMessageBoxes.push_back(box); std::vector::iterator it; - + if(mMessageBoxes.size() > 3) { delete *mMessageBoxes.begin(); mMessageBoxes.erase(mMessageBoxes.begin()); } - + int height = 0; for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) { @@ -88,9 +86,9 @@ bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, std::cout << "interactive MessageBox: " << message << " - "; std::copy (buttons.begin(), buttons.end(), std::ostream_iterator (std::cout, ", ")); std::cout << std::endl; - + mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); - + return true; } @@ -105,7 +103,7 @@ void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) timer.current = 0; timer.max = time; timer.messageBox = msgbox; - + mTimers.insert(mTimers.end(), timer); } @@ -152,25 +150,25 @@ MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::strin mBottomPadding = 20; mNextBoxPadding = 20; mMarkedToDelete = false; - + getWidget(mMessageWidget, "message"); - + mMessageWidget->setOverflowToTheLeft(true); mMessageWidget->addText(cMessage); - + MyGUI::IntSize size; size.width = mFixedWidth; size.height = 100; // dummy - + MyGUI::IntCoord coord; coord.left = 10; // dummy coord.top = 10; // dummy mMessageWidget->setSize(size); - + MyGUI::IntSize textSize = mMessageWidget->_getTextSize(); size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box - + mMainWidget->setSize(size); size.width -= 15; // this is to center the text (see messagebox_layout.xml, Widget type="Edit" position="-2 -3 0 0") mMessageWidget->setSize(size); @@ -182,11 +180,11 @@ void MessageBox::update (int height) MyGUI::IntCoord coord; coord.left = (gameWindowSize.width - mFixedWidth)/2; coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); - + MyGUI::IntSize size; size.width = mFixedWidth; size.height = mHeight; - + mMainWidget->setCoord(coord); mMainWidget->setSize(size); mMainWidget->setVisible(true); @@ -211,26 +209,26 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan int buttonTopPadding = 5; // ^-- if vertical int buttonPadding = 5; // padding between button label and button itself int buttonMainPadding = 10; // padding between buttons and bottom of the main widget - + mMarkedToDelete = false; - - + + getWidget(mMessageWidget, "message"); getWidget(mButtonsWidget, "buttons"); - + mMessageWidget->setOverflowToTheLeft(true); mMessageWidget->addText(message); - + MyGUI::IntSize textSize = mMessageWidget->_getTextSize(); - + MyGUI::IntSize gameWindowSize = mMessageBoxManager.mWindowManager->getGui()->getViewSize(); - + int biggestButtonWidth = 0; int buttonWidth = 0; int buttonsWidth = 0; int buttonHeight = 0; MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - + std::vector::const_iterator it; for(it = buttons.begin(); it != buttons.end(); ++it) { @@ -240,28 +238,28 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan dummyCoord, MyGUI::Align::Default); button->setCaption(*it); - - button->eventMouseButtonClick = MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); - + + button->eventMouseButtonClick = MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); + mButtons.push_back(button); - + buttonWidth = button->_getTextSize().width + 2*buttonPadding + buttonLeftPadding; buttonsWidth += buttonWidth; buttonHeight = button->_getTextSize().height + 2*buttonPadding + buttonTopPadding; - + if(buttonWidth > biggestButtonWidth) { biggestButtonWidth = buttonWidth; } } buttonsWidth += buttonLeftPadding; - + MyGUI::IntSize mainWidgetSize; if(buttonsWidth < fixedWidth) { // on one line std::cout << "on one line" << std::endl; - + if(textSize.width + 2*textPadding < buttonsWidth) { std::cout << "width = buttonsWidth" << std::endl; @@ -272,48 +270,48 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan mainWidgetSize.width = textSize.width + 3*textPadding; } mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; - + MyGUI::IntCoord absCoord; absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - + std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl; std::cout << "left " << absCoord.left << " top " << absCoord.top << std::endl; - + mMainWidget->setCoord(absCoord); mMainWidget->setSize(mainWidgetSize); - - + + MyGUI::IntCoord messageWidgetCoord; messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; messageWidgetCoord.top = textPadding; mMessageWidget->setCoord(messageWidgetCoord); - + mMessageWidget->setSize(textSize); - + MyGUI::IntCoord buttonCord; MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; - + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { buttonCord.left = left; buttonCord.top = textSize.height + textButtonPadding; - + buttonSize.width = (*button)->_getTextSize().width + 2*buttonPadding; buttonSize.height = (*button)->_getTextSize().height + 2*buttonPadding; - + (*button)->setCoord(buttonCord); (*button)->setSize(buttonSize); - + left += buttonSize.width + buttonLeftPadding; } } else { // among each other - + if(biggestButtonWidth > textSize.width) { mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; } @@ -321,46 +319,46 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan mainWidgetSize.width = textSize.width + 3*textPadding; } mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; - + std::cout << "biggestButtonWidth " << biggestButtonWidth << " textSize.width " << textSize.width << std::endl; std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl; mMainWidget->setSize(mainWidgetSize); - + MyGUI::IntCoord absCoord; absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - + mMainWidget->setCoord(absCoord); mMainWidget->setSize(mainWidgetSize); - - + + MyGUI::IntCoord messageWidgetCoord; messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; messageWidgetCoord.top = textPadding; mMessageWidget->setCoord(messageWidgetCoord); - + mMessageWidget->setSize(textSize); - + MyGUI::IntCoord buttonCord; MyGUI::IntSize buttonSize(0, buttonHeight); - + int top = textButtonPadding + buttonTopPadding + textSize.height; - + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { buttonSize.width = (*button)->_getTextSize().width + buttonPadding*2; buttonSize.height = (*button)->_getTextSize().height + buttonPadding*2; - + buttonCord.top = top; buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ - + (*button)->setCoord(buttonCord); (*button)->setSize(buttonSize); - + top += buttonSize.height + 2*buttonTopPadding; } - + } } @@ -387,8 +385,3 @@ int InteractiveMessageBox::readPressedButton () mButtonPressed = -1; return pressed; } - - - - - diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index aca9fbd9a..baf854814 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -51,6 +51,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, console = new Console(w,h, environment, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); + dialogueWindow = new DialogueWindow(*this,environment); // The HUD is always on hud->setVisible(true); @@ -149,6 +150,7 @@ void WindowManager::updateVisible() stats->setVisible(false); console->disable(); mJournal->setVisible(false); + dialogueWindow->setVisible(false); // Mouse is visible whenever we're not in game mode gui->setVisiblePointer(isGuiMode()); @@ -195,11 +197,6 @@ void WindowManager::updateVisible() if (mode == GM_Dialogue) { - if (!dialogueWindow) - { - dialogueWindow = new DialogueWindow(*this); - dialogueWindow->eventBye = MyGUI::newDelegate(this, &WindowManager::onDialogueWindowBye); - } dialogueWindow->open(); return; } @@ -349,6 +346,7 @@ void WindowManager::updateSkillArea() void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) { + std::cout << "dialogue a la poubelle"; assert(dialog); if (!dialog) return; @@ -387,7 +385,8 @@ void WindowManager::onDialogueWindowBye() if (dialogueWindow) { //FIXME set some state and stuff? - removeDialog(dialogueWindow); + //removeDialog(dialogueWindow); + dialogueWindow->setVisible(false); } setGuiMode(GM_Game); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 89ff4b9bb..0124c9239 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -124,6 +124,8 @@ namespace MWGui updateVisible(); } + MWGui::DialogueWindow* getDialogueWindow() {return dialogueWindow;} + MyGUI::Gui* getGui() const { return gui; } void wmUpdateFps(float fps, size_t triangleCount, size_t batchCount) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 95eb8dd33..4f84d90a9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -51,7 +51,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const cameraPitchNode->attachObject(mRendering.getCamera()); //mSkyManager = 0; - mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); + mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e09fa8a42..a747b9be0 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -10,16 +10,12 @@ #include +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + using namespace MWRender; using namespace Ogre; -// the speed at which the clouds are animated -#define CLOUD_SPEED 0.001 - -// this distance has to be set accordingly so that the -// celestial bodies are behind the clouds, but in front of the atmosphere -#define CELESTIAL_BODY_DISTANCE 1000.f - BillboardObject::BillboardObject( const String& textureName, const float initialSize, const Vector3& position, @@ -50,7 +46,7 @@ void BillboardObject::setVisibility(const float visibility) void BillboardObject::setPosition(const Vector3& pPosition) { Vector3 normalised = pPosition.normalisedCopy(); - Vector3 finalPosition = normalised * CELESTIAL_BODY_DISTANCE; + Vector3 finalPosition = normalised * 1000.f; mBBSet->setCommonDirection( -normalised ); @@ -85,7 +81,7 @@ void BillboardObject::init(const String& textureName, { SceneManager* sceneMgr = rootNode->getCreator(); - Vector3 finalPosition = position.normalisedCopy() * CELESTIAL_BODY_DISTANCE; + Vector3 finalPosition = position.normalisedCopy() * 1000.f; static unsigned int bodyCount=0; @@ -296,9 +292,10 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); } -SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : +SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env) : mGlareFade(0), mGlareEnabled(false) { + mEnvironment = env; mViewport = pCamera->getViewport(); mSceneMgr = pMwRoot->getCreator(); mRootNode = pCamera->getParentSceneNode()->createChildSceneNode(); @@ -312,7 +309,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : Pass* pass = material->getTechnique(0)->getPass(0); pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); mThunderTextureUnit = pass->createTextureUnitState(); - mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); // always black colour + mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f); OverlayManager& ovm = OverlayManager::getSingleton(); mThunderOverlay = ovm.create( "ThunderOverlay" ); @@ -504,7 +501,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : " uniform float4 emissive \n" ") \n" "{ \n" - " uv += float2(1,1) * time * speed * "<getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", 1); + mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", mEnvironment->mWorld->getTimeScaleFactor()/30.f); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); @@ -594,8 +591,8 @@ void SkyManager::update(float duration) mMasser->setVisible(mMasserEnabled); mSecunda->setVisible(mSecundaEnabled); - // rotate the whole sky by 360 degrees every 4 days - mRootNode->roll(Degree(mHourDiff*360/96.f)); + // rotate the stars by 360 degrees every 4 days + mAtmosphereNight->roll(Degree(mEnvironment->mWorld->getTimeScaleFactor()*duration*360 / (3600*96.f))); } void SkyManager::enable() @@ -692,6 +689,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) strength = 1.f; mSunGlare->setVisibility(weather.mGlareView * strength); + mSun->setVisibility(strength); mAtmosphereNight->setVisible(weather.mNight && mEnabled); } @@ -775,9 +773,6 @@ void SkyManager::setSecundaFade(const float fade) void SkyManager::setHour(double hour) { - mHourDiff = mHour - hour; - if (mHourDiff > 0) mHourDiff -= 24; - mHour = hour; } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 2c7b7379a..bf52afd8d 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -107,7 +107,7 @@ namespace MWRender class SkyManager { public: - SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); + SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env); ~SkyManager(); void update(float duration); @@ -164,12 +164,11 @@ namespace MWRender Ogre::Vector3 getRealSunPos(); private: + MWWorld::Environment* mEnvironment; float mHour; int mDay; int mMonth; - float mHourDiff; - BillboardObject* mSun; BillboardObject* mSunGlare; Moon* mMasser; diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index c2ff9ed8b..0cca028e2 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -8,6 +8,7 @@ #include #include "../mwdialogue/journal.hpp" +#include "../mwdialogue/dialoguemanager.hpp" #include "interpretercontext.hpp" @@ -72,15 +73,62 @@ namespace MWScript } }; + class OpAddTopic : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string topic = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + context.getEnvironment().mDialogueManager->addTopic(topic); + } + }; + + class OpChoice : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + MWDialogue::DialogueManager* dialogue = context.getEnvironment().mDialogueManager; + while(arg0>0) + { + std::string question = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + arg0 = arg0 -1; + Interpreter::Type_Integer choice = 1; + if(arg0>0) + { + choice = runtime[0].mInteger; + runtime.pop(); + arg0 = arg0 -1; + } + dialogue->askQuestion(question,choice); + } + } + }; + + const int opcodeJournal = 0x2000133; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; + const int opcodeAddTopic = 0x200013a; + const int opcodeChoice = 0x2000a; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerInstruction ("journal", "cl", opcodeJournal); extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); + extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); + extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -88,6 +136,8 @@ namespace MWScript interpreter.installSegment5 (opcodeJournal, new OpJournal); interpreter.installSegment5 (opcodeSetJournalIndex, new OpSetJournalIndex); interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); + interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic); + interpreter.installSegment3 (opcodeChoice,new OpChoice); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 09b0c0482..eab5bf846 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -23,7 +23,8 @@ op 0x20006: PlayAnim op 0x20007: PlayAnim, explicit reference op 0x20008: LoopAnim op 0x20009: LoopAnim, explicit reference -opcodes 0x2000a-0x3ffff unused +op 0x2000a: Choice +opcodes 0x2000b-0x3ffff unused Segment 4: (not implemented yet) @@ -115,6 +116,7 @@ op 0x2000136: GetPCCell op 0x2000137: GetButtonPressed op 0x2000138: SkipAnim op 0x2000139: SkipAnim, expplicit reference +op 0x200013a: AddTopic op 0x200013b: twf op 0x200013c: FadeIn op 0x200013d: FadeOut diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 5fcfcc605..e93f2deec 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -63,7 +63,7 @@ namespace MWScript { std::vector code; mParser.getCode (code); - mScripts.insert (std::make_pair (name, code)); + mScripts.insert (std::make_pair (name, std::make_pair (code, mParser.getLocals()))); // TODO sanity check on generated locals @@ -77,8 +77,7 @@ namespace MWScript void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext) { // compile script - std::map >::iterator iter = - mScripts.find (name); + ScriptCollection::iterator iter = mScripts.find (name); if (iter==mScripts.end()) { @@ -86,7 +85,7 @@ namespace MWScript { // failed -> ignore script from now on. std::vector empty; - mScripts.insert (std::make_pair (name, empty)); + mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); return; } @@ -95,7 +94,7 @@ namespace MWScript } // execute script - if (!iter->second.empty()) + if (!iter->second.first.empty()) try { if (!mOpcodesInstalled) @@ -104,7 +103,7 @@ namespace MWScript mOpcodesInstalled = true; } - mInterpreter.run (&iter->second[0], iter->second.size(), interpreterContext); + mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext); } catch (const std::exception& e) { @@ -113,7 +112,7 @@ namespace MWScript if (mVerbose) std::cerr << "(" << e.what() << ")" << std::endl; - iter->second.clear(); // don't execute again. + iter->second.first.clear(); // don't execute again. } } @@ -132,4 +131,24 @@ namespace MWScript return std::make_pair (count, success); } + + Compiler::Locals& ScriptManager::getLocals (const std::string& name) + { + ScriptCollection::iterator iter = mScripts.find (name); + + if (iter==mScripts.end()) + { + if (!compile (name)) + { + // failed -> ignore script from now on. + std::vector empty; + mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); + throw std::runtime_error ("failed to compile script " + name); + } + + iter = mScripts.find (name); + } + + return iter->second.second; + } } diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index 74511f456..35cbc0d1e 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -39,7 +39,11 @@ namespace MWScript Interpreter::Interpreter mInterpreter; bool mOpcodesInstalled; - std::map > mScripts; + typedef std::pair, Compiler::Locals> CompiledScript; + typedef std::map ScriptCollection; + + + ScriptCollection mScripts; public: @@ -56,6 +60,9 @@ namespace MWScript std::pair compileAll(); ///< Compile all scripts /// \return count, success + + Compiler::Locals& getLocals (const std::string& name); + ///< Return locals for script \a name. }; }; diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index a5ba04e26..226796603 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -67,6 +67,7 @@ namespace MWSound , updater(mgr) , cameraTracker(mgr) , mCurrentPlaylist(NULL) + , mUsingSound(useSound) { if(useSound) { @@ -105,8 +106,11 @@ namespace MWSound SoundManager::~SoundManager() { - Ogre::Root::getSingleton().removeFrameListener(&updater); - cameraTracker.unfollowCamera(); + if(mUsingSound) + { + Ogre::Root::getSingleton().removeFrameListener(&updater); + cameraTracker.unfollowCamera(); + } } // Convert a soundId to file name, and modify the volume @@ -354,6 +358,9 @@ namespace MWSound void SoundManager::playPlaylist(std::string playlist) { + if (!mUsingSound) + return; + if (playlist == "") { if(!isMusicPlaying()) @@ -375,6 +382,9 @@ namespace MWSound void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) { + if (!mUsingSound) + return; + // The range values are not tested std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true); if(!filePath.empty()) diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index bd3b67679..dcf64b90c 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -82,6 +82,8 @@ namespace MWSound IDMap mLoopedSounds; + bool mUsingSound; + std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void add(const std::string &file, diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index a403ee165..3a83f886f 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -9,6 +9,7 @@ namespace MWSound namespace MWScript { class GlobalScripts; + class ScriptManager; } namespace MWGui @@ -41,7 +42,7 @@ namespace MWWorld { public: Environment() - : mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0), + : mWorld (0), mSoundManager (0), mGlobalScripts (0), mScriptManager (0), mWindowManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0), mInputManager (0) {} @@ -49,6 +50,7 @@ namespace MWWorld World *mWorld; MWSound::SoundManager *mSoundManager; MWScript::GlobalScripts *mGlobalScripts; + MWScript::ScriptManager *mScriptManager; MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; MWDialogue::DialogueManager *mDialogueManager; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index eab1197c5..9a918c2fb 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -21,6 +21,18 @@ const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0"; const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1"; const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2"; const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3"; +const float WeatherGlobals::mSunriseTime = 8; +const float WeatherGlobals::mSunsetTime = 18; +const float WeatherGlobals::mSunriseDuration = 2; +const float WeatherGlobals::mSunsetDuration = 2; +const float WeatherGlobals::mWeatherUpdateTime = 20.f; + + +// morrowind sets these per-weather, but since they are only used by 'thunderstorm' +// weather setting anyway, we can just as well set them globally +const float WeatherGlobals::mThunderFrequency = .4; +const float WeatherGlobals::mThunderThreshold = 0.6; +const float WeatherGlobals::mThunderSoundDelay = 0.25; WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), @@ -259,7 +271,8 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environmen blight.mGlareView = 0; blight.mAmbientLoopSoundID = "blight"; mWeatherSettings["blight"] = blight; - + + /* Weather snow; snow.mCloudTexture = "tx_bm_sky_snow.dds"; snow.mCloudsMaximumPercent = 1.0; @@ -316,10 +329,14 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environmen blizzard.mGlareView = 0; blizzard.mAmbientLoopSoundID = "BM Blizzard"; mWeatherSettings["blizzard"] = blizzard; + */ } void WeatherManager::setWeather(const String& weather, bool instant) { + if (weather == mCurrentWeather && mNextWeather == "") + return; + if (instant || mFirstUpdate) { mNextWeather = ""; @@ -331,12 +348,12 @@ void WeatherManager::setWeather(const String& weather, bool instant) if (mNextWeather != "") { // transition more than 50% finished? - if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60) <= 0.5) + if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600) <= 0.5) mCurrentWeather = mNextWeather; } - + mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60; + mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600; } } @@ -344,7 +361,7 @@ WeatherResult WeatherManager::getResult(const String& weather) { const Weather& current = mWeatherSettings[weather]; WeatherResult result; - + result.mCloudTexture = current.mCloudTexture; result.mCloudBlendFactor = 0; result.mCloudOpacity = current.mCloudsMaximumPercent; @@ -353,16 +370,13 @@ WeatherResult WeatherManager::getResult(const String& weather) result.mGlareView = current.mGlareView; result.mAmbientLoopSoundID = current.mAmbientLoopSoundID; result.mSunColor = current.mSunDiscSunsetColor; - - const float fade_duration = current.mTransitionDelta * 24.f; - - result.mNight = (mHour < 6.f+fade_duration || mHour > 20.f-fade_duration); - + + result.mNight = (mHour < 6 || mHour > 19); + result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - + // night - if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) - || mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) + if (mHour <= 5.5f || mHour >= 21) { result.mFogColor = current.mFogNightColor; result.mAmbientColor = current.mAmbientNightColor; @@ -370,82 +384,68 @@ WeatherResult WeatherManager::getResult(const String& weather) result.mSkyColor = current.mSkyNightColor; result.mNightFade = 1.f; } - + // sunrise - else if (mHour >= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) && mHour <= WeatherGlobals::mSunriseTime) + else if (mHour >= 5.5f && mHour <= 9) { - if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)) + if (mHour <= 6) { // fade in - float advance = (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)-mHour; - float factor = (advance / fade_duration); + float advance = 6-mHour; + float factor = advance / 0.5f; result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor); result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor); result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor); result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor); result.mNightFade = factor; } - else if (mHour >= (WeatherGlobals::mSunriseTime-fade_duration)) + else //if (mHour >= 6) { // fade out - float advance = mHour-(WeatherGlobals::mSunriseTime-fade_duration); - float factor = advance / fade_duration; + float advance = mHour-6; + float factor = advance / 3.f; result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor); result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor); result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor); result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor); } - else - { - result.mFogColor = current.mFogSunriseColor; - result.mAmbientColor = current.mAmbientSunriseColor; - result.mSunColor = current.mSunSunriseColor; - result.mSkyColor = current.mSkySunriseColor; - } } - + // day - else if (mHour >= (WeatherGlobals::mSunriseTime) && mHour <= (WeatherGlobals::mSunsetTime)) + else if (mHour >= 9 && mHour <= 17) { result.mFogColor = current.mFogDayColor; result.mAmbientColor = current.mAmbientDayColor; result.mSunColor = current.mSunDayColor; result.mSkyColor = current.mSkyDayColor; } - + // sunset - else if (mHour >= (WeatherGlobals::mSunsetTime) && mHour <= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) + else if (mHour >= 17 && mHour <= 21) { - if (mHour <= (WeatherGlobals::mSunsetTime+fade_duration)) + if (mHour <= 19) { // fade in - float advance = (WeatherGlobals::mSunsetTime+fade_duration)-mHour; - float factor = (advance / fade_duration); + float advance = 19-mHour; + float factor = (advance / 2); result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor); result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor); result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor); result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor); } - else if (mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration)) + else //if (mHour >= 19) { // fade out - float advance = mHour-(WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration); - float factor = advance / fade_duration; + float advance = mHour-19; + float factor = advance / 2.f; result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor); result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor); result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor); result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor); result.mNightFade = factor; } - else - { - result.mFogColor = current.mFogSunsetColor; - result.mAmbientColor = current.mAmbientSunsetColor; - result.mSunColor = current.mSunSunsetColor; - result.mSkyColor = current.mSkySunsetColor; - } } - + return result; } @@ -454,43 +454,36 @@ WeatherResult WeatherManager::transition(float factor) const WeatherResult& current = getResult(mCurrentWeather); const WeatherResult& other = getResult(mNextWeather); WeatherResult result; - + result.mCloudTexture = current.mCloudTexture; result.mNextCloudTexture = other.mCloudTexture; result.mCloudBlendFactor = factor; - + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mFogColor = lerp(current.mFogColor, other.mFogColor); result.mSunColor = lerp(current.mSunColor, other.mSunColor); result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor); - + result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor); result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); + //result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); + result.mCloudSpeed = current.mCloudSpeed; result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mGlareView = lerp(current.mGlareView, other.mGlareView); - + result.mNight = current.mNight; - - // sound change behaviour: - // if 'other' has a new sound, switch to it after 1/2 of the transition length - if (other.mAmbientLoopSoundID != "") - result.mAmbientLoopSoundID = factor>0.5 ? other.mAmbientLoopSoundID : current.mAmbientLoopSoundID; - // if 'current' has a sound and 'other' does not have a sound, turn off the sound immediately - else if (current.mAmbientLoopSoundID != "") - result.mAmbientLoopSoundID = ""; - + return result; } void WeatherManager::update(float duration) { - mWeatherUpdateTime -= duration; + mWeatherUpdateTime -= duration * mEnvironment->mWorld->getTimeScaleFactor(); bool exterior = (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()); - + if (exterior) { std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region; @@ -499,17 +492,17 @@ void WeatherManager::update(float duration) if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { mCurrentRegion = regionstr; - mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*60.f; - + mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*3600; + std::string weather; - + if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) weather = mRegionOverrides[regionstr]; else { // get weather probabilities for the current region const ESM::Region *region = mEnvironment->mWorld->getStore().regions.find (regionstr); - + float clear = region->data.clear/255.f; float cloudy = region->data.cloudy/255.f; float foggy = region->data.foggy/255.f; @@ -518,86 +511,84 @@ void WeatherManager::update(float duration) float thunder = region->data.thunder/255.f; float ash = region->data.ash/255.f; float blight = region->data.blight/255.f; - float snow = region->data.a/255.f; - float blizzard = region->data.b/255.f; - + //float snow = region->data.a/255.f; + //float blizzard = region->data.b/255.f; + // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; - + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; + srand(time(NULL)); float random = ((rand()%100)/100.f) * total; - - if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blizzard"; - else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "snow"; - else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) + + //if (random > snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + // weather = "blizzard"; + //else if (random > blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + // weather = "snow"; + /*else*/ if (random > ash+thunder+rain+overcast+foggy+cloudy+clear) weather = "blight"; - else if (random >= thunder+rain+overcast+foggy+cloudy+clear) + else if (random > thunder+rain+overcast+foggy+cloudy+clear) weather = "ashstorm"; - else if (random >= rain+overcast+foggy+cloudy+clear) + else if (random > rain+overcast+foggy+cloudy+clear) weather = "thunderstorm"; - else if (random >= overcast+foggy+cloudy+clear) + else if (random > overcast+foggy+cloudy+clear) weather = "rain"; - else if (random >= foggy+cloudy+clear) + else if (random > foggy+cloudy+clear) weather = "overcast"; - else if (random >= cloudy+clear) + else if (random > cloudy+clear) weather = "foggy"; - else if (random >= clear) + else if (random > clear) weather = "cloudy"; else weather = "clear"; } - + setWeather(weather, false); - /* - std::cout << "roll result: " << random << std::endl; - - std::cout << regionstr << " weather probabilities: " << clear << " " << cloudy << " " << foggy << " " - << overcast << " " << rain << " " << thunder << " " << ash << " " << blight << " " << snow << " " - << blizzard << std::endl; - - std::cout << "New weather : " << weather << std::endl; - */ } - + WeatherResult result; - + if (mNextWeather != "") { - mRemainingTransitionTime -= duration; + mRemainingTransitionTime -= duration * mEnvironment->mWorld->getTimeScaleFactor(); if (mRemainingTransitionTime < 0) { mCurrentWeather = mNextWeather; mNextWeather = ""; } } - + if (mNextWeather != "") - result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60))); + result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600))); else result = getResult(mCurrentWeather); - + mRendering->configureFog(result.mFogDepth, result.mFogColor); - + // disable sun during night - if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration - || mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) + if (mHour >= 20 || mHour <= 6.f) mRendering->getSkyManager()->sunDisable(); else - { - // during day, calculate sun angle - float height = 1-std::abs(((mHour-13)/7.f)); - int facing = mHour > 13.f ? 1 : -1; - Vector3 final( - (1-height)*facing, - (1-height)*facing, - height); - mRendering->setSunDirection(final); - mRendering->getSkyManager()->sunEnable(); - } - + + // sun angle + float height; + + // rise at 6, set at 20 + if (mHour >= 6 && mHour <= 20) + height = 1-std::abs(((mHour-13)/7.f)); + else if (mHour > 20) + height = (mHour-20.f)/4.f; + else //if (mHour > 0 && mHour < 6) + height = 1-(mHour/6.f); + + int facing = (mHour > 13.f) ? 1 : -1; + + Vector3 final( + (1-height)*facing, + (1-height)*facing, + height); + mRendering->setSunDirection(final); + // moon calculations float night; if (mHour >= 14) @@ -606,9 +597,9 @@ void WeatherManager::update(float duration) night = mHour+10; else night = 0; - + night /= 20.f; - + if (night != 0) { float moonHeight = 1-std::abs((night-0.5)*2); @@ -617,17 +608,17 @@ void WeatherManager::update(float duration) (1-moonHeight)*facing, (1-moonHeight)*facing, moonHeight); - + Vector3 secunda( (1-moonHeight)*facing*0.8, (1-moonHeight)*facing*1.25, moonHeight); - + mRendering->getSkyManager()->setMasserDirection(masser); mRendering->getSkyManager()->setSecundaDirection(secunda); mRendering->getSkyManager()->masserEnable(); mRendering->getSkyManager()->secundaEnable(); - + float hour_fade; if (mHour >= 7.f && mHour <= 14.f) hour_fade = 1-(mHour-7)/3.f; @@ -635,28 +626,28 @@ void WeatherManager::update(float duration) hour_fade = mHour-14; else hour_fade = 1; - + float secunda_angle_fade; float masser_angle_fade; float angle = moonHeight*90.f; - + if (angle >= 30 && angle <= 50) secunda_angle_fade = (angle-30)/20.f; else if (angle <30) secunda_angle_fade = 0.f; else secunda_angle_fade = 1.f; - + if (angle >= 40 && angle <= 50) masser_angle_fade = (angle-40)/10.f; else if (angle <40) masser_angle_fade = 0.f; else masser_angle_fade = 1.f; - + masser_angle_fade *= hour_fade; secunda_angle_fade *= hour_fade; - + mRendering->getSkyManager()->setMasserFade(masser_angle_fade); mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); } @@ -665,7 +656,7 @@ void WeatherManager::update(float duration) mRendering->getSkyManager()->masserDisable(); mRendering->getSkyManager()->secundaDisable(); } - + if (mCurrentWeather == "thunderstorm" && mNextWeather == "" && exterior) { if (mThunderFlash > 0) @@ -684,7 +675,7 @@ void WeatherManager::update(float duration) mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0); mThunderSoundDelay = 1000; } - + mThunderFlash -= duration; if (mThunderFlash > 0) mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); @@ -703,20 +694,20 @@ void WeatherManager::update(float duration) if (mThunderChance >= mThunderChanceNeeded) { mThunderFlash = WeatherGlobals::mThunderThreshold; - + mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); - + mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; } } } else mRendering->getSkyManager()->setThunder(0.f); - + mRendering->setAmbientColour(result.mAmbientColor); mRendering->sunEnable(); mRendering->setSunColour(result.mSunColor); - + mRendering->getSkyManager()->setWeather(result); } else @@ -765,15 +756,6 @@ void WeatherManager::update(float duration) void WeatherManager::setHour(const float hour) { - // accelerate a bit for testing - /* - mHour += 0.005; - - if (mHour >= 24.f) mHour = 0.f; - - std::cout << "hour " << mHour << std::endl; - */ - mHour = hour; } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 1828a90c9..b9b40e6fa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -95,18 +95,18 @@ namespace MWWorld Script Color=255,20,20 */ - static const float mSunriseTime = 8; - static const float mSunsetTime = 18; - static const float mSunriseDuration = 2; - static const float mSunsetDuration = 2; + static const float mSunriseTime; + static const float mSunsetTime; + static const float mSunriseDuration; + static const float mSunsetDuration; - static const float mWeatherUpdateTime = 20.f; + static const float mWeatherUpdateTime; // morrowind sets these per-weather, but since they are only used by 'thunderstorm' // weather setting anyway, we can just as well set them globally - static const float mThunderFrequency = .4; - static const float mThunderThreshold = 0.6; - static const float mThunderSoundDelay = 0.25; + static const float mThunderFrequency; + static const float mThunderThreshold; + static const float mThunderSoundDelay; static const std::string mThunderSoundID0; static const std::string mThunderSoundID1; static const std::string mThunderSoundID2; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 1c47e3c71..a636ce288 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -478,7 +478,7 @@ namespace MWWorld float World::getTimeScaleFactor() const { - return mGlobalVariables->getInt ("timescale"); + return mGlobalVariables->getFloat ("timescale"); } void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 78d0ef24e..fb4a090c6 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -405,10 +405,22 @@ macro(ogre_find_plugin PLUGIN HEADER) set(OGRE_${PLUGIN}_LIBRARY_NAMES "${PLUGIN}${OGRE_LIB_SUFFIX}") get_debug_names(OGRE_${PLUGIN}_LIBRARY_NAMES) set(OGRE_${PLUGIN}_LIBRARY_FWK ${OGRE_LIBRARY_FWK}) + # Search for release plugins in OGRE dir with version suffix find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) + if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_REL}") + # Search for release plugins in OGRE dir without version suffix + find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) + endif() + # Search for debug plugins in OGRE dir with version suffix find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt debug debug/opt) + if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_DBG}") + # Search for debug plugins in OGRE dir without version suffix + find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) + endif() make_library_set(OGRE_${PLUGIN}_LIBRARY) if (OGRE_${PLUGIN}_LIBRARY OR OGRE_${PLUGIN}_INCLUDE_DIR) @@ -441,9 +453,13 @@ macro(ogre_find_plugin PLUGIN HEADER) PATH_SUFFIXES "" bin bin/debug debug) elseif (UNIX) get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_REL} PATH) - set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)") + # For some reason this fails + #set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)") + set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP}) get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_DBG} PATH) - set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)") + # Same here + #set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)") + set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP}) endif () endif () diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 06c3207e2..95480c023 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -639,7 +639,7 @@ namespace Compiler std::vector& code, bool invert) { bool optional = false; - bool optionalCount = 0; + int optionalCount = 0; ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true); StringParser stringParser (getErrorHandler(), getContext(), mLiterals); diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ce142847f..ac0ee63f1 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -24,7 +24,7 @@ namespace Compiler mLineParser.reset(); if (mLineParser.parseName (name, loc, scanner)) scanner.scan (mLineParser); - + return true; } @@ -34,22 +34,22 @@ namespace Compiler { mControlParser.reset(); if (mControlParser.parseKeyword (keyword, loc, scanner)) - scanner.scan (mControlParser); - + scanner.scan (mControlParser); + mControlParser.appendCode (mOutput.getCode()); - + return true; } - + if (keyword==Scanner::K_end && mEnd) { return false; } - + mLineParser.reset(); if (mLineParser.parseKeyword (keyword, loc, scanner)) scanner.scan (mLineParser); - + return true; } @@ -57,11 +57,11 @@ namespace Compiler { if (code==Scanner::S_newline) // empty line return true; - + mLineParser.reset(); if (mLineParser.parseSpecial (code, loc, scanner)) scanner.scan (mLineParser); - + return true; } @@ -77,4 +77,3 @@ namespace Compiler mOutput.clear(); } } - diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 396a88c78..fe7bd30b9 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -39,6 +39,11 @@ namespace Compiler mState = CommaState; return true; } + else if (code==Scanner::S_newline && mState==StartState) + { + scanner.putbackSpecial (code, loc); + return false; + } return Parser::parseSpecial (code, loc, scanner); } diff --git a/extern/mygui_3.0.1/CMakeLists.txt b/extern/mygui_3.0.1/CMakeLists.txt index 38f8abbba..9cba61344 100644 --- a/extern/mygui_3.0.1/CMakeLists.txt +++ b/extern/mygui_3.0.1/CMakeLists.txt @@ -34,6 +34,7 @@ configure_file("${SDIR}/openmw_chargen_class_description_layout.xml" "${DDIR}/op configure_file("${SDIR}/openmw_chargen_birth_layout.xml" "${DDIR}/openmw_chargen_birth_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_chargen_review_layout.xml" "${DDIR}/openmw_chargen_review_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_dialogue_window_layout.xml" "${DDIR}/openmw_dialogue_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_dialogue_window_skin.xml" "${DDIR}/openmw_dialogue_window_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_inventory_window_layout.xml" "${DDIR}/openmw_inventory_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_layers.xml" "${DDIR}/openmw_layers.xml" COPYONLY) configure_file("${SDIR}/openmw_mainmenu_layout.xml" "${DDIR}/openmw_mainmenu_layout.xml" COPYONLY) diff --git a/extern/mygui_3.0.1/openmw_resources/core.xml b/extern/mygui_3.0.1/openmw_resources/core.xml index 31d409a35..e98b20d3a 100644 --- a/extern/mygui_3.0.1/openmw_resources/core.xml +++ b/extern/mygui_3.0.1/openmw_resources/core.xml @@ -20,6 +20,7 @@ + diff --git a/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_layout.xml b/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_layout.xml index 2987e82be..44642167b 100644 --- a/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_layout.xml +++ b/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_layout.xml @@ -17,8 +17,13 @@ + + + + - + diff --git a/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_skin.xml b/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_skin.xml new file mode 100644 index 000000000..25e0b8659 --- /dev/null +++ b/extern/mygui_3.0.1/openmw_resources/openmw_dialogue_window_skin.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/readme.txt b/readme.txt index 88c170088..d53ec379c 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind 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.12.0 +Version: 0.13.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -96,11 +96,15 @@ athile Cris “Mirceam” Mihalache gugus / gus Jacob “Yacoby” Essex +Jannik “scrawl” Heller Jason “jhooks” Hooks +Karl-Felix “k1ll” Glatzer Lukasz “lgro” Gromanowski Marc “Zini” Zinnschlag +Michael “werdanith” Papageorgiou Nikolay “corristo” Kasyanov Pieter “pvdk” van der Kloet +Roman "Kromgart" Melnik Sebastian “swick” Wick Retired Developers: @@ -110,7 +114,6 @@ Diggory Hardy Jan Borsodi Jan-Peter “peppe” Nilsson Josua Grawitter -Karl-Felix “k1ll” Glatzer Nicolay Korslund sergoz Star-Demon @@ -125,6 +128,38 @@ Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Fil CHANGELOG +0.13.0 + +Bug #145: Fixed sound problems after cell change +Bug #179: Pressing space in console triggers activation +Bug #186: CMake doesn't use the debug versions of Ogre libraries on Linux +Bug #189: ASCII 16 character added to console on it's activation on Mac OS X +Bug #190: Case Folding fails with music files +Bug #192: Keypresses write Text into Console no matter which gui element is active +Bug #196: Collision shapes out of place +Bug #202: ESMTool doesn't not work with localised ESM files anymore +Bug #203: Torch lights only visible on short distance +Bug #207: Ogre.log not written +Bug #209: Sounds do not play +Bug #210: Ogre crash at Dren plantation +Bug #214: Unsupported file format version +Feature #9: NPC Dialogue Window +Feature #16/42: New sky/weather implementation +Feature #40: Fading +Feature #48: NPC Dialogue System +Feature #117: Equipping Items (backend only, no GUI yet, no rendering of equipped items yet) +Feature #161: Load REC_PGRD records +Feature #195: Wireframe-mode +Feature #198/199: Various sound effects +Feature #206: Allow picking data path from launcher if non is set +Task #108: Refactor window manager class +Task #172: Sound Manager Cleanup +Task #173: Create OpenEngine systems in the appropriate manager classes +Task #184: Adjust MSVC and gcc warning levels +Task #185: RefData rewrite +Task #201: Workaround for transparency issues +Task #208: silenced esm_reader.hpp warning + 0.12.0 Bug #154: FPS Drop