diff --git a/CMakeLists.txt b/CMakeLists.txt index a1b054853a..723d10b347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,17 @@ IF (APPLE) set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk") ENDIF (APPLE) +# Macros + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) + +include (OpenMWMacros) + # Version set (OPENMW_VERSION_MAJOR 0) set (OPENMW_VERSION_MINOR 11) -set (OPENMW_VERSION_RELEASE 0) +set (OPENMW_VERSION_RELEASE 1) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -76,171 +82,6 @@ ELSE() message (STATUS "OpenMW pre-built binaries not found. Using standard locations.") ENDIF() -# Add path for CMake scripts -set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) - -# source directory: components -set(COMP_DIR ${CMAKE_SOURCE_DIR}/components) - -set(BSA - ${COMP_DIR}/bsa/bsa_archive.cpp - ${COMP_DIR}/bsa/bsa_file.cpp) -set(BSA_HEADER - ${COMP_DIR}/bsa/bsa_archive.hpp - ${COMP_DIR}/bsa/bsa_file.hpp) -source_group(components\\bsa FILES ${BSA} ${BSA_HEADER}) - -set(CFG - ${COMP_DIR}/cfg/configurationmanager.cpp - ) -set(CFG_HEADER - ${COMP_DIR}/cfg/configurationmanager.hpp - ) -source_group(components\\cfg FILES ${CFG} ${CFG_HEADER}) - -set(NIF - ${COMP_DIR}/nif/nif_file.cpp) -set(NIF_HEADER - ${COMP_DIR}/nif/controlled.hpp - ${COMP_DIR}/nif/effect.hpp - ${COMP_DIR}/nif/nif_types.hpp - ${COMP_DIR}/nif/record.hpp - ${COMP_DIR}/nif/controller.hpp - ${COMP_DIR}/nif/extra.hpp - ${COMP_DIR}/nif/node.hpp - ${COMP_DIR}/nif/record_ptr.hpp - ${COMP_DIR}/nif/data.hpp - ${COMP_DIR}/nif/nif_file.hpp - ${COMP_DIR}/nif/property.hpp) -source_group(components\\nif FILES ${NIF} ${NIF_HEADER}) - -set(NIFOGRE - ${COMP_DIR}/nifogre/ogre_nif_loader.cpp) -set(NIFOGRE_HEADER - ${COMP_DIR}/nifogre/ogre_nif_loader.hpp) -source_group(components\\nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER}) - -set(NIFBULLET - ${COMP_DIR}/nifbullet/bullet_nif_loader.cpp) -set(NIFBULLET_HEADER - ${COMP_DIR}/nifbullet/bullet_nif_loader.hpp) -source_group(components\\nifbullet FILES ${NIFBULLET} ${NIFBULLET_HEADER}) - -set(TO_UTF8 - ${COMP_DIR}/to_utf8/to_utf8.cpp) -set(TO_UTF8_HEADER - ${COMP_DIR}/to_utf8/to_utf8.hpp) -source_group(components\\to_utf8 FILES ${TO_UTF8} ${TO_UTF8_HEADER}) - -set(FILE_FINDER - ${COMP_DIR}/file_finder/search.cpp) -set(FILE_FINDER_HEADER - ${COMP_DIR}/file_finder/file_finder.hpp - ${COMP_DIR}/file_finder/filename_less.hpp - ${COMP_DIR}/file_finder/search.hpp) -source_group(components\\file_finder FILES ${FILE_FINDER} ${FILE_FINDER_HEADER}) - -set(ESM_STORE - ${COMP_DIR}/esm_store/store.cpp) -set(ESM_STORE_HEADER - ${COMP_DIR}/esm_store/cell_store.hpp - ${COMP_DIR}/esm_store/reclists.hpp - ${COMP_DIR}/esm_store/store.hpp) -source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER}) - -file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp) -set(ESM - ${COMP_DIR}/esm/attr.cpp - ${COMP_DIR}/esm/esm_reader.cpp - ${COMP_DIR}/esm/loadland.cpp - ${COMP_DIR}/esm/loadacti.cpp - ${COMP_DIR}/esm/loadalch.cpp - ${COMP_DIR}/esm/loadappa.cpp - ${COMP_DIR}/esm/loadarmo.cpp - ${COMP_DIR}/esm/loadbody.cpp - ${COMP_DIR}/esm/loadbook.cpp - ${COMP_DIR}/esm/loadbsgn.cpp - ${COMP_DIR}/esm/loadcell.cpp - ${COMP_DIR}/esm/loadclas.cpp - ${COMP_DIR}/esm/loadclot.cpp - ${COMP_DIR}/esm/loadcont.cpp - ${COMP_DIR}/esm/loadcrea.cpp - ${COMP_DIR}/esm/loaddial.cpp - ${COMP_DIR}/esm/loaddoor.cpp - ${COMP_DIR}/esm/loadench.cpp - ${COMP_DIR}/esm/loadfact.cpp - ${COMP_DIR}/esm/loadglob.cpp - ${COMP_DIR}/esm/loadgmst.cpp - ${COMP_DIR}/esm/loadinfo.cpp - ${COMP_DIR}/esm/loadingr.cpp - ${COMP_DIR}/esm/loadlevlist.cpp - ${COMP_DIR}/esm/loadligh.cpp - ${COMP_DIR}/esm/loadlocks.cpp - ${COMP_DIR}/esm/loadltex.cpp - ${COMP_DIR}/esm/loadmgef.cpp - ${COMP_DIR}/esm/loadmisc.cpp - ${COMP_DIR}/esm/loadnpc.cpp - ${COMP_DIR}/esm/loadpgrd.cpp - ${COMP_DIR}/esm/loadrace.cpp - ${COMP_DIR}/esm/loadregn.cpp - ${COMP_DIR}/esm/loadscpt.cpp - ${COMP_DIR}/esm/loadskil.cpp - ${COMP_DIR}/esm/loadsndg.cpp - ${COMP_DIR}/esm/loadsoun.cpp - ${COMP_DIR}/esm/loadspel.cpp - ${COMP_DIR}/esm/loadsscr.cpp - ${COMP_DIR}/esm/loadstat.cpp - ${COMP_DIR}/esm/loadweap.cpp - -) -source_group(components\\esm FILES ${ESM_HEADER} ${ESM}) - -set(MISC - ${COMP_DIR}/misc/stringops.cpp - ) -set(MISC_HEADER - ${COMP_DIR}/misc/slice_array.hpp - ${COMP_DIR}/misc/stringops.hpp - ) -source_group(components\\misc FILES ${MISC} ${MISC_HEADER}) - -set(FILES - ${COMP_DIR}/files/linuxpath.cpp - ${COMP_DIR}/files/windowspath.cpp - ${COMP_DIR}/files/macospath.cpp - ${COMP_DIR}/files/multidircollection.cpp - ${COMP_DIR}/files/collections.cpp - ${COMP_DIR}/files/fileops.cpp - ) -set(FILES_HEADER - ${COMP_DIR}/files/linuxpath.hpp - ${COMP_DIR}/files/windowspath.hpp - ${COMP_DIR}/files/macospath.hpp - ${COMP_DIR}/files/path.hpp - ${COMP_DIR}/files/multidircollection.hpp - ${COMP_DIR}/files/collections.hpp - ${COMP_DIR}/files/fileops.hpp - ) -source_group(components\\files FILES ${FILES} ${FILES_HEADER}) - -file(GLOB COMPILER ${COMP_DIR}/compiler/*.cpp) -file(GLOB COMPILER_HEADER ${COMP_DIR}/compiler/*.hpp) -source_group(components\\compiler FILES ${COMPILER} ${COMPILER_HEADER}) - -file(GLOB INTERPRETER ${COMP_DIR}/interpreter/*.cpp) -file(GLOB INTERPRETER_HEADER ${COMP_DIR}/interpreter/*.hpp) -source_group(components\\interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER}) - -set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${MISC} ${TO_UTF8} - ${COMPILER} ${INTERPRETER} ${ESM} ${FILE_FINDER} ${NIFBULLET} ${FILES} - ${CFG} - ) -set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER} - ${ESM_HEADER} ${MISC_HEADER} ${COMPILER_HEADER} ${TO_UTF8_HEADER} - ${INTERPRETER_HEADER} ${FILE_FINDER_HEADER} ${NIFBULLET_HEADER} ${FILES_HEADER} - ${CFG_HEADER} - ) - # source directory: libs set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) @@ -444,10 +285,10 @@ set(CPACK_GENERATOR "Bundle") set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist") set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns") set(CPACK_BUNDLE_NAME "OpenMW") -set(CPACK_PACKAGE_VERSION "0.10") -set(CPACK_PACKAGE_VERSION_MAJOR "0") -set(CPACK_PACKAGE_VERSION_MINOR "10") -set(CPACK_PACKAGE_VERSION_PATCH "") +set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) +set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) +set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) +set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) include(CPack) @@ -471,6 +312,10 @@ if(DPKG_PROGRAM) set(PACKAGE_MAINTAINER "unknown") endif() + #Install icon and desktop file + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "share/pixmaps/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + #Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") @@ -489,8 +334,8 @@ if(DPKG_PROGRAM) Data files from the original game is required to run it.") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW") - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libogremain-1.7.1 (>= 1.7.1-1), libbullet2.77 (>= 2.77), libboost-filesystem1.42.0 (>= 1.42.0), libboost-program-options1.42.0 (>= 1.42.0), libboost-system1.42.0 (>= 1.42.0), libboost-thread1.42.0 (>= 1.42.0), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.2.0 (>= 1.2.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2)") + 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_SECTION "Games") @@ -506,6 +351,9 @@ if(DPKG_PROGRAM) include(CPack) endif(DPKG_PROGRAM) +# Components +add_subdirectory (components) + # Apps and tools add_subdirectory( apps/openmw ) diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 583f1fabd1..f2ab7bce74 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -8,13 +8,11 @@ source_group(apps\\esmtool FILES ${ESMTOOL}) # Main executable add_executable(esmtool ${ESMTOOL} - ${MISC} ${MISC_HEADER} - ${TO_UTF8} - ${ESM} ) target_link_libraries(esmtool ${Boost_LIBRARIES} + components ) #if (APPLE) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 38a8948662..2fc3189fc0 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -8,6 +8,8 @@ set(LAUNCHER playpage.cpp pluginsmodel.cpp pluginsview.cpp + + launcher.rc ) set(LAUNCHER_HEADER @@ -50,11 +52,6 @@ include(${QT_USE_FILE}) # Main executable add_executable(omwlauncher ${LAUNCHER} - ${MISC} ${MISC_HEADER} - ${FILES} ${FILES_HEADER} - ${CFG} ${CFG_HEADER} - ${TO_UTF8} - ${ESM} ${RCC_SRCS} ${MOC_SRCS} ) @@ -64,8 +61,13 @@ target_link_libraries(omwlauncher ${OGRE_LIBRARIES} ${QT_LIBRARIES} ${PNG_LIBRARY} + components ) +if(DPKG_PROGRAM) + INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher) +endif() + if (APPLE) configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss "${APP_BUNDLE_DIR}/../launcher.qss") @@ -74,7 +76,7 @@ if (APPLE) else() configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss") - + configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg") endif() diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 7f4662e428..c8311846f5 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -144,7 +144,7 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict) { QString currentMaster = QString::fromStdString( boost::filesystem::path (iter->second.filename()).string()); - + const QList itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly); if (itemList.isEmpty()) // Master is not yet in the widget @@ -178,9 +178,12 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict) if (itemList.isEmpty()) // Master is not yet in the widget { - // TODO: Show warning, missing master mMastersWidget->insertRow(i); + QTableWidgetItem *item = new QTableWidgetItem(currentMaster); + item->setForeground(Qt::red); + item->setFlags(item->flags() & ~(Qt::ItemIsSelectable)); + mMastersWidget->setItem(i, 0, item); } } @@ -189,9 +192,31 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict) // Now we put the current plugin in the mDataFilesModel under its masters QStandardItem *parent = new QStandardItem(availableMasters.join(",")); - - QStandardItem *child = new QStandardItem(QString::fromStdString( - boost::filesystem::path (iter->second.filename()).string())); + + 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()); + + // 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)); + + child->setToolTip(toolTip); const QList masterList = mDataFilesModel->findItems(availableMasters.join(",")); @@ -644,6 +669,10 @@ void DataFilesPage::scrollToSelection() void DataFilesPage::showContextMenu(const QPoint &point) { + // Make sure there are plugins in the view + if (!mPluginsTable->selectionModel()->hasSelection()) { + return; + } QPoint globalPos = mPluginsTable->mapToGlobal(point); @@ -763,6 +792,7 @@ void DataFilesPage::addPlugins(const QModelIndex &index) if (childIndex.isValid()) { // Now we see if the pluginsmodel already contains this plugin const QString childIndexData = QVariant(mDataFilesModel->data(childIndex)).toString(); + const QString childIndexToolTip = QVariant(mDataFilesModel->data(childIndex, Qt::ToolTipRole)).toString(); const QList itemList = mPluginsModel->findItems(childIndexData); @@ -772,6 +802,7 @@ void DataFilesPage::addPlugins(const QModelIndex &index) QStandardItem *item = new QStandardItem(childIndexData); item->setFlags(item->flags() & ~(Qt::ItemIsDropEnabled)); item->setCheckable(true); + item->setToolTip(childIndexToolTip); mPluginsModel->appendRow(item); } @@ -937,6 +968,11 @@ void DataFilesPage::readConfig() void DataFilesPage::writeConfig(QString profile) { + // Don't overwrite the config if no plugins are found + if (mPluginsModel->rowCount() < 1) { + return; + } + if (profile.isEmpty()) { profile = mProfilesComboBox->currentText(); } diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 300be27914..92fbf3350b 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -156,14 +156,34 @@ void GraphicsPage::setupOgre() { QString pluginCfg = mCfg.getPluginsConfigPath().string().c_str(); QFile file(pluginCfg); - + // Create a log manager so we can surpress debug text to stdout/stderr Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager; logMgr->createLog((mCfg.getLogPath().string() + "/launcherOgre.log"), true, false, false); + QString ogreCfg = QString::fromStdString(mCfg.getOgreConfigPath().string()); + file.setFileName(ogreCfg); + + //we need to check that the path to the configuration file exists before we + //try and create an instance of Ogre::Root otherwise Ogre raises an exception + QDir configDir = QFileInfo(file).dir(); + if ( !configDir.exists() && !configDir.mkpath(configDir.path()) ) + { + QMessageBox msgBox; + msgBox.setWindowTitle("Error creating config file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QString(tr("
Failed to create the configuration file

\ + Make sure you have write access to
%1

")).arg(configDir.path())); + msgBox.exec(); + + QApplication::exit(1); + return; + } + try { - mOgre = new Ogre::Root(pluginCfg.toStdString()); + mOgre = new Ogre::Root(pluginCfg.toStdString(), file.fileName().toStdString(), "./launcherOgre.log"); } catch(Ogre::Exception &ex) { @@ -180,7 +200,8 @@ void GraphicsPage::setupOgre() qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError)); - std::exit(1); + QApplication::exit(1); + return; } // Get the available renderers and put them in the combobox @@ -213,7 +234,8 @@ void GraphicsPage::setupOgre() Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); msgBox.exec(); - std::exit(1); + QApplication::exit(1); + return; } // Now fill the GUI elements @@ -318,95 +340,115 @@ void GraphicsPage::readConfig() void GraphicsPage::writeConfig() { - // Write the config file settings + mOgre->setRenderSystem(mSelectedRenderSystem); - // Custom write method: We cannot use QSettings because it does not accept spaces - QFile file(mOgreConfig->fileName()); + if (mDirect3DRenderSystem) { + // Nvidia Performance HUD + if (mD3DNvPerfCheckBox->checkState() == Qt::Checked) { + mDirect3DRenderSystem->setConfigOption("Allow NVPerfHUD", "Yes"); + } else { + mDirect3DRenderSystem->setConfigOption("Allow NVPerfHUD", "No"); + } - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - // File could not be opened, + // Antialiasing + mDirect3DRenderSystem->setConfigOption("FSAA", mD3DAntiAliasingComboBox->currentText().toStdString()); + + // Full screen + if (mD3DFullScreenCheckBox->checkState() == Qt::Checked) { + mDirect3DRenderSystem->setConfigOption("Full Screen", "Yes"); + } else { + mDirect3DRenderSystem->setConfigOption("Full Screen", "No"); + } + + // Rendering device + mDirect3DRenderSystem->setConfigOption("Rendering Device", mD3DRenderDeviceComboBox->currentText().toStdString()); + + // VSync + if (mD3DVSyncCheckBox->checkState() == Qt::Checked) { + mDirect3DRenderSystem->setConfigOption("VSync", "Yes"); + } else { + mDirect3DRenderSystem->setConfigOption("VSync", "No"); + } + + // Resolution + mDirect3DRenderSystem->setConfigOption("Video Mode", mD3DResolutionComboBox->currentText().toStdString()); + } + + if (mOpenGLRenderSystem) { + // Display Frequency + mOpenGLRenderSystem->setConfigOption("Display Frequency", mOGLFrequencyComboBox->currentText().toStdString()); + + // Antialiasing + mOpenGLRenderSystem->setConfigOption("FSAA", mOGLAntiAliasingComboBox->currentText().toStdString()); + + // Full screen + if (mOGLFullScreenCheckBox->checkState() == Qt::Checked) { + mOpenGLRenderSystem->setConfigOption("Full Screen", "Yes"); + } else { + mOpenGLRenderSystem->setConfigOption("Full Screen", "No"); + } + + // RTT mode + mOpenGLRenderSystem->setConfigOption("RTT Preferred Mode", mOGLRTTComboBox->currentText().toStdString()); + + // VSync + if (mOGLVSyncCheckBox->checkState() == Qt::Checked) { + mOpenGLRenderSystem->setConfigOption("VSync", "Yes"); + } else { + mOpenGLRenderSystem->setConfigOption("VSync", "No"); + } + + // Resolution + mOpenGLRenderSystem->setConfigOption("Video Mode", mOGLResolutionComboBox->currentText().toStdString()); + } + + // Now we validate the options + QString ogreError = QString::fromStdString(mSelectedRenderSystem->validateConfigOptions()); + + if (!ogreError.isEmpty()) { QMessageBox msgBox; - msgBox.setWindowTitle("Error opening Ogre configuration file"); + msgBox.setWindowTitle("Error validating Ogre configuration"); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not open %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); + msgBox.setText(tr("
A problem occured while validating the graphics options

\ + The graphics options could not be saved.

\ + Press \"Show Details...\" for more information.
")); + msgBox.setDetailedText(ogreError); msgBox.exec(); + + Ogre::LogManager::getSingletonPtr()->logMessage( "Caught exception in validateConfigOptions"); + + qCritical("Error validating configuration"); + + QApplication::exit(1); return; } - QTextStream out(&file); + // Write the settings to the config file - out << "Render System=" << mSelectedRenderSystem->getName().c_str() << endl << endl; - if (mDirect3DRenderSystem) { - QString direct3DName = mDirect3DRenderSystem->getName().c_str(); - direct3DName.prepend("["); - direct3DName.append("]"); - out << direct3DName << endl; - - if (mD3DNvPerfCheckBox->checkState() == Qt::Checked) { - out << "Allow NVPerfHUD=Yes" << endl; - } else { - out << "Allow NVPerfHUD=No" << endl; - } - - out << "FSAA=" << mD3DAntiAliasingComboBox->currentText() << endl; - out << "Floating-point mode=" << mD3DFloatingPointComboBox->currentText() << endl; - - if (mD3DFullScreenCheckBox->checkState() == Qt::Checked) { - out << "Full Screen=Yes" << endl; - } else { - out << "Full Screen=No" << endl; - } - - out << "Rendering Device=" << mD3DRenderDeviceComboBox->currentText() << endl; - out << "Resource Creation Policy=Create on all devices" << endl; - - if (mD3DVSyncCheckBox->checkState() == Qt::Checked) { - out << "VSync=Yes" << endl; - } else { - out << "VSync=No" << endl; - } - - out << "VSync Interval=1" << endl; - out << "Video Mode=" << mD3DResolutionComboBox->currentText() << endl; - out << "sRGB Gamma Conversion=No" << endl; + try + { + mOgre->saveConfig(); } + catch(Ogre::Exception &ex) + { + QString ogreError = QString::fromStdString(ex.getFullDescription().c_str()); + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing Ogre configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not write the graphics configuration

\ + Please make sure you have the right permissions and try again.

\ + Press \"Show Details...\" for more information.
")); + msgBox.setDetailedText(ogreError); + msgBox.exec(); - out << endl; + qCritical("Error saving Ogre configuration, the error reported was:\n %s", qPrintable(ogreError)); - if (mOpenGLRenderSystem) { - QString openGLName = mOpenGLRenderSystem->getName().c_str(); - openGLName.prepend("["); - openGLName.append("]"); - out << openGLName << endl; - - out << "Colour Depth=32" << endl; - out << "Display Frequency=" << mOGLFrequencyComboBox->currentText() << endl; - out << "FSAA=" << mOGLAntiAliasingComboBox->currentText() << endl; - - if (mOGLFullScreenCheckBox->checkState() == Qt::Checked) { - out << "Full Screen=Yes" << endl; - } else { - out << "Full Screen=No" << endl; - } - - out << "RTT Preferred Mode=" << mOGLRTTComboBox->currentText() << endl; - - if (mOGLVSyncCheckBox->checkState() == Qt::Checked) { - out << "VSync=Yes" << endl; - } else { - out << "VSync=No" << endl; - } - - out << "VSync Interval=1" << endl; - out << "Video Mode=" << mOGLResolutionComboBox->currentText() << endl; - out << "sRGB Gamma Conversion=No" << endl; + QApplication::exit(1); } - file.close(); - } QString GraphicsPage::getConfigValue(const QString &key, Ogre::RenderSystem *renderer) diff --git a/apps/launcher/launcher.pro b/apps/launcher/launcher.pro deleted file mode 100644 index 0b4e4618d8..0000000000 --- a/apps/launcher/launcher.pro +++ /dev/null @@ -1,30 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Fri Jun 24 21:14:15 2011 -###################################################################### - -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -HEADERS += combobox.hpp \ - datafilespage.hpp \ - graphicspage.hpp \ - lineedit.hpp \ - maindialog.hpp \ - naturalsort.hpp \ - playpage.hpp \ - pluginsmodel.hpp \ - pluginsview.hpp -SOURCES += datafilespage.cpp \ - graphicspage.cpp \ - lineedit.cpp \ - main.cpp \ - maindialog.cpp \ - naturalsort.cpp \ - playpage.cpp \ - pluginsmodel.cpp \ - pluginsview.cpp -RESOURCES += resources.qrc -win32:RC_FILE = launcher.rc diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b125bf13bc..4ec8b309cc 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -48,7 +48,6 @@ MainDialog::MainDialog() connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); - setupConfig(); createIcons(); createPages(); } @@ -86,17 +85,11 @@ void MainDialog::createIcons() } -void MainDialog::createPages() +QStringList MainDialog::readConfig(const QString &fileName) { - // Various pages - mPlayPage = new PlayPage(this); - mGraphicsPage = new GraphicsPage(this); - mDataFilesPage = new DataFilesPage(this); - - // First we retrieve all data= keys from the config // We can't use QSettings directly because it // does not support multiple keys with the same name - QFile file(mGameConfig->fileName()); + QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msgBox; @@ -104,34 +97,91 @@ void MainDialog::createPages() msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); + Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); QApplication::exit(); // File cannot be opened or created } QTextStream in(&file); - QStringList dataDirs; + QString dataLocal; - // Add each data= value + // Read the config line by line while (!in.atEnd()) { QString line = in.readLine(); if (line.startsWith("data=")) { dataDirs.append(line.remove("data=")); } + + // Read the data-local key, if more than one are found only the last is used + if (line.startsWith("data-local=")) { + dataLocal = line.remove("data-local="); + } + + // Read fs-strict key + if (line.startsWith("fs-strict=")) { + QString value = line.remove("fs-strict="); + + (value.toLower() == QLatin1String("true")) + ? mStrict = true + : mStrict = false; + + } + } - // Add the data-local= key - QString dataLocal = mGameConfig->value("data-local").toString(); + // Add the data-local= key to the end of the dataDirs for priority reasons if (!dataLocal.isEmpty()) { dataDirs.append(dataLocal); } + if (!dataDirs.isEmpty()) + { + // Reset the global datadirs to the newly read entries + // Else return the previous dataDirs because nothing was found in this file; + mDataDirs = dataDirs; + } + + file.close(); + + return mDataDirs; +} + +void MainDialog::createPages() +{ + mPlayPage = new PlayPage(this); + mGraphicsPage = new GraphicsPage(this); + mDataFilesPage = new DataFilesPage(this); + + // Retrieve all data entries from the configs + QStringList dataDirs; + + // Global location + QFile file(QString::fromStdString((mCfg.getGlobalConfigPath()/"openmw.cfg").string())); + if (file.exists()) { + dataDirs = readConfig(file.fileName()); + } + + // User location + file.setFileName(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string())); + if (file.exists()) { + dataDirs = readConfig(file.fileName()); + } + + // Local location + file.setFileName("./openmw.cfg"); + + if (file.exists()) { + dataDirs = readConfig(file.fileName()); + } + + file.close(); + if (!dataDirs.isEmpty()) { // Now pass the datadirs on to the DataFilesPage - mDataFilesPage->setupDataFiles(dataDirs, mGameConfig->value("fs-strict").toBool()); + mDataFilesPage->setupDataFiles(dataDirs, mStrict); } else { QMessageBox msgBox; msgBox.setWindowTitle("Error reading OpenMW configuration file"); @@ -264,24 +314,6 @@ void MainDialog::play() } } -void MainDialog::setupConfig() -{ - Cfg::ConfigurationManager cfg; - - // First we read the OpenMW config - QString config = (cfg.getRuntimeConfigPath() / "openmw.cfg").string().c_str(); - QFile file(config); - - if (!file.exists()) { - config = QString::fromStdString((cfg.getLocalConfigPath() / "openmw.cfg").string()); - } - - file.close(); - - // Open our config file - mGameConfig = new QSettings(config, QSettings::IniFormat); -} - void MainDialog::writeConfig() { // Write the profiles @@ -296,19 +328,19 @@ void MainDialog::writeConfig() dataFiles.append(mDataFilesPage->checkedPlugins()); // Open the config as a QFile - QFile file(mGameConfig->fileName()); + QFile file(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string())); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setWindowTitle("Error writing OpenMW configuration file"); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not open %0

\ + msgBox.setText(tr("
Could not open or create %0

\ Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); - return; + QApplication::exit(1); } QTextStream in(&file); @@ -334,10 +366,11 @@ void MainDialog::writeConfig() Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); - return; + QApplication::exit(1); } file.write(buffer); + QTextStream out(&file); // Write the list of game files to the config diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index c6f22e3361..047050902a 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -3,11 +3,14 @@ #include +#include + class QListWidget; class QListWidgetItem; class QStackedWidget; +class QStringList; class QStringListModel; -class QSettings; +class QString; class PlayPage; class GraphicsPage; @@ -29,10 +32,11 @@ public slots: private: void createIcons(); void createPages(); - void setupConfig(); void writeConfig(); void closeEvent(QCloseEvent *event); + QStringList readConfig(const QString &fileName); + QListWidget *mIconWidget; QStackedWidget *mPagesWidget; @@ -40,7 +44,10 @@ private: GraphicsPage *mGraphicsPage; DataFilesPage *mDataFilesPage; - QSettings *mGameConfig; + QStringList mDataDirs; + bool mStrict; + + Cfg::ConfigurationManager mCfg; }; #endif diff --git a/apps/launcher/resources/images/openmw.ico b/apps/launcher/resources/images/openmw.ico index c04fc3d9ce..aa248e6ad5 100644 Binary files a/apps/launcher/resources/images/openmw.ico and b/apps/launcher/resources/images/openmw.ico differ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 21f3e18a2a..90b7522642 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -15,242 +15,59 @@ set(GAME_HEADER config.hpp) source_group(game FILES ${GAME} ${GAME_HEADER}) -set(GAMEREND - mwrender/rendering_manager.cpp - mwrender/mwscene.cpp - mwrender/cellimp.cpp - mwrender/interior.cpp - mwrender/exterior.cpp - mwrender/sky.cpp - mwrender/player.cpp +add_openmw_dir (mwrender + rendering_manager mwscene cellimp interior exterior sky player ) -set(GAMEREND_HEADER - mwrender/rendering_manager.hpp - mwrender/cell.hpp - mwrender/cellimp.hpp - mwrender/mwscene.hpp - mwrender/interior.hpp - mwrender/exterior.hpp - mwrender/sky.hpp - mwrender/player.hpp - ) -source_group(apps\\openmw\\mwrender FILES ${GAMEREND} ${GAMEREND_HEADER}) -set(GAMEINPUT - mwinput/inputmanager.cpp -) -set(GAMEINPUT_HEADER - mwinput/inputmanager.hpp) -source_group(apps\\openmw\\mwinput FILES ${GAMEINPUT} ${GAMEINPUT_HEADER}) +add_openmw_dir (mwinput + inputmanager + ) -set(GAMEGUI_HEADER - mwgui/layouts.hpp - mwgui/text_input.hpp - mwgui/widgets.hpp - mwgui/race.hpp - mwgui/class.hpp - mwgui/birth.hpp - mwgui/review.hpp - mwgui/window_manager.hpp - mwgui/console.hpp - mwgui/dialogue.hpp - mwgui/dialogue_history.hpp - mwgui/window_base.hpp - mwgui/stats_window.hpp - mwgui/messagebox.hpp -) -set(GAMEGUI - mwgui/window_manager.cpp - mwgui/layouts.cpp - mwgui/console.cpp - mwgui/text_input.cpp - mwgui/widgets.cpp - mwgui/race.cpp - mwgui/birth.cpp - mwgui/class.cpp - mwgui/review.cpp - mwgui/dialogue.cpp - mwgui/dialogue_history.cpp - mwgui/window_base.cpp - mwgui/stats_window.cpp - mwgui/messagebox.cpp -) -source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) +add_openmw_dir (mwgui + layouts text_input widgets race class birth review window_manager console dialogue + dialogue_history window_base stats_window messagebox + ) -set(GAMEDIALOGUE_HEADER - mwdialogue/dialoguemanager.hpp - mwdialogue/journal.hpp - mwdialogue/journalentry.hpp - mwdialogue/quest.hpp - mwdialogue/topic.hpp -) -set(GAMEDIALOGUE - mwdialogue/dialoguemanager.cpp - mwdialogue/journal.cpp - mwdialogue/journalentry.cpp - mwdialogue/quest.cpp - mwdialogue/topic.cpp -) -source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) +add_openmw_dir (mwdialogue + dialoguemanager journal journalentry quest topic + ) -set(GAMESCRIPT - mwscript/scriptmanager.cpp - mwscript/compilercontext.cpp - mwscript/interpretercontext.cpp - mwscript/cellextensions.cpp - mwscript/miscextensions.cpp - mwscript/guiextensions.cpp - mwscript/soundextensions.cpp - mwscript/skyextensions.cpp - mwscript/statsextensions.cpp - mwscript/containerextensions.cpp - mwscript/aiextensions.cpp - mwscript/controlextensions.cpp - mwscript/extensions.cpp - mwscript/globalscripts.cpp - mwscript/dialogueextensions.cpp +add_openmw_dir (mwscript + locals scriptmanager compilercontext interpretercontext cellextensions miscextensions + guiextensions soundextensions skyextensions statsextensions containerextensions + aiextensions controlextensions extensions globalscripts ref dialogueextensions ) -set(GAMESCRIPT_HEADER - mwscript/locals.hpp - mwscript/scriptmanager.hpp - mwscript/compilercontext.hpp - mwscript/interpretercontext.hpp - mwscript/cellextensions.hpp - mwscript/miscextensions.hpp - mwscript/guiextensions.hpp - mwscript/soundextensions.hpp - mwscript/skyextensions.hpp - mwscript/statsextensions.hpp - mwscript/containerextensions.hpp - mwscript/aiextensions.hpp - mwscript/controlextensions.hpp - mwscript/extensions.hpp - mwscript/globalscripts.hpp - mwscript/ref.hpp - mwscript/dialogueextensions.hpp - ) -source_group(apps\\openmw\\mwscript FILES ${GAMESCRIPT} ${GAMESCRIPT_HEADER}) -set(GAMESOUND - mwsound/soundmanager.cpp) -set(GAMESOUND_HEADER - mwsound/soundmanager.hpp) -source_group(apps\\openmw\\mwsound FILES ${GAMESOUND} ${GAMESOUND_HEADER}) +add_openmw_dir (mwsound + soundmanager + ) -set(GAMEWORLD - mwworld/world.cpp - mwworld/scene.cpp - mwworld/physicssystem.cpp - mwworld/globals.cpp - mwworld/class.cpp - mwworld/actionteleport.cpp - mwworld/actiontalk.cpp - mwworld/actiontake.cpp - mwworld/containerutil.cpp - mwworld/player.cpp - mwworld/cells.cpp +add_openmw_dir (mwworld + refdata world physicssystem scene environment globals class action nullaction actionteleport + containerstore actiontalk actiontake containerstore manualref containerutil player cellfunctors + cells localscripts ) -set(GAMEWORLD_HEADER - mwworld/refdata.hpp - mwworld/world.hpp - mwworld/physicssystem.hpp - mwworld/scene.hpp - mwworld/environment.hpp - mwworld/globals.hpp - mwworld/class.hpp - mwworld/action.hpp - mwworld/nullaction.hpp - mwworld/actionteleport.hpp - mwworld/containerstore.hpp - mwworld/actiontalk.hpp - mwworld/actiontake.hpp - mwworld/containerstore.hpp - mwworld/manualref.hpp - mwworld/containerutil.hpp - mwworld/player.hpp - mwworld/cellfunctors.hpp - mwworld/cells.hpp - ) -source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER}) -set(GAMECLASS - mwclass/classes.cpp - mwclass/activator.cpp - mwclass/creature.cpp - mwclass/npc.cpp - mwclass/weapon.cpp - mwclass/armor.cpp - mwclass/potion.cpp - mwclass/apparatus.cpp - mwclass/book.cpp - mwclass/clothing.cpp - mwclass/container.cpp - mwclass/door.cpp - mwclass/ingredient.cpp - mwclass/creaturelevlist.cpp - mwclass/itemlevlist.cpp - mwclass/light.cpp - mwclass/lockpick.cpp - mwclass/misc.cpp - mwclass/probe.cpp - mwclass/repair.cpp - mwclass/static.cpp +add_openmw_dir (mwclass + classes activator creature npc weapon armor potion apparatus book clothing container door + ingredient creaturelevlist itemlevlist light lockpick misc probe repair static ) -set(GAMECLASS_HEADER - mwclass/classes.hpp - mwclass/activator.hpp - mwclass/creature.hpp - mwclass/npc.hpp - mwclass/weapon.hpp - mwclass/armor.hpp - mwclass/potion.hpp - mwclass/apparatus.hpp - mwclass/book.hpp - mwclass/clothing.hpp - mwclass/container.hpp - mwclass/door.hpp - mwclass/ingredient.hpp - mwclass/creaturelevlist.hpp - mwclass/itemlevlist.hpp - mwclass/light.hpp - mwclass/lockpick.hpp - mwclass/misc.hpp - mwclass/probe.hpp - mwclass/repair.hpp - mwclass/static.hpp - mwclass/containerutil.hpp - ) -source_group(apps\\openmw\\mwclass FILES ${GAMECLASS} ${GAMECLASS_HEADER}) -set(GAMEMECHANICS - mwmechanics/mechanicsmanager.cpp - mwmechanics/magiceffects.cpp - ) -set(GAMEMECHANICS_HEADER - mwmechanics/mechanicsmanager.hpp - mwmechanics/stat.hpp - mwmechanics/creaturestats.hpp - mwmechanics/magiceffects.hpp - mwmechanics/movement.hpp - ) -source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER}) - -set(OPENMW_CPP ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT} ${GAMESOUND} ${GAMEGUI} ${GAMEWORLD} - ${GAMECLASS} ${GAMEMECHANICS} ${GAMEDIALOGUE} - ) -set(OPENMW_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER} ${GAMESCRIPT_HEADER} - ${GAMESOUND_HEADER} ${GAMEGUI_HEADER} ${GAMEWORLD_HEADER} ${GAMECLASS_HEADER} - ${GAMEMECHANICS_HEADER} ${GAMEDIALOG_HEADERUE} +add_openmw_dir (mwmechanics + mechanicsmanager stat creaturestats magiceffects movement ) # Main executable add_executable(openmw - ${COMPONENTS} ${COMPONENTS_HEADER} ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} - ${OPENMW_CPP} ${OPENMW_HEADER} + ${CONPONENT_FILES} + ${OPENMW_FILES} + ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} ) +target_link_libraries (openmw components) + # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e9ceea2f34..7fa98f8e2c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,22 +6,24 @@ #include #include -#include -#include +#include -#include "components/esm/records.hpp" +#include + +#include +#include + +#include #include -#include #include -#include #include #include - -#include -#include "mwgui/window_manager.hpp" +#include #include "mwinput/inputmanager.hpp" +#include "mwgui/window_manager.hpp" + #include "mwscript/scriptmanager.hpp" #include "mwscript/compilercontext.hpp" #include "mwscript/interpretercontext.hpp" @@ -43,116 +45,76 @@ #include "mwmechanics/mechanicsmanager.hpp" -#include - -#include -#include "mwgui/class.hpp" - -#include "components/nifbullet/bullet_nif_loader.hpp" - -//using namespace ESM; - void OMW::Engine::executeLocalScripts() { - for (MWWorld::World::ScriptList::const_iterator iter ( - mEnvironment.mWorld->getLocalScripts().begin()); - iter!=mEnvironment.mWorld->getLocalScripts().end(); ++iter) - { - if (mIgnoreLocalPtr.isEmpty() || mIgnoreLocalPtr!=iter->second) - { - MWScript::InterpreterContext interpreterContext (mEnvironment, - &iter->second.getRefData().getLocals(), MWWorld::Ptr (iter->second)); - mScriptManager->run (iter->first, interpreterContext); + MWWorld::LocalScripts& localScripts = mEnvironment.mWorld->getLocalScripts(); - if (mEnvironment.mWorld->hasCellChanged()) - break; - } + localScripts.startIteration(); + + while (!localScripts.isFinished()) + { + std::pair script = localScripts.getNext(); + + MWScript::InterpreterContext interpreterContext (mEnvironment, + &script.second.getRefData().getLocals(), script.second); + mScriptManager->run (script.first, interpreterContext); + + if (mEnvironment.mWorld->hasCellChanged()) + break; } - mIgnoreLocalPtr = MWWorld::Ptr(); + localScripts.setIgnore (MWWorld::Ptr()); } +void OMW::Engine::updateFocusReport (float duration) +{ + if ((mFocusTDiff += duration)>0.25) + { + mFocusTDiff = 0; + + std::string name; + + std::string handle = mEnvironment.mWorld->getFacedHandle(); + + if (!handle.empty()) + { + MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + + if (!ptr.isEmpty()) + name = MWWorld::Class::get (ptr).getName (ptr); + } + + if (name!=mFocusName) + { + mFocusName = name; + + if (mFocusName.empty()) + std::cout << "Unfocus" << std::endl; + else + std::cout << "Focus: " << name << std::endl; + } + } +} bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { - if(mShowFPS) - { - mEnvironment.mWindowManager->wmSetFPS(mOgre.getFPS()); - } - - if(mUseSound && !(mEnvironment.mSoundManager->isMusicPlaying())) - { - // Play some good 'ol tunes - mEnvironment.mSoundManager->startRandomTitle(); - } - - std::string effect; - - MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); - - - //If the region has changed - if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){ - timer.restart(); - if (test.name != current->cell->region) - { - total = 0; - test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region)); - } - - if(test.soundList.size() > 0) - { - std::vector::iterator soundIter = test.soundList.begin(); - //mEnvironment.mSoundManager - if(total == 0){ - while (!(soundIter == test.soundList.end())) - { - ESM::NAME32 go = soundIter->sound; - int chance = (int) soundIter->chance; - //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - soundIter++; - total += chance; - } - } - - srand ( time(NULL) ); - int r = rand() % total; //old random code - int pos = 0; - soundIter = test.soundList.begin(); - while (!(soundIter == test.soundList.end())) - { - const ESM::NAME32 go = soundIter->sound; - int chance = (int) soundIter->chance; - //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - soundIter++; - if( r - pos < chance) - { - effect = go.name; - //play sound - std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0); - - break; - - } - pos += chance; - } - } - - //mEnvironment.mSoundManager->playSound(effect, 1.0, 1.0); - //printf("REGION: %s\n", test.name); - - } - else if(current->cell->data.flags & current->cell->Interior) - { - test.name = ""; - } - try { mEnvironment.mFrameDuration = evt.timeSinceLastFrame; - // + // sound + if (mUseSound) + { + if (!mEnvironment.mSoundManager->isMusicPlaying()) + mEnvironment.mSoundManager->startRandomTitle(); + + mEnvironment.mSoundManager->update (evt.timeSinceLastFrame); + } + + // update GUI + if(mShowFPS) + mEnvironment.mWindowManager->wmSetFPS(mOgre->getFPS()); + mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); // global scripts @@ -177,52 +139,39 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) std::vector > movement; mEnvironment.mMechanicsManager->update (movement); - if (focusFrameCounter++ == focusUpdateFrame) - { - std::string handle = mEnvironment.mWorld->getFacedHandle(); - - std::string name; - - if (!handle.empty()) - { - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); - - if (!ptr.isEmpty()) - name = MWWorld::Class::get (ptr).getName (ptr); - } - - if (!name.empty()) - std::cout << "Object: " << name << std::endl; - - focusFrameCounter = 0; - } - if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game) mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration); + + // report focus object (for debugging) + if (mReportFocus) + updateFocusReport (mEnvironment.mFrameDuration); } catch (const std::exception& e) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } - //std::cout << "TESTING2"; return true; } OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager) - : mPhysicEngine (0) + : mOgre (0) + , mPhysicEngine (0) , mShowFPS (false) , mDebug (false) , mVerboseScripts (false) , mNewGame (false) , mUseSound (true) , mCompileAll (false) + , mReportFocus (false) + , mFocusTDiff (0) , mScriptManager (0) , mScriptContext (0) , mGuiManager (0) , mFSStrict (false) , mCfgMgr(configurationManager) { + std::srand ( std::time(NULL) ); MWClass::registerClasses(); } @@ -238,6 +187,7 @@ OMW::Engine::~Engine() delete mScriptManager; delete mScriptContext; delete mPhysicEngine; + delete mOgre; } // Load all BSA files in data directory. @@ -261,7 +211,7 @@ void OMW::Engine::loadBSA() void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) { - mOgre.getRoot()->addResourceLocation (path.string(), "FileSystem", + mOgre->getRoot()->addResourceLocation (path.string(), "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); } @@ -325,6 +275,11 @@ void OMW::Engine::setNewGame(bool newGame) mNewGame = newGame; } +void OMW::Engine::setReportFocus (bool report) +{ + mReportFocus = report; +} + // Initialise and enter main loop. void OMW::Engine::go() @@ -332,11 +287,19 @@ void OMW::Engine::go() assert (!mEnvironment.mWorld); assert (!mCellName.empty()); assert (!mMaster.empty()); + assert (!mOgre); - test.name = ""; - total = 0; + mOgre = new OEngine::Render::OgreRenderer; - mOgre.configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()), + //we need to ensure the path to the configuration exists before creating an + //instance of ogre root so that Ogre doesn't raise an exception when trying to + //access it + const boost::filesystem::path configPath = mCfgMgr.getOgreConfigPath().parent_path(); + if ( !boost::filesystem::exists(configPath) ) + { + boost::filesystem::create_directories(configPath); + } + mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()), mCfgMgr.getOgreConfigPath().string(), mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getPluginsConfigPath().string(), false); @@ -346,28 +309,24 @@ void OMW::Engine::go() addResourcesDirectory(mResDir / "mygui"); // Create the window - mOgre.createWindow("OpenMW"); + mOgre->createWindow("OpenMW"); loadBSA(); + /// \todo move this into the physics manager // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mPhysicEngine = new OEngine::Physic::PhysicEngine(shapeLoader); // Create the world - mEnvironment.mWorld = new MWWorld::World (mOgre, mPhysicEngine, mFileCollections, mMaster, + mEnvironment.mWorld = new MWWorld::World (*mOgre, mPhysicEngine, mFileCollections, mMaster, mResDir, mNewGame, mEnvironment, mEncoding); + /// \todo move this into the GUI manager (a.k.a WindowManager) // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(), mOgre.getScene(), false, + mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, mCfgMgr.getLogPath().string() + std::string("/")); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); @@ -375,11 +334,11 @@ void OMW::Engine::go() mExtensions, mShowFPS, mNewGame); // Create sound system - mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre.getRoot(), - mOgre.getCamera(), + mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(), + mOgre->getCamera(), mEnvironment.mWorld->getStore(), (mDataDir), - mUseSound, mFSStrict); + mUseSound, mFSStrict, mEnvironment); // Create script system mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full, @@ -417,89 +376,68 @@ void OMW::Engine::go() } // Sets up the input system - MWInput::MWInputManager input(mOgre, mEnvironment.mWorld->getPlayer(), + MWInput::MWInputManager input(*mOgre, mEnvironment.mWorld->getPlayer(), *mEnvironment.mWindowManager, mDebug, *this); mEnvironment.mInputManager = &input; - focusFrameCounter = 0; - std::cout << "\nPress Q/ESC or close window to exit.\n"; - mOgre.getRoot()->addFrameListener (this); + mOgre->getRoot()->addFrameListener (this); // Play some good 'ol tunes - mEnvironment.mSoundManager->startRandomTitle(); + mEnvironment.mSoundManager->startRandomTitle(); // scripts if (mCompileAll) { - typedef ESMS::ScriptListT::MapType Container; + std::pair result = mScriptManager->compileAll(); - Container scripts = mEnvironment.mWorld->getStore().scripts.list; - - int count = 0; - int success = 0; - - for (Container::const_iterator iter (scripts.begin()); iter!=scripts.end(); ++iter, ++count) - if (mScriptManager->compile (iter->first)) - ++success; - - if (count) + if (result.first) std::cout - << "compiled " << success << " of " << count << " scripts (" - << 100*static_cast (success)/count + << "compiled " << result.second << " of " << result.first << " scripts (" + << 100*static_cast (result.second)/result.first << "%)" << std::endl; - } // Start the main rendering loop - mOgre.start(); + mOgre->start(); std::cout << "Quitting peacefully.\n"; } void OMW::Engine::activate() { - // TODO: This is only a workaround. The input dispatcher should catch any exceptions thrown inside - // the input handling functions. Looks like this will require an OpenEngine modification. - try + std::string handle = mEnvironment.mWorld->getFacedHandle(); + + if (handle.empty()) + return; + + MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + + if (ptr.isEmpty()) + return; + + MWScript::InterpreterContext interpreterContext (mEnvironment, + &ptr.getRefData().getLocals(), ptr); + + boost::shared_ptr action = + MWWorld::Class::get (ptr).activate (ptr, mEnvironment.mWorld->getPlayer().getPlayer(), + mEnvironment); + + interpreterContext.activate (ptr, action); + + std::string script = MWWorld::Class::get (ptr).getScript (ptr); + + if (!script.empty()) { - std::string handle = mEnvironment.mWorld->getFacedHandle(); - - if (handle.empty()) - return; - - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); - - if (ptr.isEmpty()) - return; - - MWScript::InterpreterContext interpreterContext (mEnvironment, - &ptr.getRefData().getLocals(), ptr); - - boost::shared_ptr action = - MWWorld::Class::get (ptr).activate (ptr, mEnvironment.mWorld->getPlayer().getPlayer(), - mEnvironment); - - interpreterContext.activate (ptr, action); - - std::string script = MWWorld::Class::get (ptr).getScript (ptr); - - if (!script.empty()) - { - mIgnoreLocalPtr = ptr; - mScriptManager->run (script, interpreterContext); - } - - if (!interpreterContext.hasActivationBeenHandled()) - { - interpreterContext.executeActivation(); - } + mEnvironment.mWorld->getLocalScripts().setIgnore (ptr); + mScriptManager->run (script, interpreterContext); } - catch (const std::exception& e) + + if (!interpreterContext.hasActivationBeenHandled()) { - std::cerr << "Activation failed: " << e.what() << std::endl; + interpreterContext.executeActivation(); } } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 3df0d0b3af..443f790a47 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -7,15 +7,14 @@ #include -#include #include + #include #include +#include #include "mwworld/environment.hpp" #include "mwworld/ptr.hpp" -#include -#include namespace Compiler { @@ -48,6 +47,11 @@ namespace OEngine { class MyGUIManager; } + + namespace Render + { + class OgreRenderer; + } } namespace OMW @@ -58,7 +62,7 @@ namespace OMW std::string mEncoding; boost::filesystem::path mDataDir; boost::filesystem::path mResDir; - OEngine::Render::OgreRenderer mOgre; + OEngine::Render::OgreRenderer *mOgre; OEngine::Physic::PhysicEngine* mPhysicEngine; std::string mCellName; std::string mMaster; @@ -68,20 +72,15 @@ namespace OMW bool mNewGame; bool mUseSound; bool mCompileAll; - int total; + bool mReportFocus; + float mFocusTDiff; + std::string mFocusName; MWWorld::Environment mEnvironment; MWScript::ScriptManager *mScriptManager; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; OEngine::GUI::MyGUIManager *mGuiManager; - ESM::Region test; - boost::timer timer; - - int focusFrameCounter; - static const int focusUpdateFrame = 10; - - MWWorld::Ptr mIgnoreLocalPtr; Files::Collections mFileCollections; bool mFSStrict; @@ -100,9 +99,9 @@ namespace OMW void executeLocalScripts(); - virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); + void updateFocusReport (float duration); - /// Process pending commands + virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); public: Engine(Cfg::ConfigurationManager& configurationManager); @@ -144,6 +143,9 @@ namespace OMW /// Start as a new game. void setNewGame(bool newGame); + /// Write name of focussed object to cout + void setReportFocus (bool report); + /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index aa8b13b80d..933d1c48aa 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -102,6 +102,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" "\n\twin1252 - Western European (Latin) alphabet, used by default") + + ("report-focus", boost::program_options::value()->implicit_value(true) + ->default_value(false), "write name of focussed object to cout") ; bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) @@ -202,6 +205,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio engine.setSoundUsage(!variables["nosound"].as()); engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setCompileAll(variables["script-all"].as()); + engine.setReportFocus(variables["report-focus"].as()); return true; } diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 7a72ddb8cf..4d4b7aeaae 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -21,7 +21,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2dbeae3605..ddf96d1be9 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index d637956412..9452fea161 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 964ccbdfe6..c2d3c4aa81 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index a264f2a1cd..7c69573ed5 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 1da55e6f69..ad2ab8d655 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -21,7 +21,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/containerutil.hpp b/apps/openmw/mwclass/containerutil.hpp index 5f89983acb..76bdf02361 100644 --- a/apps/openmw/mwclass/containerutil.hpp +++ b/apps/openmw/mwclass/containerutil.hpp @@ -16,10 +16,7 @@ namespace MWClass { // TODO check stacking - ESMS::LiveCellRef cellRef; - - cellRef.base = ptr.get()->base; - cellRef.ref = ptr.getCellRef(); + ESMS::LiveCellRef cellRef(ptr.getCellRef(), ptr.get()->base); cellRef.mData = ptr.getRefData(); containerStore.list.push_back (cellRef); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 0bd133f21c..2e223c918c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -33,7 +33,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh("meshes\\" + model); cellRender.insertActorPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 8a34d3abe5..e32e3ef4eb 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -28,7 +28,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index c88e1794b6..e2c9b072f2 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 159196eb2c..f32378002f 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -28,7 +28,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 9a4b98b431..3a94fce261 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 2986c812d9..84560d009c 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 9ef5e6f406..83161ebeb3 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -64,7 +64,7 @@ namespace MWClass std::string hairModel = "meshes\\" + environment.mWorld->getStore().bodyParts.find(hairID)->model; - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); //TODO: define consts for each bodypart e.g. chest, foot, wrist... and put the parts in the diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 6c9889a7b8..7cd6db223f 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 028d8b5e3e..b92f5ff267 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index b9b5036fbc..d52f04e536 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index cf0be94992..5691f92baa 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -19,7 +19,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref, true); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData, true); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a985a7e42f..5dcc94fc8e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -24,7 +24,7 @@ namespace MWClass const std::string &model = ref->base->model; if (!model.empty()) { - MWRender::Rendering rendering (cellRender, ref->ref); + MWRender::Rendering rendering (cellRender, ref->ref, ref->mData); cellRender.insertMesh ("meshes\\" + model); cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index eeac575196..be4632b41a 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -79,6 +79,12 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment playerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat())); } + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + // Set up visibility updateVisible(); } @@ -333,7 +339,7 @@ void WindowManager::updateVisible() dialogueWindow->open(); return; } - + if(mode == GM_InterMessageBox) { if(!mMessageBoxManager->isInteractiveMessageBox()) { diff --git a/apps/openmw/mwrender/cellimp.hpp b/apps/openmw/mwrender/cellimp.hpp index 664fed64f0..c497b1d19c 100644 --- a/apps/openmw/mwrender/cellimp.hpp +++ b/apps/openmw/mwrender/cellimp.hpp @@ -35,7 +35,7 @@ namespace MWRender virtual ~CellRenderImp() {} /// start inserting a new reference. - virtual void insertBegin (ESM::CellRef &ref, bool static_ = false) = 0; + virtual void insertBegin (ESM::CellRef& ref, MWWorld::RefData& refData, bool static_ = false) = 0; virtual void rotateMesh(Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName[], int elements) = 0; /// insert a mesh related to the most recent insertBegin call. @@ -71,10 +71,10 @@ namespace MWRender public: - Rendering (CellRenderImp& cellRender, ESM::CellRef &ref, bool static_ = false) + Rendering (CellRenderImp& cellRender, ESM::CellRef& ref, MWWorld::RefData& refData, bool static_ = false) : mCellRender (cellRender), mEnd (false) { - mCellRender.insertBegin (ref, static_); + mCellRender.insertBegin (ref, refData, static_); } ~Rendering() diff --git a/apps/openmw/mwrender/exterior.cpp b/apps/openmw/mwrender/exterior.cpp index 9dd82c68f1..aa8ca0a3cb 100644 --- a/apps/openmw/mwrender/exterior.cpp +++ b/apps/openmw/mwrender/exterior.cpp @@ -43,7 +43,7 @@ ExteriorCellRender::ExteriorCellRender(ESMS::CellStore &_cell, -void ExteriorCellRender::insertBegin (ESM::CellRef &ref, bool static_) +void ExteriorCellRender::insertBegin (ESM::CellRef &ref, MWWorld::RefData& refData, bool static_) { assert (!mInsert); diff --git a/apps/openmw/mwrender/exterior.hpp b/apps/openmw/mwrender/exterior.hpp index d8f6b9b96c..24464698f4 100644 --- a/apps/openmw/mwrender/exterior.hpp +++ b/apps/openmw/mwrender/exterior.hpp @@ -70,7 +70,7 @@ namespace MWRender Ogre::ColourValue mAmbientColor; /// start inserting a new reference. - virtual void insertBegin (ESM::CellRef &ref, bool static_ = false); + virtual void insertBegin (ESM::CellRef &ref, MWWorld::RefData& refData, bool static_ = false); /// insert a mesh related to the most recent insertBegin call. virtual void insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements); diff --git a/apps/openmw/mwrender/interior.cpp b/apps/openmw/mwrender/interior.cpp index bfde4b04e0..99843272f6 100644 --- a/apps/openmw/mwrender/interior.cpp +++ b/apps/openmw/mwrender/interior.cpp @@ -35,14 +35,14 @@ bool InteriorCellRender::lightOutQuadInLin = false; // start inserting a new reference. -void InteriorCellRender::insertBegin (ESM::CellRef &ref, bool static_) +void InteriorCellRender::insertBegin (ESM::CellRef &ref, MWWorld::RefData& refData, bool static_) { assert (!insert); // Create and place scene node for this object insert = base->createChildSceneNode(); - const float *f = ref.pos.pos; + const float *f = refData.getPosition().pos; insert->setPosition(f[0], f[1], f[2]); insert->setScale(ref.scale, ref.scale, ref.scale); diff --git a/apps/openmw/mwrender/interior.hpp b/apps/openmw/mwrender/interior.hpp index 16fca0898c..cc1b5661de 100644 --- a/apps/openmw/mwrender/interior.hpp +++ b/apps/openmw/mwrender/interior.hpp @@ -65,7 +65,7 @@ namespace MWRender Ogre::ColourValue ambientColor; /// start inserting a new reference. - virtual void insertBegin (ESM::CellRef &ref, bool static_ = false); + virtual void insertBegin (ESM::CellRef &ref, MWWorld::RefData& refData, bool static_ = false); virtual void rotateMesh(Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName[], int elements); virtual void scaleMesh(Ogre::Vector3 axis, std::string sceneNodeName[], int elements); /// insert a mesh related to the most recent insertBegin call. diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 6d74ae45a2..aa541e55d3 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -25,13 +25,13 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Float x = runtime[0].mInteger; + Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float y = runtime[0].mInteger; + Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float z = runtime[0].mInteger; + Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. @@ -53,16 +53,16 @@ namespace MWScript std::string actor = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float duration = runtime[0].mInteger; + Interpreter::Type_Float duration = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float x = runtime[0].mInteger; + Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float y = runtime[0].mInteger; + Interpreter::Type_Float y = runtime[0].mFloat; runtime.pop(); - Interpreter::Type_Float z = runtime[0].mInteger; + Interpreter::Type_Float z = runtime[0].mFloat; runtime.pop(); // discard additional arguments (reset), because we have no idea what they mean. @@ -99,9 +99,9 @@ namespace MWScript void registerExtensions (Compiler::Extensions& extensions) { - extensions.registerInstruction ("aitravel", "lll/l", opcodeAiTravel, + extensions.registerInstruction ("aitravel", "fff/l", opcodeAiTravel, opcodeAiTravelExplicit); - extensions.registerInstruction ("aiescort", "cllll/l", opcodeAiEscort, + extensions.registerInstruction ("aiescort", "cffff/l", opcodeAiEscort, opcodeAiEscortExplicit); extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone, diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 77a71a1d4d..258493782c 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -196,8 +196,10 @@ namespace MWScript double diff[3]; + const float* const pos1 = ref.getRefData().getPosition().pos; + const float* const pos2 = ref2.getRefData().getPosition().pos; for (int i=0; i<3; ++i) - diff[i] = ref.getCellRef().pos.pos[i] - ref2.getCellRef().pos.pos[i]; + diff[i] = pos1[i] - pos2[i]; return std::sqrt (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); } diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 07fa934547..5fcfcc6050 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -116,4 +116,20 @@ namespace MWScript iter->second.clear(); // don't execute again. } } + + std::pair ScriptManager::compileAll() + { + typedef ESMS::ScriptListT::MapType Container; + + const Container& scripts = mStore.scripts.list; + + int count = 0; + int success = 0; + + for (Container::const_iterator iter (scripts.begin()); iter!=scripts.end(); ++iter, ++count) + if (compile (iter->first)) + ++success; + + return std::make_pair (count, success); + } } diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index eab9bdcc08..74511f456e 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -52,6 +52,10 @@ namespace MWScript bool compile (const std::string& name); ///< Compile script with the given namen /// \return Success? + + std::pair compileAll(); + ///< Compile all scripts + /// \return count, success }; }; diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 970118a13b..7390e4c5ca 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -1,18 +1,23 @@ #include "soundmanager.hpp" #include +#include +#include + using namespace std; +#include + #include #include #include #include #include -#include -#include -#include +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" /* Set up the sound manager to use Audiere, FFMPEG or MPG123/libsndfile for input. The OPENMW_USE_x macros are set in @@ -378,12 +383,18 @@ namespace MWSound SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &store, boost::filesystem::path dataDir, - bool useSound, bool fsstrict) - : mData(NULL), fsStrict (fsstrict) + bool useSound, bool fsstrict, MWWorld::Environment& environment) + : mData(NULL), fsStrict (fsstrict), mEnvironment (environment) { MP3Lookup(dataDir / "Music/Explore/"); if(useSound) mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict); + + + test.name = ""; + total = 0; + + } SoundManager::~SoundManager() @@ -533,4 +544,64 @@ namespace MWSound if(!mData) return; mData->updatePositions(ptr); } + + void SoundManager::update (float duration) + { + std::string effect; + + MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); + + //If the region has changed + if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){ + timer.restart(); + if (test.name != current->cell->region) + { + total = 0; + test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region)); + } + + if(test.soundList.size() > 0) + { + std::vector::iterator soundIter = test.soundList.begin(); + //mEnvironment.mSoundManager + if(total == 0){ + while (!(soundIter == test.soundList.end())) + { + ESM::NAME32 go = soundIter->sound; + int chance = (int) soundIter->chance; + //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; + soundIter++; + total += chance; + } + } + + int r = rand() % total; //old random code + int pos = 0; + soundIter = test.soundList.begin(); + while (!(soundIter == test.soundList.end())) + { + const ESM::NAME32 go = soundIter->sound; + int chance = (int) soundIter->chance; + //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; + soundIter++; + if( r - pos < chance) + { + effect = go.name; + //play sound + std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; + mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0); + + break; + + } + pos += chance; + } + } + } + else if(current->cell->data.flags & current->cell->Interior) + { + test.name = ""; + } + + } } diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index ab9559176e..7dff16c761 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -8,6 +8,9 @@ #include "../mwworld/ptr.hpp" #include + +#include + namespace Ogre { class Root; @@ -19,6 +22,11 @@ namespace ESMS struct ESMStore; } +namespace MWWorld +{ + struct Environment; +} + namespace MWSound { //SoundPtr *music; @@ -31,6 +39,11 @@ namespace MWSound SoundImpl *mData; std::vector files; bool fsStrict; + MWWorld::Environment& mEnvironment; + + int total; + ESM::Region test; + boost::timer timer; void streamMusicFull (const std::string& filename); ///< Play a soundifle @@ -38,8 +51,9 @@ namespace MWSound public: - SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store, - boost::filesystem::path dataDir, bool useSound, bool fsstrict); + SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store, + boost::filesystem::path dataDir, bool useSound, bool fsstrict, + MWWorld::Environment& environment); ~SoundManager(); void streamMusic(const std::string& filename); @@ -60,8 +74,6 @@ namespace MWSound bool sayDone (MWWorld::Ptr reference) const; ///< Is actor not speaking? - - void playSound (const std::string& soundId, float volume, float pitch); ///< Play a sound, independently of 3D-position @@ -81,6 +93,8 @@ namespace MWSound void updateObject(MWWorld::Ptr reference); ///< Update the position of all sounds connected to the given object. + + void update (float duration); }; } diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 7d04cfc687..143ce557b5 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -4,6 +4,8 @@ #include +#include "world.hpp" + MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) { if (cell->data.flags & ESM::Cell::Interior) @@ -33,8 +35,8 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) } } -MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader) -: mStore (store), mReader (reader) {} +MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world) +: mStore (store), mReader (reader), mWorld (world) {} MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) { @@ -43,7 +45,21 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) if (result==mExteriors.end()) { - const ESM::Cell *cell = mStore.cells.findExt (x, y); + const ESM::Cell *cell = mStore.cells.searchExt (x, y); + + if (!cell) + { + // Cell isn't predefined. Make one on the fly. + ESM::Cell record; + + record.data.flags = 0; + record.data.gridX = x; + record.data.gridY = y; + record.water = 0; + record.mapColor = 0; + + cell = mWorld.createRecord (record); + } result = mExteriors.insert (std::make_pair ( std::make_pair (x, y), Ptr::CellStore (cell))).first; diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 661969881f..0ecbd02d37 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -18,6 +18,8 @@ namespace ESM namespace MWWorld { + class World; + /// \brief Cell container class Cells { @@ -25,6 +27,7 @@ namespace MWWorld ESM::ESMReader& mReader; std::map mInteriors; std::map, Ptr::CellStore> mExteriors; + MWWorld::World& mWorld; Cells (const Cells&); Cells& operator= (const Cells&); @@ -33,7 +36,9 @@ namespace MWWorld public: - Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader); + Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world); + ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole + /// world Ptr::CellStore *getExterior (int x, int y); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp new file mode 100644 index 0000000000..2d90d90e01 --- /dev/null +++ b/apps/openmw/mwworld/localscripts.cpp @@ -0,0 +1,126 @@ + +#include "localscripts.hpp" + +namespace +{ + template + void listCellScripts (MWWorld::LocalScripts& localScripts, + ESMS::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + { + for (typename ESMS::CellRefList::List::iterator iter ( + cellRefList.list.begin()); + iter!=cellRefList.list.end(); ++iter) + { + if (!iter->base->script.empty() && iter->mData.getCount()) + { + localScripts.add (iter->base->script, MWWorld::Ptr (&*iter, cell)); + } + } + } +} + +MWWorld::LocalScripts::LocalScripts (const ESMS::ESMStore& store) : mStore (store) {} + +void MWWorld::LocalScripts::setIgnore (const Ptr& ptr) +{ + mIgnore = ptr; +} + +void MWWorld::LocalScripts::startIteration() +{ + mIter = mScripts.begin(); +} + +bool MWWorld::LocalScripts::isFinished() const +{ + if (mIter==mScripts.end()) + return true; + + if (!mIgnore.isEmpty() && mIter->second==mIgnore) + { + std::list >::iterator iter = mIter; + return ++iter==mScripts.end(); + } + + return false; +} + +std::pair MWWorld::LocalScripts::getNext() +{ + assert (!isFinished()); + + std::list >::iterator iter = mIter++; + + if (mIgnore.isEmpty() || iter->second!=mIgnore) + return *iter; + + return getNext(); +} + +void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) +{ + if (const ESM::Script *script = mStore.scripts.find (scriptName)) + { + ptr.getRefData().setLocals (*script); + + mScripts.push_back (std::make_pair (scriptName, ptr)); + } +} + +void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell) +{ + listCellScripts (*this, cell->activators, cell); + listCellScripts (*this, cell->potions, cell); + listCellScripts (*this, cell->appas, cell); + listCellScripts (*this, cell->armors, cell); + listCellScripts (*this, cell->books, cell); + listCellScripts (*this, cell->clothes, cell); + listCellScripts (*this, cell->containers, cell); + listCellScripts (*this, cell->creatures, cell); + listCellScripts (*this, cell->doors, cell); + listCellScripts (*this, cell->ingreds, cell); + listCellScripts (*this, cell->lights, cell); + listCellScripts (*this, cell->lockpicks, cell); + listCellScripts (*this, cell->miscItems, cell); + listCellScripts (*this, cell->npcs, cell); + listCellScripts (*this, cell->probes, cell); + listCellScripts (*this, cell->repairs, cell); + listCellScripts (*this, cell->weapons, cell); +} + +void MWWorld::LocalScripts::clear() +{ + mScripts.clear(); +} + +void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) +{ + std::list >::iterator iter = mScripts.begin(); + + while (iter!=mScripts.end()) + { + if (iter->second.getCell()==cell) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter++); + } + else + ++iter; + } +} + +void MWWorld::LocalScripts::remove (const Ptr& ptr) +{ + for (std::list >::iterator iter = mScripts.begin(); + iter!=mScripts.end(); ++iter) + if (iter->second==ptr) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter); + break; + } +} diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp new file mode 100644 index 0000000000..1ea2cf4d5a --- /dev/null +++ b/apps/openmw/mwworld/localscripts.hpp @@ -0,0 +1,58 @@ +#ifndef GAME_MWWORLD_LOCALSCRIPTS_H +#define GAME_MWWORLD_LOCALSCRIPTS_H + +#include +#include + +#include "ptr.hpp" + +namespace ESMS +{ + struct ESMStore; +} + +namespace MWWorld +{ + /// \brief List of active local scripts + class LocalScripts + { + std::list > mScripts; + std::list >::iterator mIter; + MWWorld::Ptr mIgnore; + const ESMS::ESMStore& mStore; + + public: + + LocalScripts (const ESMS::ESMStore& store); + + void setIgnore (const Ptr& ptr); + ///< Mark a single reference for ignoring during iteration over local scripts (will revoke + /// previous ignores). + + void startIteration(); + ///< Set the iterator to the begin of the script list. + + bool isFinished() const; + ///< Is iteration finished? + + std::pair getNext(); + ///< Get next local script (must not be called if isFinished()) + + void add (const std::string& scriptName, const Ptr& ptr); + ///< Add script to collection of active local scripts. + + void addCell (Ptr::CellStore *cell); + ///< Add all local scripts in a cell. + + void clear(); + ///< Clear active local scripts collection. + + void clearCell (Ptr::CellStore *cell); + ///< Remove all scripts belonging to \a cell. + + void remove (const Ptr& ptr); + ///< Remove script for given reference (ignored if reference does not have a scirpt listed). + }; +} + +#endif diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index cad97c9ea5..db950b00ec 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -17,7 +17,10 @@ namespace MWWorld mName = player->name; mMale = !(player->flags & ESM::NPC::Female); mRace = player->race; - mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0; + + float* playerPos = mPlayer.mData.getPosition().pos; + playerPos[0] = playerPos[1] = playerPos[2] = 0; + std::cout << renderer->getHandle(); mPlayer.mData.setHandle (renderer->getHandle()); /// \todo Do not make a copy of classes defined in esm/p records. diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index a9613248e6..419bb2663b 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -41,9 +41,14 @@ namespace MWWorld boost::shared_ptr > mContainerStore; - public: + ESM::Position mPosition; - RefData() : mHasLocals (false), mEnabled (true), mCount (1) {} + public: + /// @param cr Used to copy constant data such as position into this class where it can + /// be altered without effecting the original data. This makes it possible + /// to reset the position as the orignal data is still held in the CellRef + RefData(const ESMS::CellRef& cr) : mHasLocals (false), mEnabled (true), + mCount (1), mPosition(cr.pos) {} std::string getHandle() { @@ -113,6 +118,11 @@ namespace MWWorld { return mContainerStore; } + + ESM::Position& getPosition() + { + return mPosition; + } }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 11bdad35f6..da9bff6b2e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -57,7 +57,7 @@ namespace MWWorld mPhysics->removeObject (*iter); } - mWorld->removeScripts (iter->first); + mWorld->getLocalScripts().clearCell (iter->first); mEnvironment.mMechanicsManager->dropActors (iter->first); mEnvironment.mSoundManager->stopSound (iter->first); @@ -68,7 +68,7 @@ namespace MWWorld void Scene::loadCell (Ptr::CellStore *cell, MWRender::CellRender *render) { // register local scripts - mWorld->insertInteriorScripts (*cell); + mWorld->getLocalScripts().addCell (cell); // This connects the cell data with the rendering scene. std::pair result = diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index ee1a0ad2d4..ff530454fe 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -27,7 +27,7 @@ namespace { template void listCellScripts (const ESMS::ESMStore& store, - ESMS::CellRefList& cellRefList, MWWorld::World::ScriptList& scriptList, + ESMS::CellRefList& cellRefList, MWWorld::LocalScripts& localScripts, MWWorld::Ptr::CellStore *cell) { for (typename ESMS::CellRefList::List::iterator iter ( @@ -40,8 +40,7 @@ namespace { iter->mData.setLocals (*script); - scriptList.push_back ( - std::make_pair (iter->base->script, MWWorld::Ptr (&*iter, cell))); + localScripts.add (iter->base->script, MWWorld::Ptr (&*iter, cell)); } } } @@ -67,28 +66,6 @@ namespace namespace MWWorld { - - void World::insertInteriorScripts (ESMS::CellStore& cell) - { - listCellScripts (mStore, cell.activators, mLocalScripts, &cell); - listCellScripts (mStore, cell.potions, mLocalScripts, &cell); - listCellScripts (mStore, cell.appas, mLocalScripts, &cell); - listCellScripts (mStore, cell.armors, mLocalScripts, &cell); - listCellScripts (mStore, cell.books, mLocalScripts, &cell); - listCellScripts (mStore, cell.clothes, mLocalScripts, &cell); - listCellScripts (mStore, cell.containers, mLocalScripts, &cell); - listCellScripts (mStore, cell.creatures, mLocalScripts, &cell); - listCellScripts (mStore, cell.doors, mLocalScripts, &cell); - listCellScripts (mStore, cell.ingreds, mLocalScripts, &cell); - listCellScripts (mStore, cell.lights, mLocalScripts, &cell); - listCellScripts (mStore, cell.lockpicks, mLocalScripts, &cell); - listCellScripts (mStore, cell.miscItems, mLocalScripts, &cell); - listCellScripts (mStore, cell.npcs, mLocalScripts, &cell); - listCellScripts (mStore, cell.probes, mLocalScripts, &cell); - listCellScripts (mStore, cell.repairs, mLocalScripts, &cell); - listCellScripts (mStore, cell.weapons, mLocalScripts, &cell); - } - Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell) { if (ESMS::LiveCellRef *ref = @@ -185,20 +162,6 @@ namespace MWWorld throw std::runtime_error ("month out of range"); } - void World::removeScripts (Ptr::CellStore *cell) - { - ScriptList::iterator iter = mLocalScripts.begin(); - - while (iter!=mLocalScripts.end()) - { - if (iter->second.getCell()==cell) - mLocalScripts.erase (iter++); - else - ++iter; - } - } - - void World::adjustSky() { if (mSky) @@ -213,8 +176,8 @@ namespace MWWorld const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment, const std::string& encoding) - : mScene (renderer,physEng), mPlayer (0), mGlobalVariables (0), - mSky (false), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm) + : mScene (renderer,physEng), mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), + mSky (false), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm, *this) { mPhysEngine = physEng; @@ -306,7 +269,7 @@ namespace MWWorld return mEsm; } - const World::ScriptList& World::getLocalScripts() const + LocalScripts& World::getLocalScripts() { return mLocalScripts; } @@ -574,6 +537,8 @@ namespace MWWorld mEnvironment.mSoundManager->stopSound3D (ptr); mPhysics->removeObject (ptr.getRefData().getHandle()); + + mLocalScripts.remove (ptr); } render->deleteObject (ptr.getRefData().getHandle()); @@ -584,9 +549,9 @@ namespace MWWorld void World::moveObjectImp (Ptr ptr, float x, float y, float z) { - ptr.getCellRef().pos.pos[0] = x; - ptr.getCellRef().pos.pos[1] = y; - ptr.getCellRef().pos.pos[2] = z; + ptr.getRefData().getPosition().pos[0] = x; + ptr.getRefData().getPosition().pos[1] = y; + ptr.getRefData().getPosition().pos[2] = z; if (ptr==mPlayer->getPlayer()) { @@ -603,7 +568,7 @@ namespace MWWorld if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY) { - mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getCellRef().pos, false); + mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false); } } @@ -722,4 +687,27 @@ namespace MWWorld return std::make_pair (stream.str(), created); } + + const ESM::Cell *World::createRecord (const ESM::Cell& record) + { + if (record.data.flags & ESM::Cell::Interior) + { + if (mStore.cells.searchInt (record.name)) + throw std::runtime_error ("failed creating interior cell"); + + ESM::Cell *cell = new ESM::Cell (record); + mStore.cells.intCells.insert (std::make_pair (record.name, cell)); + return cell; + } + else + { + if (mStore.cells.searchExt (record.data.gridX, record.data.gridY)) + throw std::runtime_error ("failed creating exterior cell"); + + ESM::Cell *cell = new ESM::Cell (record); + mStore.cells.extCells.insert ( + std::make_pair (std::make_pair (record.data.gridX, record.data.gridY), cell)); + return cell; + } + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 90d6121634..978f14c8ea 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -17,6 +17,7 @@ #include "scene.hpp" #include "physicssystem.hpp" #include "cells.hpp" +#include "localscripts.hpp" #include @@ -55,9 +56,7 @@ namespace MWWorld class World { - public: - typedef std::list > ScriptList; enum RenderMode { @@ -71,7 +70,7 @@ namespace MWWorld MWWorld::Player *mPlayer; ESM::ESMReader mEsm; ESMS::ESMStore mStore; - ScriptList mLocalScripts; + LocalScripts mLocalScripts; MWWorld::Globals *mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; @@ -108,10 +107,6 @@ namespace MWWorld Ptr::CellStore *getInterior (const std::string& name); - void removeScripts (Ptr::CellStore *cell); - - void insertInteriorScripts (ESMS::CellStore& cell); - void adjustSky(); MWWorld::Player& getPlayer(); @@ -120,8 +115,7 @@ namespace MWWorld ESM::ESMReader& getEsmReader(); - const ScriptList& getLocalScripts() const; - ///< Names and local variable state of all local scripts in active cells. + LocalScripts& getLocalScripts(); bool hasCellChanged() const; ///< Has the player moved to a different cell, since the last frame? @@ -207,6 +201,10 @@ namespace MWWorld std::pair createRecord (const ESM::Class& record); ///< Create a new recrod (of type class) in the ESM store. /// \return ID, pointer to created record + + const ESM::Cell *createRecord (const ESM::Cell& record); + ///< Create a new recrod (of type cell) in the ESM store. + /// \return ID, pointer to created record }; } diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake new file mode 100644 index 0000000000..c409366912 --- /dev/null +++ b/cmake/OpenMWMacros.cmake @@ -0,0 +1,24 @@ + +macro (add_openmw_dir dir) +set (files) +foreach (u ${ARGN}) +file (GLOB ALL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.*") +foreach (f ${ALL}) +list (APPEND files "${f}") +list (APPEND OPENMW_FILES "${f}") +endforeach (f) +endforeach (u) +source_group ("apps\\openmw\\${dir}" FILES ${files}) +endmacro (add_openmw_dir) + +macro (add_component_dir dir) +set (files) +foreach (u ${ARGN}) +file (GLOB ALL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.*") +foreach (f ${ALL}) +list (APPEND files "${f}") +list (APPEND COMPONENT_FILES "${f}") +endforeach (f) +endforeach (u) +source_group ("components\\${dir}" FILES ${files}) +endmacro (add_component_dir) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt new file mode 100644 index 0000000000..76e68dd89e --- /dev/null +++ b/components/CMakeLists.txt @@ -0,0 +1,66 @@ +project (Components) + +# source files + +add_component_dir (bsa + bsa_archive bsa_file + ) + +add_component_dir (cfg + configurationmanager + ) + +add_component_dir (nif + controlled effect nif_types record controller extra node record_ptr data nif_file property + ) + +add_component_dir (nifogre + ogre_nif_loader + ) + +add_component_dir (nifbullet + bullet_nif_loader + ) + +add_component_dir (to_utf8 + to_utf8 + ) + +add_component_dir (file_finder + file_finder filename_less search + ) + +add_component_dir (esm_store + cell_store reclists store + ) + +add_component_dir (esm + attr defs esm_reader loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell + loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst + loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc + loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat + loadweap records + ) + +add_component_dir (misc + slice_array stringops + ) + +add_component_dir (files + linuxpath windowspath macospath path multidircollection collections fileops + ) + +add_component_dir (compiler + context controlparser errorhandler exception exprparser extensions fileparser generator + lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler + stringparser tokenloc + ) + +add_component_dir (interpreter + context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes + miscopcodes opcodes runtime scriptopcodes spatialopcodes types + ) + +include_directories(${BULLET_INCLUDE_DIRS}) + +add_library (components STATIC ${COMPONENT_FILES}) diff --git a/components/esm_store/cell_store.hpp b/components/esm_store/cell_store.hpp index 1336cc2ab3..12f6444178 100644 --- a/components/esm_store/cell_store.hpp +++ b/components/esm_store/cell_store.hpp @@ -26,9 +26,20 @@ namespace ESMS using namespace ESM; /// A reference to one object (of any type) in a cell. + /// + /// Constructing this with a CellRef instance in the constructor means that + /// in practice (where D is RefData) the possibly mutable data is copied + /// across to mData. If later adding data (such as position) to CellRef + /// this would have to be manually copied across. template struct LiveCellRef { + LiveCellRef(const CellRef& cref, const X* b = NULL) : base(b), ref(cref), + mData(ref) {} + + + LiveCellRef(const X* b = NULL) : base(b), mData(ref) {} + // The object that this instance is based on. const X* base; @@ -59,11 +70,7 @@ namespace ESMS if(obj == NULL) throw std::runtime_error("Error resolving cell reference " + ref.refID); - LiveRef lr; - lr.ref = ref; - lr.base = obj; - - list.push_back(lr); + list.push_back(LiveRef(ref, obj)); } LiveRef *find (const std::string& name) @@ -189,6 +196,9 @@ namespace ESMS { assert (cell); + if (cell->context.filename.empty()) + return; // this is a dynamically generated cell -> skipping. + // Reopen the ESM reader and seek to the right position. cell->restore (esm); @@ -212,6 +222,9 @@ namespace ESMS { assert (cell); + if (cell->context.filename.empty()) + return; // this is a dynamically generated cell -> skipping. + // Reopen the ESM reader and seek to the right position. cell->restore(esm); diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 7d3afbb96b..20a2e8ff95 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -305,15 +305,24 @@ namespace ESMS delete it->second; } + const ESM::Cell* searchInt(const std::string &id) const + { + IntCells::const_iterator iter = intCells.find(id); + + if (iter!=intCells.end()) + return iter->second; + + return 0; + } const ESM::Cell* findInt(const std::string &id) const { - IntCells::const_iterator it = intCells.find(id); + const ESM::Cell *cell = searchInt (id); - if(it == intCells.end()) + if (!cell) throw std::runtime_error ("Interior cell not found - " + id); - return it->second; + return cell; } const ESM::Cell *searchExt (int x, int y) const diff --git a/libs/openengine b/libs/openengine index 0b1d6d4330..2f5eca9d87 160000 --- a/libs/openengine +++ b/libs/openengine @@ -1 +1 @@ -Subproject commit 0b1d6d4330818ee3e491e1ec78928ff714e9bbaa +Subproject commit 2f5eca9d878526bdd9dce93ece7f42093b481545 diff --git a/readme.txt b/readme.txt index ccf08c1ee9..cfddd9a1fa 100644 --- a/readme.txt +++ b/readme.txt @@ -3,21 +3,22 @@ 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.11 +Version: 0.11.1 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org THIS IS A WORK IN PROGRESS + INSTALLATION Windows: -TODO add description for Windows +Just unpack to a location of your choice. Currently there is no installer. Linux: -Ubuntu -TODO add description for Ubuntu +Ubuntu (and most others) +Download the .deb file and install it in the usual way. Arch Linux There's an OpenMW package available in the AUR Repository: @@ -26,21 +27,36 @@ http://aur.archlinux.org/packages.php?ID=21419 OS X: TODO add description for OS X + BUILD FROM SOURCE TODO add description here + +THE DATA PATH + +After the installation OpenMW needs to be told where to find the Morrowind data directory. Create a text file named openmw.cfg (location depends on platform) and enter the following line: + +data=path to your data directory + +(where you replace "path to your data directory" with the actual location of your data directory) + +On Windows a suitable location for the cfg file is alongside the binary. Currently the binary release comes with such a file pre-generated, but you still need to adjust the data setting. + +On Linux and Mac the default location will be ~/.config/openmw/openmw.cfg. + + COMMAND LINE OPTIONS TODO add description of command line options + CREDITS Developers: TODO add list of developers OpenMW: -Thanks to DokterDume for kindly providing us with the Moon and Star logo -used as the application icon and project logo. +Thanks to DokterDume for kindly providing us with the Moon and Star logo used as the application icon and project logo. Launcher: Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Files tab. @@ -48,4 +64,30 @@ Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Fil CHANGELOG -TODO add changelog (take pre 0.11.0 changelog from wiki when it is up again; take 0.11.0 and later changelog from tracker) +0.11.1 + +Bug #2: Resources loading doesn't work outside of bsa files +Bug #3: GUI does not render non-English characters +Bug #7: openmw.cfg location doesn't match +Bug #124: The TCL alias for ToggleCollision is missing. +Bug #125: Some command line options can't be used from a .cfg file +Bug #126: Toggle-type script instructions are less verbose compared with original MW +Bug #130: NPC-Record Loading fails for some NPCs +Bug #167: Launcher sets invalid parameters in ogre config +Feature #10: Journal +Feature #12: Rendering Optimisations +Feature #23: Change Launcher GUI to a tabbed interface +Feature #24: Integrate the OGRE settings window into the launcher +Feature #25: Determine openmw.cfg location (Launcher) +Feature #26: Launcher Profiles +Feature #79: MessageBox +Feature #116: Tab-Completion in Console +Feature #132: --data-local and multiple --data +Feature #143: Non-Rendering Performance-Optimisations +Feature #150: Accessing objects in cells via ID does only work for objects with all lower case IDs +Feature #157: Version Handling +Task #14: Replace tabs with 4 spaces +Task #18: Move components from global namespace into their own namespace +Task #123: refactor header files in components/esm + +TODO add old changelog (take pre 0.11.0 changelog from wiki)