diff --git a/.gitignore b/.gitignore index 776e2b6591..27d3a13de3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ data CMakeLists.txt.user *.swp *.swo +*.kate-swp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bdd8b21cf..e1b8e32e5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 21) +set (OPENMW_VERSION_MINOR 22) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -257,10 +257,10 @@ set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) # Set up Ogre plugin folder & debug suffix if (APPLE) - # Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt) - add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="") + # Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt) + add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="") else () - add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") + add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") endif() add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") @@ -278,9 +278,9 @@ add_subdirectory(files/mygui) # Specify build paths if (APPLE) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") else (APPLE) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") endif (APPLE) # Other files @@ -334,7 +334,7 @@ if(DPKG_PROGRAM) #Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/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(FILES "${OpenMW_SOURCE_DIR}/files/launcher/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}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") @@ -355,7 +355,7 @@ 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 bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "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") @@ -384,6 +384,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -409,8 +410,8 @@ if(WIN32) SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") - SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico") - SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico") + SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico") + SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico") SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe") @@ -510,10 +511,10 @@ if (WIN32) 4986 # Undocumented warning that occurs in the crtdbg.h file 4996 # Function was declared deprecated - # cause by ogre extensivly - 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' - 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' - 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + # cause by ogre extensivly + 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' + 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' + 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type @@ -525,7 +526,7 @@ if (WIN32) 4309 # Variable overflow, trying to store 128 in a signed char for example 4355 # Using 'this' in member initialization list 4701 # Potentially uninitialized local variable used - 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt + 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt ) foreach(d ${WARNINGS_DISABLE}) @@ -536,12 +537,12 @@ if (WIN32) set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) if (BUILD_LAUNCHER) - set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_LAUNCHER) + set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) - if (BUILD_BSATOOL) + if (BUILD_BSATOOL) set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_BSATOOL) + endif (BUILD_BSATOOL) if (BUILD_ESMTOOL) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_ESMTOOL) @@ -666,9 +667,9 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) - IF(BUILD_BSATOOL) + IF(BUILD_BSATOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) - ENDIF(BUILD_BSATOOL) + ENDIF(BUILD_BSATOOL) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) @@ -680,7 +681,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) ENDIF(BUILD_OPENCS) # Install icon and .desktop - INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications") # Install global configuration files diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 20c01af259..521383f3ff 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -227,7 +227,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; - std::cout << " INTV: " << ref.mIntv << " NAM9: " << ref.mIntv << std::endl; + std::cout << " Uses/health: " << ref.mCharge << " NAM9: " << ref.mNam9 << std::endl; } } diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 38fddd6b92..de3a175106 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -275,7 +275,7 @@ RecordBase::create(ESM::NAME type) } case ESM::REC_LOCK: { - record = new EsmTool::Record; + record = new EsmTool::Record; break; } case ESM::REC_LTEX: @@ -864,14 +864,13 @@ void Record::print() } template<> -void Record::print() +void Record::print() { std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -886,8 +885,6 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - // BUG? No Type Label? - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -902,7 +899,6 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c3daa9d0c3..e0dd988a65 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -104,7 +104,7 @@ namespace EsmTool template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); - template<> void Record::print(); + template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index a63898c0ec..eb93d71e78 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,7 +12,7 @@ set(LAUNCHER utils/checkablemessagebox.cpp utils/textinputdialog.cpp - launcher.rc + ${CMAKE_SOURCE_DIR}/files/launcher/launcher.rc ) set(LAUNCHER_HEADER @@ -43,10 +43,10 @@ set(LAUNCHER_HEADER_MOC ) set(LAUNCHER_UI - ../../files/ui/datafilespage.ui - ../../files/ui/graphicspage.ui - ../../files/ui/mainwindow.ui - ../../files/ui/playpage.ui + ${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui + ${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui + ${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui + ${CMAKE_SOURCE_DIR}/files/ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 444d05b2a0..add3dea40e 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -1,6 +1,9 @@ #include "datafilespage.hpp" -#include +#include +#include +#include +#include #include @@ -97,7 +100,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); - + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); @@ -144,7 +147,7 @@ void DataFilesPage::setupDataFiles() profilesComboBox->addItems(profiles); // Add the current profile if empty - if (profilesComboBox->findText(profile) == -1) + if (profilesComboBox->findText(profile) == -1 && !profile.isEmpty()) profilesComboBox->addItem(profile); if (profilesComboBox->findText(QString("Default")) == -1) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 3caae2c36d..700ba3db9c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,6 +1,8 @@ #include "graphicspage.hpp" -#include +#include +#include +#include #include @@ -257,7 +259,7 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) for (opt_it = i->second.possibleValues.begin (); opt_it != i->second.possibleValues.end (); opt_it++, idx++) { - QRegExp resolutionRe(QString("(\\d+) x (\\d+)")); + QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); QString resolution = QString::fromStdString(*opt_it).simplified(); if (resolutionRe.exactMatch(resolution)) { @@ -266,16 +268,17 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) int height = resolutionRe.cap(2).toInt(); QString aspect = getAspect(width, height); + QString cleanRes = resolutionRe.cap(1) + QString(" x ") + resolutionRe.cap(2); if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { - resolution.append(tr("\t(Wide ") + aspect + ")"); + cleanRes.append(tr("\t(Wide ") + aspect + ")"); } else if (aspect == QLatin1String("4:3")) { - resolution.append(tr("\t(Standard 4:3)")); + cleanRes.append(tr("\t(Standard 4:3)")); } // do not add duplicate resolutions - if (!result.contains(resolution)) - result.append(resolution); + if (!result.contains(cleanRes)) + result.append(cleanRes); } } } diff --git a/apps/launcher/launcher.rc b/apps/launcher/launcher.rc deleted file mode 100644 index efe86e4da4..0000000000 --- a/apps/launcher/launcher.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "resources/images/openmw.ico" diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 5d11421d0f..e5da3431ab 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,6 +1,15 @@ #include "maindialog.hpp" -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include "utils/checkablemessagebox.hpp" @@ -113,6 +122,51 @@ void MainDialog::createPages() bool MainDialog::showFirstRunDialog() { + QStringList iniPaths; + + foreach (const QString &path, mGameSettings.getDataDirs()) { + QDir dir(path); + dir.setPath(dir.canonicalPath()); // Resolve symlinks + + if (!dir.cdUp()) + continue; // Cannot move from Data Files + + if (dir.exists(QString("Morrowind.ini"))) + iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); + } + + // Ask the user where the Morrowind.ini is + if (iniPaths.empty()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error detecting Morrowind configuration")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(QObject::tr("
Could not find Morrowind.ini

\ + OpenMW needs to import settings from this file.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + QString iniFile; + if (msgBox.clickedButton() == dirSelectButton) { + iniFile = QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select configuration file"), + QDir::currentPath(), + QString(tr("Morrowind configuration file (*.ini)"))); + } + + if (iniFile.isEmpty()) + return false; // Cancel was clicked; + + QFileInfo info(iniFile); + iniPaths.clear(); + iniPaths.append(info.absoluteFilePath()); + } + CheckableMessageBox msgBox(this); msgBox.setWindowTitle(tr("Morrowind installation detected")); @@ -120,7 +174,6 @@ bool MainDialog::showFirstRunDialog() int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize); msgBox.setIconPixmap(icon.pixmap(size, size)); - QAbstractButton *importerButton = msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?! QAbstractButton *skipButton = @@ -129,54 +182,28 @@ bool MainDialog::showFirstRunDialog() Q_UNUSED(skipButton); // Surpress compiler unused warning msgBox.setStandardButtons(QDialogButtonBox::NoButton); - - msgBox.setText(tr("
An existing Morrowind installation was detected

\ - Would you like to import settings from Morrowind.ini?
")); - + msgBox.setText(tr("
An existing Morrowind configuration was detected
\ +
Would you like to import settings from Morrowind.ini?
\ +
Warning: In most cases OpenMW needs these settings to run properly
")); msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)")); msgBox.exec(); if (msgBox.clickedButton() == importerButton) { - QStringList iniPaths; - - foreach (const QString &path, mGameSettings.getDataDirs()) { - QDir dir(path); - dir.setPath(dir.canonicalPath()); // Resolve symlinks - - if (!dir.cdUp()) - continue; // Cannot move from Data Files - - if (dir.exists(QString("Morrowind.ini"))) - iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); - } - - if (iniPaths.isEmpty()) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error reading Morrowind configuration file")); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not find Morrowind.ini

\ - The problem may be due to an incomplete installation of Morrowind.
\ - Reinstalling Morrowind may resolve the problem.")); - msgBox.exec(); - return false; - } - if (iniPaths.count() > 1) { // Multiple Morrowind.ini files found bool ok; - QString path = QInputDialog::getItem(this, tr("Multiple configurations found"), + QString path = QInputDialog::getItem(this, tr("Multiple configurations found"), tr("
There are multiple Morrowind.ini files found.

\ Please select the one you wish to import from:"), iniPaths, 0, false, &ok); - if (ok && !path.isEmpty()) { - iniPaths.clear(); - iniPaths.append(path); - } else { - // Cancel was clicked TODO: should we abort here? - return false; - } + if (ok && !path.isEmpty()) { + iniPaths.clear(); + iniPaths.append(path); + } else { + // Cancel was clicked + return false; + } } // Create the file if it doesn't already exist, else the importer will fail @@ -204,9 +231,13 @@ bool MainDialog::showFirstRunDialog() QStringList arguments; if (msgBox.isChecked()) - arguments.append(QString("-g")); + arguments.append(QString("--game-files")); + arguments.append(QString("--encoding")); + arguments.append(mGameSettings.value(QString("encoding"), QString("win1252"))); + arguments.append(QString("--ini")); arguments.append(iniPaths.first()); + arguments.append(QString("--cfg")); arguments.append(path); if (!startProgram(QString("mwiniimport"), arguments, false)) @@ -218,7 +249,7 @@ bool MainDialog::showFirstRunDialog() // Add a new profile if (msgBox.isChecked()) { - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported")); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), QString("Imported")); mLauncherSettings.remove(QString("Profiles/Imported/master")); mLauncherSettings.remove(QString("Profiles/Imported/plugin")); @@ -659,7 +690,7 @@ bool MainDialog::startProgram(const QString &name, const QStringList &arguments, return false; } - if (process.exitCode() != 0) { + if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit) { QString error(process.readAllStandardError()); error.append(tr("\nArguments:\n")); error.append(arguments.join(" ")); diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index d6d25d71d0..46900c5958 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -1,6 +1,10 @@ #include "playpage.hpp" -#include +#include + +#ifdef Q_OS_MAC +#include +#endif PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index deab88ce28..702f665138 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -22,3 +22,8 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(mwiniimport gcov) endif() + +if(DPKG_PROGRAM) + INSTALL(TARGETS mwiniimport RUNTIME DESTINATION games COMPONENT mwiniimport) +endif() + diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 488e3c65f5..a305d90d93 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid + stage verifier mandatoryid skillcheck ) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7a88335c89..d1462d6a3f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,7 @@ #include "document.hpp" #include -#include + void CSMDoc::Document::load (const std::vector::const_iterator& begin, const std::vector::const_iterator& end, bool lastAsModified) { @@ -150,6 +150,10 @@ void CSMDoc::Document::addOptionalGlobals() ESM::Global global; global.mId = sGlobals[i]; global.mValue.setType (ESM::VT_Long); + + if (i==0) + global.mValue.setInteger (1); // dayspassed starts counting at 1 + addOptionalGlobal (global); } } @@ -189,15 +193,25 @@ void CSMDoc::Document::createBase() record.mId = sGlobals[i]; - record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int); + record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Long); - if (i==0) + if (i==0 || i==1) record.mValue.setInteger (1); getData().getGlobals().add (record); } /// \todo add GMSTs + + for (int i=0; i<27; ++i) + { + ESM::Skill record; + record.mIndex = i; + record.mId = ESM::Skill::getIndexToId (record.mIndex); + record.blank(); + + getData().getSkills().add (record); + } } CSMDoc::Document::Document (const std::vector& files, bool new_) @@ -214,7 +228,7 @@ CSMDoc::Document::Document (const std::vector& files, b if (new_ && files.size()==1) createBase(); - else if (files.size()>1) + else { std::vector::const_iterator end = files.end(); diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp new file mode 100644 index 0000000000..897aeab473 --- /dev/null +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -0,0 +1,37 @@ + +#include "skillcheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SkillCheckStage::SkillCheckStage (const CSMWorld::IdCollection& skills) +: mSkills (skills) +{} + +int CSMTools::SkillCheckStage::setup() +{ + return mSkills.getSize(); +} + +void CSMTools::SkillCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Skill& skill = mSkills.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Skill, skill.mId); + + for (int i=0; i<4; ++i) + if (skill.mData.mUseValue[i]<0) + { + std::ostringstream stream; + + stream << id.toString() << "|Use value #" << i << " of " << skill.mId << " is negative"; + + messages.push_back (stream.str()); + } + + if (skill.mDescription.empty()) + messages.push_back (id.toString() + "|" + skill.mId + " has an empty description"); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/skillcheck.hpp b/apps/opencs/model/tools/skillcheck.hpp new file mode 100644 index 0000000000..30a3f01cad --- /dev/null +++ b/apps/opencs/model/tools/skillcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SKILLCHECK_H +#define CSM_TOOLS_SKILLCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that skill records are internally consistent + class SkillCheckStage : public Stage + { + const CSMWorld::IdCollection& mSkills; + + public: + + SkillCheckStage (const CSMWorld::IdCollection& skills); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 8dd1c0fe6f..33cc3cc61b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -12,6 +12,7 @@ #include "reportmodel.hpp" #include "mandatoryid.hpp" +#include "skillcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -51,6 +52,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); + + mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); } return mVerifier; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c44abda2b2..b5863f8e4e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -31,7 +31,9 @@ namespace CSMWorld Display_Float, Display_Var, Display_GmstVarType, - Display_GlobalVarType + Display_GlobalVarType, + Display_Specialisation, + Display_Attribute }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 018825831b..7764f58709 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H +#include + #include "columnbase.hpp" namespace CSMWorld @@ -35,7 +37,7 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mId.c_str(); + return QString::fromUtf8 (record.get().mId.c_str()); } virtual bool isEditable() const @@ -127,17 +129,17 @@ namespace CSMWorld { case ESM::VT_String: - return record.get().mValue.getString().c_str(); break; + return QString::fromUtf8 (record.get().mValue.getString().c_str()); case ESM::VT_Int: case ESM::VT_Short: case ESM::VT_Long: - return record.get().mValue.getInteger(); break; + return record.get().mValue.getInteger(); case ESM::VT_Float: - return record.get().mValue.getFloat(); break; + return record.get().mValue.getFloat(); default: return QVariant(); } @@ -177,6 +179,112 @@ namespace CSMWorld return true; } }; + + template + struct DescriptionColumn : public Column + { + DescriptionColumn() : Column ("Description", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mDescription.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mDescription = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct SpecialisationColumn : public Column + { + SpecialisationColumn() : Column ("Specialisation", ColumnBase::Display_Specialisation) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mSpecialization; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mSpecialization = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct UseValueColumn : public Column + { + int mIndex; + + UseValueColumn (int index) + : Column ("Use value #" + boost::lexical_cast (index), + ColumnBase::Display_Float), mIndex (index) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mUseValue[mIndex]; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mUseValue[mIndex] = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct AttributeColumn : public Column + { + AttributeColumn() : Column ("Attribute", ColumnBase::Display_Attribute) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mAttribute; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mAttribute = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index e22ecf9921..1f8660bdde 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,7 +1,7 @@ #include "commands.hpp" -#include +#include #include "idtableproxymodel.hpp" #include "idtable.hpp" diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index bbd8667b34..4b10a66836 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -12,7 +12,7 @@ #include "idtable.hpp" #include "columns.hpp" -void CSMWorld::Data::addModel (QAbstractTableModel *model, UniversalId::Type type1, +void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2) { mModels.push_back (model); @@ -36,13 +36,22 @@ CSMWorld::Data::Data() mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); + mSkills.addColumn (new StringIdColumn); + mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new AttributeColumn); + mSkills.addColumn (new SpecialisationColumn); + for (int i=0; i<4; ++i) + mSkills.addColumn (new UseValueColumn (i)); + mSkills.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); + addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); } CSMWorld::Data::~Data() { - for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) + for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) delete *iter; } @@ -66,9 +75,19 @@ CSMWorld::IdCollection& CSMWorld::Data::getGmsts() return mGmsts; } -QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) +const CSMWorld::IdCollection& CSMWorld::Data::getSkills() const { - std::map::iterator iter = mModelIndex.find (id.getType()); + return mSkills; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSkills() +{ + return mSkills; +} + +QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) +{ + std::map::iterator iter = mModelIndex.find (id.getType()); if (iter==mModelIndex.end()) throw std::logic_error ("No table model available for " + id.toString()); @@ -102,7 +121,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { case ESM::REC_GLOB: mGlobals.load (reader, base); break; case ESM::REC_GMST: mGmsts.load (reader, base); break; - + case ESM::REC_SKIL: mSkills.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 3745346511..ac953dbece 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -8,11 +8,12 @@ #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" -class QAbstractTableModel; +class QAbstractItemModel; namespace CSMWorld { @@ -20,14 +21,15 @@ namespace CSMWorld { IdCollection mGlobals; IdCollection mGmsts; - std::vector mModels; - std::map mModelIndex; + IdCollection mSkills; + std::vector mModels; + std::map mModelIndex; // not implemented Data (const Data&); Data& operator= (const Data&); - void addModel (QAbstractTableModel *model, UniversalId::Type type1, + void addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2 = UniversalId::Type_None); public: @@ -44,7 +46,11 @@ namespace CSMWorld IdCollection& getGmsts(); - QAbstractTableModel *getTableModel (const UniversalId& id); + const IdCollection& getSkills() const; + + IdCollection& getSkills(); + + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// /// \note The returned table may either be the model for the ID itself or the model that diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 9b69dfb889..3bf53349e6 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -74,6 +74,8 @@ namespace CSMWorld virtual const RecordBase& getRecord (const std::string& id) const = 0; + virtual const RecordBase& getRecord (int index) const = 0; + virtual void load (ESM::ESMReader& reader, bool base) = 0; }; @@ -139,7 +141,9 @@ namespace CSMWorld /// /// \attention Throw san exception, if the type of \a record does not match. - virtual const RecordBase& getRecord (const std::string& id) const; + virtual const Record& getRecord (const std::string& id) const; + + virtual const Record& getRecord (int index) const; virtual void load (ESM::ESMReader& reader, bool base); @@ -373,11 +377,18 @@ namespace CSMWorld } template - const RecordBase& IdCollection::getRecord (const std::string& id) const + const Record& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } + + template + const Record& IdCollection::getRecord (int index) const + { + return mRecords.at (index); + } + } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index afed6b6eda..79e33584b2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -96,6 +96,25 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren return true; } +QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const +{ + if (parent.isValid()) + return QModelIndex(); + + if (row<0 || row>=mIdCollection->getSize()) + return QModelIndex(); + + if (column<0 || column>=mIdCollection->getColumns()) + return QModelIndex(); + + return createIndex (row, column); +} + +QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const +{ + return QModelIndex(); +} + void CSMWorld::IdTable::addRecord (const std::string& id) { int index = mIdCollection->getSize(); diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index deaebaa38a..80476c5243 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -1,14 +1,14 @@ #ifndef CSM_WOLRD_IDTABLE_H #define CSM_WOLRD_IDTABLE_H -#include +#include namespace CSMWorld { class IdCollectionBase; class RecordBase; - class IdTable : public QAbstractTableModel + class IdTable : public QAbstractItemModel { Q_OBJECT @@ -39,6 +39,11 @@ namespace CSMWorld virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) + const; + + virtual QModelIndex parent (const QModelIndex& index) const; + void addRecord (const std::string& id); QModelIndex getModelIndex (const std::string& id, int column) const; diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 53bb7ea2ce..c8f728e7d1 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -62,7 +62,7 @@ namespace CSMWorld if (mState==State_Erased) throw std::logic_error ("attempt to access a deleted record"); - return mState==State_BaseOnly ? mBase : mModified; + return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified; } template @@ -81,9 +81,7 @@ namespace CSMWorld throw std::logic_error ("attempt to modify a deleted record"); mModified = modified; - - if (mState!=State_ModifiedOnly) - mState = mBase==mModified ? State_BaseOnly : State_Modified; + mState = State_Modified; } template diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index c006852bc6..57c276a6d3 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -19,6 +19,7 @@ namespace { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -27,6 +28,7 @@ namespace { { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -43,7 +45,7 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string::size_type index = universalId.find (':'); - if (index==std::string::npos) + if (index!=std::string::npos) { std::string type = universalId.substr (0, index); diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 9ff7d17b18..a412cb6b1e 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -37,8 +37,9 @@ namespace CSMWorld Type_Global, Type_VerificationResults, Type_Gmsts, - Type_Gmst - + Type_Gmst, + Type_Skills, + Type_Skill }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 995d3ca2e2..267ddf26cc 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -86,6 +86,10 @@ void CSVDoc::View::setupWorldMenu() connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); world->addAction (gmsts); + QAction *skills = new QAction (tr ("Skills"), this); + connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); + world->addAction (skills); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -244,6 +248,11 @@ void CSVDoc::View::addGmstsSubView() addSubView (CSMWorld::UniversalId::Type_Gmsts); } +void CSVDoc::View::addSkillsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Skills); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e91a4d4a80..4c5aa40784 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -116,6 +116,7 @@ namespace CSVDoc void addGmstsSubView(); + void addSkillsSubView(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 33300f67a7..bc87728945 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -38,6 +38,17 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) { + static const char *sSpecialisations[] = + { + "Combat", "Magic", "Stealth", 0 + }; + + static const char *sAttributes[] = + { + "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", + "Luck", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -45,6 +56,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation, + new CSVWorld::EnumDelegateFactory (sSpecialisations)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, + new CSVWorld::EnumDelegateFactory (sAttributes)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e16de99eff..cedb20de92 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -24,7 +24,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM widget->setLayout (layout); - QAbstractTableModel *model = document.getData().getTableModel (id); + QAbstractItemModel *model = document.getData().getTableModel (id); int columns = model->columnCount(); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7a8b45373d..0dd0a1d594 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -1,6 +1,7 @@ #include "enumdelegate.hpp" +#include #include #include @@ -89,6 +90,16 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte } +CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} + +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names) +{ + assert (names); + + for (int i=0; names[i]; ++i) + add (i, names[i]); +} + CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, QObject *parent) const { diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index f11252371e..752ed5be72 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -45,6 +45,11 @@ namespace CSVWorld public: + EnumDelegateFactory(); + + EnumDelegateFactory (const char **names); + ///< \param names Array of char pointer with a 0-pointer as end mark + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 351007ded5..bdff0017b4 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -14,6 +14,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Gmsts, new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Skills, + new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Global, new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8df2136e5e..41599b35db 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,6 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons + merchantrepair repair ) add_openmw_dir (mwdialogue @@ -53,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp + esmstore store recordcmp fallback actionrepair ) add_openmw_dir (mwclass @@ -64,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate repair ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index a205e78db7..db86385d4e 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -41,6 +41,8 @@ namespace MWBase virtual void goodbyeSelected() = 0; virtual void questionAnswered (const std::string& answer) = 0; + virtual bool checkServiceRefused () = 0; + virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; virtual void applyTemporaryDispositionChange (int delta) = 0; diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index b8733259ff..020647744b 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -82,7 +82,7 @@ namespace MWBase virtual int getDerivedDisposition(const MWWorld::Ptr& ptr) = 0; ///< Calculate the diposition of an NPC toward the player. - + virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 93cc8e44a2..6760c89d07 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -91,6 +91,8 @@ namespace MWBase virtual bool isGuiMode() const = 0; + virtual bool isConsoleMode() const = 0; + virtual void toggleVisible (MWGui::GuiWindow wnd) = 0; /// Disallow all inventory mode windows @@ -236,6 +238,8 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; + virtual void startRepair(MWWorld::Ptr actor) = 0; + virtual void startRepairItem(MWWorld::Ptr item) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6cd5b90b40..f3b817e516 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -46,6 +46,7 @@ namespace MWRender namespace MWWorld { + class Fallback; class CellStore; class Player; class LocalScripts; @@ -103,11 +104,7 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual void setFallbackValues (const std::map& fallbackMap) = 0; - - virtual std::string getFallback (const std::string& key) const = 0; - - virtual std::string getFallback (const std::string& key, const std::string& def) const = 0; + virtual const MWWorld::Fallback *getFallback () const = 0; virtual MWWorld::Player& getPlayer() = 0; @@ -142,7 +139,7 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. - + virtual std::vector getGlobals () const = 0; virtual std::string getCurrentCellName() const = 0; @@ -299,7 +296,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual void renderPlayer() = 0; - + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fdf211c28a..513ebf75fc 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -247,8 +247,9 @@ namespace MWClass text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); - /// \todo store the current armor health somewhere - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")"; text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 19f327dcbb..1097f8f29c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -191,6 +191,12 @@ namespace MWClass return info; } + float Creature::getArmorRating (const MWWorld::Ptr& ptr) const + { + /// \todo add Shield magic effect magnitude here, controlled by a GMST (Vanilla vs MCP behaviour) + return 0.f; + } + float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); @@ -203,9 +209,9 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).mMagnitude; if (weight<0) weight = 0; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index a96c18a8c5..ea356165eb 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -54,6 +54,9 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual bool isEssential (const MWWorld::Ptr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 665644736d..2015726968 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -1,7 +1,7 @@ #include "lockpick.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -41,8 +41,8 @@ namespace MWClass std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); assert(ref->mBase != NULL); const std::string &model = ref->mBase->mModel; @@ -54,8 +54,8 @@ namespace MWClass std::string Lockpick::getName (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mName; } @@ -75,8 +75,8 @@ namespace MWClass std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mScript; } @@ -92,8 +92,8 @@ namespace MWClass int Lockpick::getValue (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mData.mValue; } @@ -102,7 +102,7 @@ namespace MWClass { boost::shared_ptr instance (new Lockpick); - registerClass (typeid (ESM::Tool).name(), instance); + registerClass (typeid (ESM::Lockpick).name(), instance); } std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr) const @@ -117,24 +117,24 @@ namespace MWClass std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mIcon; } bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -142,9 +142,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); @@ -171,8 +171,8 @@ namespace MWClass MWWorld::Ptr Lockpick::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d4e5e5cd67..a5319ada07 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -471,9 +471,9 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).mMagnitude; if (weight<0) weight = 0; @@ -505,12 +505,75 @@ namespace MWClass stats.useSkill (skill, *class_, usageType); } + float Npc::getArmorRating (const MWWorld::Ptr& ptr) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + int ratings[MWWorld::InventoryStore::Slots]; + + int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); + float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); + float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); + + for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(i); + if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) + { + // unarmored + ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + } + else + { + MWWorld::LiveCellRef *ref = + it->get(); + + int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); + int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); + + if (ref->mBase->mData.mWeight == 0) + ratings[i] = ref->mBase->mData.mArmor; + else + ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + } + + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; + + return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] + + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] + + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] + ) * 0.1 + + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) + * 0.05 + + shield; + } + + void Npc::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const { y = 0; x = 0; } + void Npc::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + const ESM::Race* race = + MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); + + if (ref->mBase->isMale()) + scale *= race->mData.mHeight.mMale; + else + scale *= race->mData.mHeight.mFemale; + } + MWWorld::Ptr Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f41edb0df6..0f61fc8c91 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -81,7 +81,7 @@ namespace MWClass virtual bool getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce = false) const; - ////< Check if a stance is active or not. + ///< Check if a stance is active or not. virtual float getSpeed (const MWWorld::Ptr& ptr) const; ///< Return movement speed. @@ -104,12 +104,17 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const; ///< Apply \a id on \a ptr. /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? + virtual void adjustScale (const MWWorld::Ptr &ptr, float &scale) const; + virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5b1b55bd31..e4533af655 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -1,7 +1,7 @@ #include "probe.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -141,9 +141,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index d6afe93198..bafedee88b 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -1,7 +1,7 @@ #include "repair.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -12,6 +12,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/actionrepair.hpp" #include "../mwgui/tooltips.hpp" @@ -120,6 +121,19 @@ namespace MWClass return (ref->mBase->mName != ""); } + bool Repair::hasItemHealth (const MWWorld::Ptr& ptr) const + { + return true; + } + + int Repair::getItemMaxHealth (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mUses; + } + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -131,9 +145,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); @@ -156,4 +170,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mRepairs.insert(*ref), &cell); } + + boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const + { + return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index c58e38f96b..3083c97e35 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -49,6 +49,18 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu (default implementation: return a + /// null action). + + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + ///< \return Item health data available? (default implementation: false) + + virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + ///< Return item max health or throw an exception, if class does not have item health + /// (default implementation: throw an exceoption) }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 475c08ccbf..a6a8e631b3 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -75,7 +75,10 @@ namespace MWClass bool Weapon::hasItemHealth (const MWWorld::Ptr& ptr) const { - return true; + MWWorld::LiveCellRef *ref = + ptr.get(); + + return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } int Weapon::getItemMaxHealth (const MWWorld::Ptr& ptr) const @@ -334,9 +337,12 @@ namespace MWClass } } - /// \todo store the current weapon health somewhere if (ref->mBase->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + { + int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + } text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f0c94937..b75c514a29 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -241,7 +241,7 @@ namespace MWDialogue } } - void DialogueManager::executeTopic (const std::string& topic) + void DialogueManager::executeTopic (const std::string& topic, bool randomResponse) { Filter filter (mActor, mChoice, mTalkedTo); @@ -256,7 +256,7 @@ namespace MWDialogue if (!infos.empty()) { - const ESM::DialInfo* info = infos[std::rand() % infos.size()]; + const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0]; parseText (info->mResponse); @@ -367,6 +367,9 @@ namespace MWDialogue if (services & ESM::NPC::Enchanting) windowServices |= MWGui::DialogueWindow::Service_Enchant; + if (services & ESM::NPC::Repair) + windowServices |= MWGui::DialogueWindow::Service_Repair; + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->setServices (windowServices); @@ -505,7 +508,7 @@ namespace MWDialogue text = "Bribe"; } - executeTopic (text + (success ? " Success" : " Fail")); + executeTopic (text + (success ? " Success" : " Fail"), true); } int DialogueManager::getTemporaryDispositionChange() const @@ -518,6 +521,37 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } + bool DialogueManager::checkServiceRefused() + { + Filter filter (mActor, mChoice, mTalkedTo); + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + + std::vector infos = filter.list (dialogue, false, false, true); + if (!infos.empty()) + { + const ESM::DialInfo* info = infos[0]; + + parseText (info->mResponse); + + const MWWorld::Store& gmsts = + MWBase::Environment::get().getWorld()->getStore().get(); + + win->addTitle (gmsts.find ("sServiceRefusal")->getString()); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + + executeScript (info->mResultScript); + return true; + } + return false; + } + std::vector ParseHyperText(const std::string& text) { std::vector result; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 1ca2ae5ebc..337cf62478 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -48,7 +48,7 @@ namespace MWDialogue void printError (const std::string& error); - void executeTopic (const std::string& topic); + void executeTopic (const std::string& topic, bool randomResponse=false); public: @@ -65,6 +65,8 @@ namespace MWDialogue virtual MWWorld::Ptr getActor() const; ///< Return the actor the player is currently talking to. + virtual bool checkServiceRefused (); + //calbacks for the GUI virtual void keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 10740794ea..cd9908d3df 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -121,7 +121,7 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const return true; } -bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const +bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert) const { bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); @@ -129,14 +129,19 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const return true; int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); - - return actorDisposition >= info.mData.mDisposition; + // For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed". + return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition) + : (actorDisposition >= info.mData.mDisposition); } bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { - if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) - return select.isInverted(); + if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) + // If the actor is a creature, we do not test the conditions applicable + // only to NPCs. Such conditions can never be satisfied, apart + // inverted ones (NotClass, NotRace, NotFaction return true + // because creatures are not of any race, class or faction). + return select.getType() == SelectWrapper::Type_Inverted; switch (select.getType()) { @@ -144,6 +149,9 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const case SelectWrapper::Type_Integer: return select.selectCompare (getSelectStructInteger (select)); case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select); case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select)); + + // We must not do the comparison for inverted functions (eg. Function_NotClass) + case SelectWrapper::Type_Inverted: return getSelectStructBoolean (select); } return true; @@ -412,25 +420,49 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return false; - case SelectWrapper::Function_Id: + case SelectWrapper::Function_NotId: - return select.getName()==Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); + return select.getName()!=Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); - case SelectWrapper::Function_Faction: + case SelectWrapper::Function_NotFaction: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)!=select.getName(); - case SelectWrapper::Function_Class: + case SelectWrapper::Function_NotClass: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)!=select.getName(); - case SelectWrapper::Function_Race: + case SelectWrapper::Function_NotRace: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)!=select.getName(); - case SelectWrapper::Function_Cell: + case SelectWrapper::Function_NotCell: - return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)!=select.getName(); + + case SelectWrapper::Function_NotLocal: + { + std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor); + + if (scriptName.empty()) + // This actor has no attached script, so there is no local variable + return true; + + const ESM::Script *script = + MWBase::Environment::get().getWorld()->getStore().get().find (scriptName); + + std::string name = select.getName(); + + int i = 0; + for (; i < static_cast (script->mVarNames.size()); ++i) + if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) + break; + + if (i >= static_cast (script->mVarNames.size())) + return true; // script does not have a variable of this name + + return false; + } case SelectWrapper::Function_SameGender: @@ -458,7 +490,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_PcCorprus: return MWWorld::Class::get (player).getCreatureStats (player). - getMagicEffects().get (132).mMagnitude!=0; + getMagicEffects().get (ESM::MagicEffect::Corprus).mMagnitude!=0; case SelectWrapper::Function_PcExpelled: { @@ -570,7 +602,7 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, } std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, - bool fallbackToInfoRefusal, bool searchAll) const + bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition) const { std::vector infos; @@ -582,7 +614,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { - if (testDisposition (*iter)) { + if (testDisposition (*iter, invertDisposition)) { infos.push_back(&*iter); if (!searchAll) break; @@ -604,7 +636,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) - if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter, invertDisposition)) { infos.push_back(&*iter); if (!searchAll) break; diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 069bf6353d..5c6d092ad9 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -30,8 +30,8 @@ namespace MWDialogue bool testSelectStructs (const ESM::DialInfo& info) const; ///< Are all select structs matching? - bool testDisposition (const ESM::DialInfo& info) const; - ///< Is the actor disposition toward the player high enough? + bool testDisposition (const ESM::DialInfo& info, bool invert=false) const; + ///< Is the actor disposition toward the player high enough (or low enough, if \a invert is true)? bool testSelectStruct (const SelectWrapper& select) const; @@ -54,7 +54,7 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); std::vector list (const ESM::Dialogue& dialogue, - bool fallbackToInfoRefusal, bool searchAll) const; + bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition=false) const; const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 9d705f6bec..64bd1d2449 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -112,12 +112,12 @@ MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() con case '4': return Function_Journal; case '5': return Function_Item; case '6': return Function_Dead; - case '7': return Function_Id; - case '8': return Function_Faction; - case '9': return Function_Class; - case 'A': return Function_Race; - case 'B': return Function_Cell; - case 'C': return Function_Local; + case '7': return Function_NotId; + case '8': return Function_NotFaction; + case '9': return Function_NotClass; + case 'A': return Function_NotRace; + case 'B': return Function_NotCell; + case 'C': return Function_NotLocal; } return Function_None; @@ -219,7 +219,6 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function booleanFunctions[] = { Function_False, - Function_Id, Function_Faction, Function_Class, Function_Race, Function_Cell, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, Function_PcExpelled, @@ -231,6 +230,13 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_None // end marker }; + static const Function invertedBooleanFunctions[] = + { + Function_NotId, Function_NotFaction, Function_NotClass, + Function_NotRace, Function_NotCell, Function_NotLocal, + Function_None // end marker + }; + Function function = getFunction(); for (int i=0; integerFunctions[i]!=Function_None; ++i) @@ -245,21 +251,18 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const if (booleanFunctions[i]==function) return Type_Boolean; + for (int i=0; invertedBooleanFunctions[i]!=Function_None; ++i) + if (invertedBooleanFunctions[i]==function) + return Type_Inverted; + return Type_None; } -bool MWDialogue::SelectWrapper::isInverted() const -{ - char type = mSelect.mSelectRule[1]; - - return type=='7' || type=='8' || type=='9' || type=='A' || type=='B' || type=='C'; -} - bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = { - Function_Faction, SelectWrapper::Function_Class, SelectWrapper::Function_Race, + Function_NotFaction, Function_NotClass, Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcSkill, Function_PcExpelled, @@ -283,17 +286,17 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const bool MWDialogue::SelectWrapper::selectCompare (int value) const { - return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR + return selectCompareImp (mSelect, value); } bool MWDialogue::SelectWrapper::selectCompare (float value) const { - return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR + return selectCompareImp (mSelect, value); } bool MWDialogue::SelectWrapper::selectCompare (bool value) const { - return selectCompareImp (mSelect, static_cast (value))!=isInverted(); // logic XOR + return selectCompareImp (mSelect, static_cast (value)); } std::string MWDialogue::SelectWrapper::getName() const diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index b77ed7985a..f4bc898a4b 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -17,11 +17,12 @@ namespace MWDialogue Function_Journal, Function_Item, Function_Dead, - Function_Id, - Function_Faction, - Function_Class, - Function_Race, - Function_Cell, + Function_NotId, + Function_NotFaction, + Function_NotClass, + Function_NotRace, + Function_NotCell, + Function_NotLocal, Function_Local, Function_Global, Function_SameGender, Function_SameRace, Function_SameFaction, @@ -50,7 +51,8 @@ namespace MWDialogue Type_None, Type_Integer, Type_Numeric, - Type_Boolean + Type_Boolean, + Type_Inverted }; private: @@ -67,8 +69,6 @@ namespace MWDialogue Type getType() const; - bool isInverted() const; - bool isNpcOnly() const; ///< \attention Do not call any of the select functions for this select struct! diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index b98fd2bd9f..bcf3c335d3 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -12,6 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwworld/fallback.hpp" namespace { @@ -23,14 +24,13 @@ namespace }; const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer - Step sGenerateClassSteps(int number) { - MWBase::World *world = MWBase::Environment::get().getWorld(); number++; - Step step = {world->getFallback("Question_"+boost::lexical_cast(number)+"_Question"), - {world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerOne"), - world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), - world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), + {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), + fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), + fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav" }; return step; @@ -674,9 +674,6 @@ void CharacterCreation::showClassQuestionDialog() void CharacterCreation::onGenerateClassBack() { - if(mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - mWM->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2b80003127..9c1fbae69e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -45,7 +45,7 @@ namespace mapping.push_back( typeid(ESM::Book).name() ); mapping.push_back( typeid(ESM::Light).name() ); mapping.push_back( typeid(ESM::Miscellaneous).name() ); - mapping.push_back( typeid(ESM::Tool).name() ); + mapping.push_back( typeid(ESM::Lockpick).name() ); mapping.push_back( typeid(ESM::Repair).name() ); mapping.push_back( typeid(ESM::Probe).name() ); @@ -683,12 +683,18 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + std::vector equippedItems = getEquippedItems(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); int i=0; for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) { + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() + && !mDisplayEquippedItems) + continue; + playerStore.add(*iter); if (i==0) @@ -698,11 +704,11 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } + iter->getRefData().setCount(0); + ++i; } - containerStore.clear(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index cdcbfc4d18..bfbd60b07d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -175,6 +175,9 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) if (!mEnabled && color == "#572D21") MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + if (!mEnabled) + return; + if(color != "#B29154") { MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); @@ -227,54 +230,61 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) { if (!mEnabled) return; - int separatorPos = mTopicsList->getItemCount(); + int separatorPos = 0; for (unsigned int i=0; igetItemCount(); ++i) { if (mTopicsList->getItemNameAt(i) == "") separatorPos = i; } - if (id > separatorPos) + if (id >= separatorPos) MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); else { const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (topic == gmst.find("sBarter")->getString()) - { - /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? - mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mPtr); - } if (topic == gmst.find("sPersuasion")->getString()) { mPersuasionDialog.setVisible(true); } - else if (topic == gmst.find("sSpells")->getString()) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); + if (topic == gmst.find("sBarter")->getString()) + { + mWindowManager.pushGuiMode(GM_Barter); + mWindowManager.getTradeWindow()->startTrade(mPtr); + } + else if (topic == gmst.find("sSpells")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellBuying); + mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + mWindowManager.pushGuiMode(GM_Travel); + mWindowManager.getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellCreation); + mWindowManager.startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + mWindowManager.pushGuiMode(GM_Enchanting); + mWindowManager.startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_Training); + mWindowManager.startTraining (mPtr); + } + else if (topic == gmst.find("sRepair")->getString()) + { + mWindowManager.pushGuiMode(GM_MerchantRepair); + mWindowManager.startRepair (mPtr); + } } } } @@ -322,6 +332,9 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + if (mServices & Service_Repair) + mTopicsList->addItem(gmst.find("sRepair")->getString()); + if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addSeparator(); @@ -376,10 +389,17 @@ std::string DialogueWindow::parseText(const std::string& text) std::vector topics; + bool hasSeparator = false; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + hasSeparator = true; + } + for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached) + if (separatorReached || !hasSeparator) topics.push_back(keyWord); else if (keyWord == "") separatorReached = true; diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a8e0a6d174..187731fc77 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -81,7 +81,8 @@ namespace MWGui Service_CreateSpells = 0x04, Service_Enchant = 0x08, Service_Training = 0x10, - Service_Travel = 0x20 + Service_Travel = 0x20, + Service_Repair = 0x40 }; protected: diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ab7615c0ef..578ec3da3e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -13,6 +13,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -50,6 +51,7 @@ namespace MWGui getWidget(mFilterMisc, "MiscButton"); getWidget(mLeftPane, "LeftPane"); getWidget(mRightPane, "RightPane"); + getWidget(mArmorRating, "ArmorRating"); mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); @@ -288,6 +290,9 @@ namespace MWGui mPreview.update (size.width, size.height); mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); mAvatarImage->setImageTexture("CharacterPreview"); + + mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + + boost::lexical_cast(static_cast(MWWorld::Class::get(mPtr).getArmorRating(mPtr)))); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) @@ -303,7 +308,7 @@ namespace MWGui && (type != typeid(ESM::Ingredient).name()) && (type != typeid(ESM::Light).name()) && (type != typeid(ESM::Miscellaneous).name()) - && (type != typeid(ESM::Tool).name()) + && (type != typeid(ESM::Lockpick).name()) && (type != typeid(ESM::Probe).name()) && (type != typeid(ESM::Repair).name()) && (type != typeid(ESM::Weapon).name()) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 9473f48b4e..f0a3858084 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -9,6 +9,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/fallback.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" @@ -138,9 +139,9 @@ namespace MWGui std::string levelupdescription; if(level>20) - levelupdescription=world->getFallback("Level_Up_Default"); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); else - levelupdescription=world->getFallback("Level_Up_Level"+boost::lexical_cast(level)); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast(level)); mLevelDescription->setCaption (levelupdescription); diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 52b108f850..d0f3f921e5 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -190,8 +190,8 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", marker.name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); markerWidget->setUserString("IsMarker", "true"); markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); @@ -323,16 +323,16 @@ void MapWindow::addVisitedLocation(const std::string& name, int x, int y) widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); ++_counter; markerWidget = mEventBoxGlobal->createWidget("", widgetCoord, MyGUI::Align::Default); markerWidget->setNeedMouseFocus (true); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); } void MapWindow::cellExplored(int x, int y) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp new file mode 100644 index 0000000000..0a65326050 --- /dev/null +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -0,0 +1,132 @@ +#include "merchantrepair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "list.hpp" +#include "inventorywindow.hpp" +#include "tradewindow.hpp" + +namespace MWGui +{ + +MerchantRepair::MerchantRepair(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_merchantrepair.layout", parWindowManager) +{ + getWidget(mList, "RepairView"); + getWidget(mOkButton, "OkButton"); + getWidget(mGoldLabel, "PlayerGold"); + + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); +} + +void MerchantRepair::startRepair(const MWWorld::Ptr &actor) +{ + mActor = actor; + + while (mList->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) + { + int maxDurability = MWWorld::Class::get(*iter).getItemMaxHealth(*iter); + int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + if (maxDurability == durability) + continue; + + int basePrice = MWWorld::Class::get(*iter).getValue(*iter); + float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fRepairMult")->getFloat(); + + float p = std::max(1, basePrice); + float r = std::max(1, static_cast(maxDurability / p)); + + int x = ((maxDurability - durability) / r); + x = (fRepairMult * x); + + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); + + + std::string name = MWWorld::Class::get(*iter).getName(*iter) + + " - " + boost::lexical_cast(price) + + MWBase::Environment::get().getWorld()->getStore().get() + .find("sgp")->getString();; + + + MyGUI::Button* button = + mList->createWidget( + (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + 0, + currentY, + 0, + 18, + MyGUI::Align::Default + ); + + currentY += 18; + + button->setEnabled(price<=mWindowManager.getInventoryWindow()->getPlayerGold()); + button->setUserString("Price", boost::lexical_cast(price)); + button->setUserData(*iter); + button->setCaptionWithReplacing(name); + button->setSize(button->getTextSize().width,18); + button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); + button->setUserString("ToolTipType", "ItemPtr"); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); + } + } + mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); +} + +void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mList->getViewOffset().top + _rel*0.3 > 0) + mList->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mList->setViewOffset(MyGUI::IntPoint(0, mList->getViewOffset().top + _rel*0.3)); +} + +void MerchantRepair::open() +{ + center(); +} + +void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) +{ + // repair + MWWorld::Ptr item = *sender->getUserData(); + item.getCellRef().mCharge = MWWorld::Class::get(item).getItemMaxHealth(item); + + MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); + + int price = boost::lexical_cast(sender->getUserString("Price")); + mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + + startRepair(mActor); +} + +void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) +{ + mWindowManager.removeGuiMode(GM_MerchantRepair); +} + +} diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp new file mode 100644 index 0000000000..4b7e2b8fbd --- /dev/null +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_MWGUI_MERCHANTREPAIR_H +#define OPENMW_MWGUI_MERCHANTREPAIR_H + +#include "window_base.hpp" +#include "../mwworld/ptr.hpp" + + + +namespace MWGui +{ + +class MerchantRepair : public WindowBase +{ +public: + MerchantRepair(MWBase::WindowManager &parWindowManager); + + virtual void open(); + + void startRepair(const MWWorld::Ptr& actor); + +private: + MyGUI::ScrollView* mList; + MyGUI::Button* mOkButton; + MyGUI::TextBox* mGoldLabel; + + MWWorld::Ptr mActor; + +protected: + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onRepairButtonClick(MyGUI::Widget* sender); + void onOkButtonClick(MyGUI::Widget* sender); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 3195372978..4091f47acc 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -16,6 +16,7 @@ namespace MWGui GM_Scroll, // Read scroll GM_Book, // Read book GM_Alchemy, // Make potions + GM_Repair, GM_Dialogue, // NPC interaction GM_Barter, @@ -26,6 +27,7 @@ namespace MWGui GM_SpellCreation, GM_Enchanting, GM_Training, + GM_MerchantRepair, GM_Levelup, diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp new file mode 100644 index 0000000000..f53ddc4305 --- /dev/null +++ b/apps/openmw/mwgui/repair.cpp @@ -0,0 +1,157 @@ +#include "repair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "widgets.hpp" + +namespace MWGui +{ + +Repair::Repair(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_repair.layout", parWindowManager) +{ + getWidget(mRepairBox, "RepairBox"); + getWidget(mRepairView, "RepairView"); + getWidget(mToolBox, "ToolBox"); + getWidget(mToolIcon, "ToolIcon"); + getWidget(mUsesLabel, "UsesLabel"); + getWidget(mQualityLabel, "QualityLabel"); + getWidget(mCancelButton, "CancelButton"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel); +} + +void Repair::open() +{ + center(); +} + +void Repair::startRepairItem(const MWWorld::Ptr &item) +{ + mRepair.setTool(item); + + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + mToolIcon->setImageTexture (path); + mToolIcon->setUserString("ToolTipType", "ItemPtr"); + mToolIcon->setUserData(item); + + updateRepairView(); +} + +void Repair::updateRepairView() +{ + MWWorld::LiveCellRef *ref = + mRepair.getTool().get(); + + int uses = (mRepair.getTool().getCellRef().mCharge != -1) ? mRepair.getTool().getCellRef().mCharge : ref->mBase->mData.mUses; + + float quality = ref->mBase->mData.mQuality; + + std::stringstream qualityStr; + qualityStr << std::setprecision(3) << quality; + + mUsesLabel->setCaptionWithReplacing("#{sUses} " + boost::lexical_cast(uses)); + mQualityLabel->setCaptionWithReplacing("#{sQuality} " + qualityStr.str()); + + bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); + mToolBox->setVisible(toolBoxVisible); + + bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top); + + if (toolBoxVisible && !toolBoxWasVisible) + { + // shrink + mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height)); + mRepairBox->setSize(mRepairBox->getSize() - MyGUI::IntSize(0,mToolBox->getSize().height)); + } + else if (!toolBoxVisible && toolBoxWasVisible) + { + // expand + mRepairBox->setPosition(MyGUI::IntPoint (mRepairBox->getPosition().left, mToolBox->getPosition().top)); + mRepairBox->setSize(mRepairBox->getSize() + MyGUI::IntSize(0,mToolBox->getSize().height)); + } + + while (mRepairView->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; + for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); + iter!=store.end(); ++iter) + { + if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) + { + int maxDurability = MWWorld::Class::get(*iter).getItemMaxHealth(*iter); + int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + if (maxDurability == durability) + continue; + + MyGUI::TextBox* text = mRepairView->createWidget ( + "SandText", MyGUI::IntCoord(8, currentY, mRepairView->getWidth()-8, 18), MyGUI::Align::Default); + text->setCaption(MWWorld::Class::get(*iter).getName(*iter)); + text->setNeedMouseFocus(false); + currentY += 19; + + MyGUI::ImageBox* icon = mRepairView->createWidget ( + "ImageBox", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + icon->setImageTexture (path); + icon->setUserString("ToolTipType", "ItemPtr"); + icon->setUserData(*iter); + icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); + icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); + + Widgets::MWDynamicStatPtr chargeWidget = mRepairView->createWidget + ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); + chargeWidget->setValue(durability, maxDurability); + chargeWidget->setNeedMouseFocus(false); + + currentY += 32 + 4; + } + } + mRepairView->setCanvasSize (MyGUI::IntSize(mRepairView->getWidth(), std::max(mRepairView->getHeight(), currentY))); +} + +void Repair::onCancel(MyGUI::Widget *sender) +{ + mWindowManager.removeGuiMode(GM_Repair); +} + +void Repair::onRepairItem(MyGUI::Widget *sender) +{ + if (!mRepair.getTool().getRefData().getCount()) + return; + + mRepair.repair(*sender->getUserData()); + + updateRepairView(); +} + +void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mRepairView->getViewOffset().top + _rel*0.3 > 0) + mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mRepairView->setViewOffset(MyGUI::IntPoint(0, mRepairView->getViewOffset().top + _rel*0.3)); +} + +} diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp new file mode 100644 index 0000000000..c14b1955bd --- /dev/null +++ b/apps/openmw/mwgui/repair.hpp @@ -0,0 +1,46 @@ +#ifndef OPENMW_MWGUI_REPAIR_H +#define OPENMW_MWGUI_REPAIR_H + +#include "window_base.hpp" + +#include "../mwworld/ptr.hpp" +#include "../mwmechanics/repair.hpp" + +namespace MWGui +{ + +class Repair : public WindowBase +{ +public: + Repair(MWBase::WindowManager &parWindowManager); + + virtual void open(); + + void startRepairItem (const MWWorld::Ptr& item); + +protected: + MyGUI::Widget* mRepairBox; + MyGUI::ScrollView* mRepairView; + + MyGUI::Widget* mToolBox; + + MyGUI::ImageBox* mToolIcon; + + MyGUI::TextBox* mUsesLabel; + MyGUI::TextBox* mQualityLabel; + + MyGUI::Button* mCancelButton; + + MWMechanics::Repair mRepair; + + void updateRepairView(); + + void onRepairItem (MyGUI::Widget* sender); + void onCancel (MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 40fcf2988a..d39ad6a5ae 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -32,20 +32,9 @@ namespace MWGui getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); - getWidget(mSelect, "Select"); - getWidget(mSpells, "Spells"); getWidget(mSpellsView, "SpellsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); - - mSpells->setCoord(450/2-mSpells->getTextSize().width/2, - mSpells->getTop(), - mSpells->getTextSize().width, - mSpells->getHeight()); - mSelect->setCoord(8, - mSelect->getTop(), - mSelect->getTextSize().width, - mSelect->getHeight()); } void SpellBuyingWindow::addSpell(const std::string& spellId) diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index c4988fff35..f9cda35df0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,8 +28,6 @@ namespace MWGui protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - MyGUI::TextBox* mSpells; - MyGUI::TextBox* mSelect; MyGUI::ScrollView* mSpellsView; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8395864521..8a079e40ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -454,10 +454,13 @@ namespace MWGui mAvailableEffectsList->clear (); + int i=0; for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString()); + mButtonMapping[i] = *it; + ++i; } mAvailableEffectsList->adjustSize (); @@ -466,7 +469,6 @@ namespace MWGui std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); - w->setUserData(*it); ToolTips::createMagicEffectToolTip (w, *it); } @@ -518,7 +520,8 @@ namespace MWGui return; } - short effectId = *sender->getUserData(); + int buttonId = *sender->getUserData(); + short effectId = mButtonMapping[buttonId]; for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 4d27ec1c6f..393d9c3ec2 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -88,6 +88,8 @@ namespace MWGui protected: + std::map mButtonMapping; // maps button ID to effect ID + Widgets::MWList* mAvailableEffectsList; MyGUI::ScrollView* mUsedEffectsView; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8eb0336a79..af3e146bba 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -90,7 +90,20 @@ void ToolTips::onFrame(float frameDuration) if (mFocusObject.isEmpty ()) return; - MyGUI::IntSize tooltipSize = getToolTipViaPtr(true); + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + + IntSize tooltipSize; + if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=mFocusObject.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0fd24601a8..f84a0abc88 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -368,7 +368,7 @@ namespace MWGui return services & ESM::NPC::Books; else if (item.getTypeName() == typeid(ESM::Ingredient).name()) return services & ESM::NPC::Ingredients; - else if (item.getTypeName() == typeid(ESM::Tool).name()) + else if (item.getTypeName() == typeid(ESM::Lockpick).name()) return services & ESM::NPC::Picks; else if (item.getTypeName() == typeid(ESM::Probe).name()) return services & ESM::NPC::Probes; diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 794a9ab55f..df8a52456c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -132,7 +132,7 @@ namespace MWGui case 11: month = "#{sMonthEveningstar}"; break; - default: + default: break; } int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); @@ -142,7 +142,7 @@ namespace MWGui std::string dateTimeText = boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()) + " " - + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay ()+1) + + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mDateTimeText->setCaptionWithReplacing (dateTimeText); @@ -156,13 +156,13 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - + float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; - - bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(136)).mMagnitude > 0); + + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); - + // this massive duplication is why it has to be put into helper functions instead float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat(); float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat(); @@ -174,7 +174,7 @@ namespace MWGui normalizedEncumbrance = 1; float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); - + float healthHours = hourlyHealthDelta >= 0.0 ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta : 1.0f; @@ -185,9 +185,9 @@ namespace MWGui float fatigueHours = hourlyFatigueDelta >= 0.0 ? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta : 1.0f; - + int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible - + startWaiting(autoHours); } @@ -201,11 +201,11 @@ namespace MWGui MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); setVisible(false); mProgressBar.setVisible (true); - + mWaiting = true; mCurHour = 0; mHours = hoursToWait; - + mRemainingTime = 0.05; mProgressBar.setProgress (0, mHours); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3da739e260..718bb7106e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -55,6 +55,8 @@ #include "exposedwindow.hpp" #include "cursor.hpp" #include "spellicons.hpp" +#include "merchantrepair.hpp" +#include "repair.hpp" using namespace MWGui; @@ -90,6 +92,8 @@ WindowManager::WindowManager( , mSpellCreationDialog(NULL) , mEnchantingDialog(NULL) , mTrainingWindow(NULL) + , mMerchantRepair(NULL) + , mRepair(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -180,6 +184,8 @@ WindowManager::WindowManager( mSpellCreationDialog = new SpellCreationDialog(*this); mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); + mMerchantRepair = new MerchantRepair(*this); + mRepair = new Repair(*this); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -245,6 +251,8 @@ WindowManager::~WindowManager() delete mTrainingWindow; delete mCountDialog; delete mQuickKeysMenu; + delete mMerchantRepair; + delete mRepair; delete mCursor; cleanupGarbage(); @@ -303,6 +311,8 @@ void WindowManager::updateVisible() mSpellCreationDialog->setVisible(false); mEnchantingDialog->setVisible(false); mTrainingWindow->setVisible(false); + mMerchantRepair->setVisible(false); + mRepair->setVisible(false); mHud->setVisible(mHudEnabled); @@ -428,6 +438,12 @@ void WindowManager::updateVisible() case GM_Training: mTrainingWindow->setVisible(true); break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; + case GM_Repair: + mRepair->setVisible(true); + break; case GM_InterMessageBox: break; case GM_Journal: @@ -1020,6 +1036,13 @@ bool WindowManager::isGuiMode() const return !mGuiModes.empty(); } +bool WindowManager::isConsoleMode() const +{ + if (mGuiModes.back()==GM_Console) + return true; + return false; +} + MWGui::GuiMode WindowManager::getMode() const { if (mGuiModes.empty()) @@ -1125,6 +1148,16 @@ void WindowManager::startTraining(MWWorld::Ptr actor) mTrainingWindow->startTraining(actor); } +void WindowManager::startRepair(MWWorld::Ptr actor) +{ + mMerchantRepair->startRepair(actor); +} + +void WindowManager::startRepairItem(MWWorld::Ptr item) +{ + mRepair->startRepairItem(item); +} + const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 122b10cc39..216ab9a6f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -74,6 +74,8 @@ namespace MWGui class TrainingWindow; class Cursor; class SpellIcons; + class MerchantRepair; + class Repair; class WindowManager : public MWBase::WindowManager { @@ -102,6 +104,8 @@ namespace MWGui virtual bool isGuiMode() const; + virtual bool isConsoleMode() const; + virtual void toggleVisible(GuiWindow wnd); // Disallow all inventory mode windows @@ -227,6 +231,8 @@ namespace MWGui virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); + virtual void startRepair(MWWorld::Ptr actor); + virtual void startRepairItem(MWWorld::Ptr item); virtual void changePointer (const std::string& name); @@ -264,6 +270,9 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; + MerchantRepair* mMerchantRepair; + Repair* mRepair; + Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f18c02a0e8..f49422747f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -55,6 +55,7 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) + , mAlwaysRunActive(false) { Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; @@ -180,12 +181,12 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - activate(); if( MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); } + activate(); break; case A_Journal: toggleJournal (); @@ -193,7 +194,7 @@ namespace MWInput case A_AutoMove: toggleAutoMove (); break; - case A_ToggleWalk: + case A_AlwaysRun: toggleWalking (); break; case A_ToggleWeapon: @@ -315,10 +316,10 @@ namespace MWInput else mPlayer.setUpDown (0); - if(actionIsActive(A_Run)) - mPlayer.setRunState(true); + if (mAlwaysRunActive) + mPlayer.setRunState(!actionIsActive(A_Run)); else - mPlayer.setRunState(false); + mPlayer.setRunState(actionIsActive(A_Run)); // if player tried to start moving, but can't (due to being overencumbered), display a notification. if (triedToMove) @@ -699,7 +700,7 @@ namespace MWInput void InputManager::toggleWalking() { if (mWindows.isGuiMode()) return; - mPlayer.toggleRunning(); + mAlwaysRunActive = !mAlwaysRunActive; } // Exit program now button (which is disabled in GUI mode) @@ -768,6 +769,7 @@ namespace MWInput defaultKeyBindings[A_QuickKey10] = OIS::KC_0; defaultKeyBindings[A_Screenshot] = OIS::KC_SYSRQ; defaultKeyBindings[A_ToggleHUD] = OIS::KC_F12; + defaultKeyBindings[A_AlwaysRun] = OIS::KC_Y; std::map defaultMouseButtonBindings; defaultMouseButtonBindings[A_Inventory] = OIS::MB_Right; @@ -834,6 +836,7 @@ namespace MWInput descriptions[A_QuickKey8] = "sQuick8Cmd"; descriptions[A_QuickKey9] = "sQuick9Cmd"; descriptions[A_QuickKey10] = "sQuick10Cmd"; + descriptions[A_AlwaysRun] = "sAlways_Run"; if (descriptions[action] == "") return ""; // not configurable @@ -865,6 +868,7 @@ namespace MWInput ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); ret.push_back(A_Run); + ret.push_back(A_AlwaysRun); ret.push_back(A_Sneak); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 8bb20b7bed..e181fb351d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -152,6 +152,7 @@ namespace MWInput int mMouseWheel; bool mDebug; bool mUserFileExists; + bool mAlwaysRunActive; std::map mControlSwitch; @@ -217,7 +218,7 @@ namespace MWInput A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponRight, A_ToggleSneak, //Toggles Sneak - A_ToggleWalk, //Toggle Walking/Running + A_AlwaysRun, //Toggle Walking/Running A_Sneak, A_QuickSave, diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9632bdf769..1480b3182e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,7 @@ namespace MWMechanics int endurance = creatureStats.getAttribute(5).getBase(); double magickaFactor = - creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5; + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude * 0.1 + 0.5; DynamicStat health = creatureStats.getHealth(); health.setBase (static_cast (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ()); @@ -80,7 +80,7 @@ namespace MWMechanics DynamicStat magicka = creatureStats.getMagicka(); magicka.setBase (static_cast (intelligence + magickaFactor * intelligence)); creatureStats.setMagicka (magicka); - + DynamicStat fatigue = creatureStats.getFatigue(); fatigue.setBase (strength+willpower+agility+endurance); creatureStats.setFatigue (fatigue); @@ -92,11 +92,10 @@ namespace MWMechanics if (duration == 3600) { - // stunted magicka - bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(136)).mMagnitude > 0; + bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - + DynamicStat health = stats.getHealth(); health.setCurrent (health.getCurrent() + 0.1 * endurance); stats.setHealth (health); @@ -115,15 +114,15 @@ namespace MWMechanics float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; - + DynamicStat fatigue = stats.getFatigue(); fatigue.setCurrent (fatigue.getCurrent() + 3600 * x); stats.setFatigue (fatigue); - + if (!stunted) { float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat (); - + DynamicStat magicka = stats.getMagicka(); magicka.setCurrent (magicka.getCurrent() + fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified()); @@ -140,31 +139,34 @@ namespace MWMechanics for (int i=0; i<8; ++i) { int modifier = - creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude; + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyAttribute, i)).mMagnitude; - modifier -= creatureStats.getMagicEffects().get (EffectKey (17, i)).mMagnitude; + modifier -= creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::DrainAttribute, i)).mMagnitude; creatureStats.getAttribute(i).setModifier (modifier); } // dynamic stats MagicEffects effects = creatureStats.getMagicEffects(); - + for (int i=0; i<3; ++i) { DynamicStat stat = creatureStats.getDynamic (i); - + stat.setModifier ( effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude); - + creatureStats.setDynamic (i, stat); - } + } } Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) { + // erase previous death events since we are currently only tracking them while in an active cell + MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); @@ -278,7 +280,7 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) calculateRestoration(iter->first, 3600); } - + int Actors::countDeaths (const std::string& id) const { std::map::const_iterator iter = mDeathCount.find(id); diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 94f6fd8928..2c5260a625 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -46,7 +46,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; - for(int i=1; imPoints.size();i++) + for(unsigned int i=1; imPoints.size();++i) { if(distance(grid->mPoints[i],x,y,z)mPoints.size();i++) + for(unsigned int i = 0;imPoints.size();++i) { PointID pID = boost::add_vertex(graph); graph[pID].mX = pathgrid->mPoints[i].mX + xCell; @@ -147,7 +147,7 @@ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCe graph[pID].mZ = pathgrid->mPoints[i].mZ; } - for(int i = 0;imEdges.size();i++) + for(unsigned int i = 0;imEdges.size();++i) { PointID u = pathgrid->mEdges[i].mV0; PointID v = pathgrid->mEdges[i].mV1; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 3d220cb7e3..ef2359ba91 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,35 +1,35 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H - -#include "aipackage.hpp" -#include "components\esm\loadpgrd.hpp" -#include - -namespace MWMechanics -{ - class AiTravel : public AiPackage - { - public: - AiTravel(float x, float y, float z); - virtual AiTravel *clone() const; - - virtual bool execute (const MWWorld::Ptr& actor); - ///< \return Package completed? - - virtual int getTypeId() const; - - private: - float mX; - float mY; - float mZ; - - int cellX; - int cellY; - - bool isPathConstructed; - std::list mPath; - - }; + +#include "aipackage.hpp" +#include +#include + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + int cellX; + int cellY; + + bool isPathConstructed; + std::list mPath; + + }; } #endif diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 4be5d55b22..19d2080211 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -10,7 +10,8 @@ namespace MWMechanics { CreatureStats::CreatureStats() - : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), + : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mDied (false), mFriendlyHits (0), + mTalkedTo (false), mAlarmed (false), mAttacked (false), mHostile (false) { for (int i=0; i<4; ++i) @@ -167,7 +168,12 @@ namespace MWMechanics mDynamic[index] = value; if (index==0 && mDynamic[index].getCurrent()<1) + { + if (!mDead) + mDied = true; + mDead = true; + } } void CreatureStats::setLevel(int level) @@ -196,6 +202,16 @@ namespace MWMechanics return mDead; } + bool CreatureStats::hasDied() const + { + return mDied; + } + + void CreatureStats::clearHasDied() + { + mDied = false; + } + void CreatureStats::resurrect() { if (mDead) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 3375c1af83..63de13d0d4 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -28,6 +28,7 @@ namespace MWMechanics AiSequence mAiSequence; float mLevelHealthBonus; bool mDead; + bool mDied; int mFriendlyHits; bool mTalkedTo; bool mAlarmed; @@ -100,6 +101,10 @@ namespace MWMechanics bool isDead() const; + bool hasDied() const; + + void clearHasDied(); + void resurrect(); bool hasCommonDisease() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c9e4c77eaf..32fa58980d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,7 @@ #include "mechanicsmanagerimp.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp new file mode 100644 index 0000000000..8ed4498859 --- /dev/null +++ b/apps/openmw/mwmechanics/repair.cpp @@ -0,0 +1,110 @@ +#include "repair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" + +namespace MWMechanics +{ + +void Repair::repair(const MWWorld::Ptr &itemToRepair) +{ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::LiveCellRef *ref = + mTool.get(); + + // reduce number of uses left + int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses; + mTool.getCellRef().mCharge = uses-1; + + // unstack tool if required + if (mTool.getRefData().getCount() > 1 && uses == ref->mBase->mData.mUses) + { + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + MWWorld::ContainerStoreIterator it = store.add(mTool); + it->getRefData().setCount(mTool.getRefData().getCount()-1); + it->getCellRef().mCharge = -1; + + mTool.getRefData().setCount(1); + } + + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player); + + float fatigueTerm = stats.getFatigueTerm(); + int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified(); + int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); + int armorerSkill = npcStats.getSkill(ESM::Skill::Armorer).getModified(); + + float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fRepairAmountMult")->getFloat(); + + float toolQuality = ref->mBase->mData.mQuality; + + float x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) * fatigueTerm; + + int roll = static_cast (std::rand()) / RAND_MAX * 100; + if (roll <= x) + { + int y = fRepairAmountMult * toolQuality * roll; + y = std::max(1, y); + + // repair by 'y' points + itemToRepair.getCellRef().mCharge += y; + itemToRepair.getCellRef().mCharge = std::min(itemToRepair.getCellRef().mCharge, + MWWorld::Class::get(itemToRepair).getItemMaxHealth(itemToRepair)); + + // set the OnPCRepair variable on the item's script + std::string script = MWWorld::Class::get(itemToRepair).getScript(itemToRepair); + if(script != "") + itemToRepair.getRefData().getLocals().setVarByInt(script, "onpcrepair", 1); + + // increase skill + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Armorer, 0); + + MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); + MWBase::Environment::get().getWindowManager()->messageBox("#{sRepairSuccess}"); + } + else + { + MWBase::Environment::get().getSoundManager()->playSound("Repair Fail",1,1); + MWBase::Environment::get().getWindowManager()->messageBox("#{sRepairFailed}"); + } + + // tool used up? + if (mTool.getCellRef().mCharge == 0) + { + mTool.getRefData().setCount(0); + + std::string message = MWBase::Environment::get().getWorld()->getStore().get() + .find("sNotifyMessage51")->getString(); + + MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % MWWorld::Class::get(mTool).getName(mTool)).str()); + + // try to find a new tool of the same ID + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, mTool.getCellRef().mRefID)) + { + mTool = *iter; + break; + } + } + } +} + +} diff --git a/apps/openmw/mwmechanics/repair.hpp b/apps/openmw/mwmechanics/repair.hpp new file mode 100644 index 0000000000..6f9a866af1 --- /dev/null +++ b/apps/openmw/mwmechanics/repair.hpp @@ -0,0 +1,23 @@ +#ifndef OPENMW_MWMECHANICS_REPAIR_H +#define OPENMW_MWMECHANICS_REPAIR_H + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + + class Repair + { + public: + void setTool (const MWWorld::Ptr& tool) { mTool = tool; } + MWWorld::Ptr getTool() { return mTool; } + + void repair (const MWWorld::Ptr& itemToRepair); + + private: + MWWorld::Ptr mTool; + }; + +} + +#endif diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c99e426624..843bcf007b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -104,11 +104,14 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + float scale=1.f; + MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); + mNode->setScale(Ogre::Vector3(scale)); + mNode->setVisible (false); - Ogre::Vector3 scale = mNode->getScale(); - mCamera->setPosition(mPosition * scale); - mCamera->lookAt(mLookAt * scale); + mCamera->setPosition(mPosition * mNode->getScale()); + mCamera->lookAt(mLookAt * mNode->getScale()); onSetup(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9da70beb45..b76a38c469 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -85,11 +85,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); - float scale = race->mData.mHeight.mMale; - if(!mNpc->isMale()) - scale = race->mData.mHeight.mFemale; - node->scale(Ogre::Vector3(scale)); - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index cb1dfa75be..23d35c65f0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -16,16 +16,31 @@ #include "renderconst.hpp" using namespace MWRender; +float Objects::lightLinearValue() +{ + return mFallback->getFallbackFloat("LightAttenuation_LinearValue"); +} +float Objects::lightLinearRadiusMult() +{ + return mFallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); +} +float Objects::lightQuadraticValue() +{ + return mFallback->getFallbackFloat("LightAttenuation_QuadraticValue"); +} +float Objects::lightQuadraticRadiusMult() +{ + return mFallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); +} -/// \todo Replace these, once fallback values from the ini file are available. -float Objects::lightLinearValue = 3; -float Objects::lightLinearRadiusMult = 1; - -float Objects::lightQuadraticValue = 16; -float Objects::lightQuadraticRadiusMult = 1; - -bool Objects::lightOutQuadInLin = true; -bool Objects::lightQuadratic = false; +bool Objects::lightOutQuadInLin() +{ + return mFallback->getFallbackBool("LightAttenuation_OutQuadInLin"); +} +bool Objects::lightQuadratic() +{ + return mFallback->getFallbackBool("LightAttenuation_UseQuadratic"); +} int Objects::uniqueID = 0; @@ -269,14 +284,14 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre if (!quadratic) { - float r = radius * lightLinearRadiusMult; - float attenuation = lightLinearValue / r; + float r = radius * lightLinearRadiusMult(); + float attenuation = lightLinearValue() / r; light->setAttenuation(r*10, 0, attenuation, 0); } else { - float r = radius * lightQuadraticRadiusMult; - float attenuation = lightQuadraticValue / pow(r, 2); + float r = radius * lightQuadraticRadiusMult(); + float attenuation = lightQuadraticValue() / pow(r, 2); light->setAttenuation(r*10, 0, 0, attenuation); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 73e95a3c53..cfe5243061 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -5,6 +5,7 @@ #include #include +#include "../mwworld/fallback.hpp" namespace MWWorld { @@ -56,21 +57,21 @@ class Objects{ Ogre::SceneNode* mRootNode; bool mIsStatic; static int uniqueID; + MWWorld::Fallback* mFallback; + float lightLinearValue(); + float lightLinearRadiusMult(); - static float lightLinearValue; - static float lightLinearRadiusMult; + bool lightQuadratic(); + float lightQuadraticValue(); + float lightQuadraticRadiusMult(); - static bool lightQuadratic; - static float lightQuadraticValue; - static float lightQuadraticRadiusMult; - - static bool lightOutQuadInLin; + bool lightOutQuadInLin(); void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} + Objects(OEngine::Render::OgreRenderer& renderer, MWWorld::Fallback* fallback): mRenderer (renderer), mIsStatic(false), mFallback(fallback) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e6216b5372..1bab676c3c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -48,9 +48,10 @@ using namespace Ogre; namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback) : mRendering(_rend) - , mObjects(mRendering) + , mFallback(fallback) + , mObjects(mRendering,mFallback) , mActors(mRendering, this) , mAmbientMode(0) , mSunEnabled(0) @@ -884,6 +885,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) mPlayer->setAnimation(anim); mWater->removeEmitter (ptr); mWater->addEmitter (ptr); + // apply race height + MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); } void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1777a72c33..fd43438ca5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -60,7 +60,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList public: RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine); + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback); virtual ~RenderingManager(); void togglePOV() { @@ -220,6 +220,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList bool mSunEnabled; + MWWorld::Fallback* mFallback; + SkyManager* mSkyManager; OcclusionQuery* mOcclusionQuery; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 604ad50d22..94af3521b3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -21,6 +21,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/fallback.hpp" + #include "renderconst.hpp" #include "renderingmanager.hpp" @@ -266,11 +268,12 @@ void SkyManager::create() mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); - mSecunda = new Moon("secunda_texture", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + mSecunda = new Moon("secunda_texture", /*0.5*/fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("masser_texture", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mMasser = new Moon("masser_texture", /*0.75*/fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); @@ -368,7 +371,7 @@ int SkyManager::getSecundaPhase() const void SkyManager::update(float duration) { if (!mEnabled) return; - + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mCamera->getParentSceneNode ()->needUpdate (); mRootNode->setPosition(mCamera->getDerivedPosition()); @@ -381,7 +384,7 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setColour ( mMoonRed ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1,1,1,1)); + mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 57d93512f4..7e63a33b25 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -59,7 +59,7 @@ namespace MWScript store.get().search (name) || store.get().search (name) || store.get().search (name) || - store.get().search (name) || + store.get().search (name) || store.get().search (name) || store.get().search (name) || store.get().search (name) || diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 283f149de2..0f07b4d2e8 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -315,5 +315,6 @@ op 0x20001f8: Drop op 0x20001f9: Drop, explicit reference op 0x20001fa: DropSoulGem op 0x20001fb: DropSoulGem, explicit reference +op 0x20001fc: OnDeath -opcodes 0x20001fa-0x3ffffff unused +opcodes 0x20001fd-0x3ffffff unused diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c74e3f1633..cad143c469 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -215,19 +215,22 @@ namespace MWScript std::string InterpreterContext::getNPCRace() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mRace); + return race->mName; } std::string InterpreterContext::getNPCClass() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mClass; + const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mClass); + return class_->mName; } std::string InterpreterContext::getNPCFaction() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mFaction; + const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mFaction); + return faction->mName; } std::string InterpreterContext::getNPCRank() const diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index f0b2758d9e..9c7b443ae1 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -89,7 +89,7 @@ namespace MWScript virtual std::string getNPCClass() const; virtual std::string getNPCFaction() const; - + virtual std::string getNPCRank() const; virtual std::string getPCName() const; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 530d44c9dd..c5fc9436be 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1025,6 +1025,27 @@ namespace MWScript } }; + class OpOnDeath : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + Interpreter::Type_Integer value = + MWWorld::Class::get (ptr).getCreatureStats (ptr).hasDied(); + + if (value) + MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); + + runtime.push (value); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -1114,6 +1135,8 @@ namespace MWScript const int opcodeLowerRank = 0x20001ea; const int opcodeLowerRankExplicit = 0x20001eb; + const int opcodeOnDeath = 0x20001fc; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -1227,6 +1250,8 @@ namespace MWScript extensions.registerInstruction ("pcclearexpelled", "/S", opcodePcClearExpelled, opcodePcClearExpelledExplicit); extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit); extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); + + extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -1341,6 +1366,8 @@ namespace MWScript interpreter.installSegment5 (opcodeRaiseRankExplicit, new OpRaiseRank); interpreter.installSegment5 (opcodeLowerRank, new OpLowerRank); interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); + + interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); } } } diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp new file mode 100644 index 0000000000..bd56421165 --- /dev/null +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -0,0 +1,18 @@ +#include "actionrepair.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +namespace MWWorld +{ + ActionRepair::ActionRepair(const Ptr &item) + : Action(false, item) + { + } + + void ActionRepair::executeImp (const Ptr& actor) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); + MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); + } +} diff --git a/apps/openmw/mwworld/actionrepair.hpp b/apps/openmw/mwworld/actionrepair.hpp new file mode 100644 index 0000000000..1d3ef2bc11 --- /dev/null +++ b/apps/openmw/mwworld/actionrepair.hpp @@ -0,0 +1,17 @@ +#ifndef GAME_MWWORLD_ACTIONREPAIR_H +#define GAME_MWWORLD_ACTIONREPAIR_H + +#include "action.hpp" + +namespace MWWorld +{ + class ActionRepair : public Action + { + virtual void executeImp (const Ptr& actor); + + public: + ActionRepair(const MWWorld::Ptr& item); + }; +} + +#endif diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index f95d30df13..5f771be475 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -206,7 +206,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce if (MWWorld::LiveCellRef *ref = cell.mLights.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) ptr = Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = cell.mMiscItems.find (name)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index c182f196bc..2e6b45bb7e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -112,7 +112,7 @@ namespace MWWorld CellRefList mCreatureLists; CellRefList mItemLists; CellRefList mLights; - CellRefList mLockpicks; + CellRefList mLockpicks; CellRefList mMiscItems; CellRefList mNpcs; CellRefList mProbes; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..108efddd81 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -167,9 +167,14 @@ namespace MWWorld return false; } - bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const + bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const { - return false; + return true; + } + + float Class::getArmorRating (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error("Class does not support armor rating"); } const Class& Class::get (const std::string& key) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1a6a16ca07..53dbeff862 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -215,6 +215,9 @@ namespace MWWorld ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8a7884e9e0..ac27beb44a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -38,12 +38,6 @@ namespace return sum; } - - bool compare_string_ci(std::string str1, std::string str2) - { - Misc::StringUtils::toLower(str1); - return str1 == str2; - } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -62,13 +56,17 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { - /// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented + /// \todo add current enchantment charge here when it is implemented if ( ptr1.mCellRef->mRefID == ptr2.mCellRef->mRefID && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) && ptr1.mCellRef->mOwner == ptr2.mCellRef->mOwner && ptr1.mCellRef->mSoul == ptr2.mCellRef->mSoul - && ptr1.mCellRef->mCharge == ptr2.mCellRef->mCharge) + // item that is already partly used up never stacks + && (!MWWorld::Class::get(ptr1).hasItemHealth(ptr1) || ptr1.mCellRef->mCharge == -1 + || MWWorld::Class::get(ptr1).getItemMaxHealth(ptr1) == ptr1.mCellRef->mCharge) + && (!MWWorld::Class::get(ptr2).hasItemHealth(ptr2) || ptr2.mCellRef->mCharge == -1 + || MWWorld::Class::get(ptr2).getItemMaxHealth(ptr2) == ptr2.mCellRef->mCharge)) return true; return false; @@ -118,11 +116,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) MWWorld::LiveCellRef *gold = ptr.get(); - if (compare_string_ci(gold->mRef.mRefID, "gold_001") - || compare_string_ci(gold->mRef.mRefID, "gold_005") - || compare_string_ci(gold->mRef.mRefID, "gold_010") - || compare_string_ci(gold->mRef.mRefID, "gold_025") - || compare_string_ci(gold->mRef.mRefID, "gold_100")) + if (Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_001") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_005") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_010") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_025") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_100")) { MWWorld::ManualRef ref(esmStore, "Gold_001"); @@ -130,7 +128,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (compare_string_ci((*iter).get()->mRef.mRefID, "gold_001")) + if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); @@ -171,7 +169,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr case Type_Clothing: clothes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.mList.end()); break; case Type_Ingredient: ingreds.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.mList.end()); break; case Type_Light: lights.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.mList.end()); break; - case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; + case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; case Type_Miscellaneous: miscItems.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.mList.end()); break; case Type_Probe: probes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.mList.end()); break; case Type_Repair: repairs.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.mList.end()); break; @@ -272,7 +270,7 @@ int MWWorld::ContainerStore::getType (const Ptr& ptr) if (ptr.getTypeName()==typeid (ESM::Light).name()) return Type_Light; - if (ptr.getTypeName()==typeid (ESM::Tool).name()) + if (ptr.getTypeName()==typeid (ESM::Lockpick).name()) return Type_Lockpick; if (ptr.getTypeName()==typeid (ESM::Miscellaneous).name()) @@ -321,7 +319,7 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *contain : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e4f75d5478..9d315d27f0 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -44,7 +44,7 @@ namespace MWWorld MWWorld::CellRefList clothes; MWWorld::CellRefList ingreds; MWWorld::CellRefList lights; - MWWorld::CellRefList lockpicks; + MWWorld::CellRefList lockpicks; MWWorld::CellRefList miscItems; MWWorld::CellRefList probes; MWWorld::CellRefList repairs; @@ -127,7 +127,7 @@ namespace MWWorld MWWorld::CellRefList::List::iterator mClothing; MWWorld::CellRefList::List::iterator mIngredient; MWWorld::CellRefList::List::iterator mLight; - MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mLockpick; MWWorld::CellRefList::List::iterator mMiscellaneous; MWWorld::CellRefList::List::iterator mProbe; MWWorld::CellRefList::List::iterator mRepair; @@ -149,7 +149,7 @@ namespace MWWorld ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index b9b95e4f4e..61a106e163 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -32,7 +32,7 @@ namespace MWWorld Store mCreatureLists; Store mItemLists; Store mLights; - Store mLockpicks; + Store mLockpicks; Store mMiscItems; Store mNpcs; Store mNpcChange; @@ -312,7 +312,7 @@ namespace MWWorld } template <> - inline const Store &ESMStore::get() const { + inline const Store &ESMStore::get() const { return mLockpicks; } diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp new file mode 100644 index 0000000000..569a6b50c2 --- /dev/null +++ b/apps/openmw/mwworld/fallback.cpp @@ -0,0 +1,49 @@ +#include "fallback.hpp" +#include "boost/lexical_cast.hpp" +namespace MWWorld +{ + Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) + {} + + std::string Fallback::getFallbackString(const std::string& fall) const + { + std::map::const_iterator it; + if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) + { + return ""; + } + return it->second; + } + float Fallback::getFallbackFloat(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback.empty()) + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback.empty()) + return false; + else + return boost::lexical_cast(fallback); + } + Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const + { + std::string sum=getFallbackString(fall); + if(sum.empty()) + return Ogre::ColourValue(0,0,0); + else + { + std::string ret[3]; + unsigned int j=0; + for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + } + } +} diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp new file mode 100644 index 0000000000..6c5802e071 --- /dev/null +++ b/apps/openmw/mwworld/fallback.hpp @@ -0,0 +1,22 @@ +#ifndef GAME_MWWORLD_FALLBACK_H +#define GAME_MWWORLD_FALLBACK_H + +#include +#include + +#include + +namespace MWWorld +{ + class Fallback + { + const std::map mFallbackMap; + public: + Fallback(const std::map& fallback); + std::string getFallbackString(const std::string& fall) const; + float getFallbackFloat(const std::string& fall) const; + bool getFallbackBool(const std::string& fall) const; + Ogre::ColourValue getFallbackColour(const std::string& fall) const; + }; +} +#endif diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 9e57910ee0..72bebc0498 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -79,7 +79,7 @@ namespace MWWorld { // vanilla Morrowind does not define dayspassed. Data value; - value.mLong = 0; + value.mLong = 1; // but the addons start counting at 1 :( mVariables.insert (std::make_pair ("dayspassed", std::make_pair ('l', value))); } diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 91b8cf8cd4..58395d8798 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -53,7 +53,7 @@ namespace MWWorld !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && - !create (store.get(), name) && + !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && @@ -68,8 +68,7 @@ namespace MWWorld cellRef.mRefnum = -1; cellRef.mScale = 1; cellRef.mFactIndex = 0; - cellRef.mCharge = 0; - cellRef.mIntv = 0; + cellRef.mCharge = -1; cellRef.mNam9 = 0; cellRef.mTeleport = false; cellRef.mLockLevel = 0; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 03dd1abc79..0dc8b37eff 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -77,15 +77,6 @@ namespace MWWorld MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run); } - void Player::toggleRunning() - { - MWWorld::Ptr ptr = getPlayer(); - - bool running = MWWorld::Class::get (ptr).getStance (ptr, MWWorld::Class::Run, true); - - MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); - } - void Player::setSneak(bool sneak) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 5f2fc3a08b..d82d3fc329 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -66,7 +66,6 @@ namespace MWWorld void setUpDown(int value); void setRunState(bool run); - void toggleRunning(); void setSneak(bool sneak); }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 592fb5c80a..339026ca60 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -41,7 +41,7 @@ namespace ++current; - if (it->mData.getCount() || it->mData.isEnabled()) + if (it->mData.getCount() && it->mData.isEnabled()) { MWWorld::Ptr ptr (&*it, &cell); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 586e407ff0..f69f606b45 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,18 +187,20 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - // delete from the static part of mShared - typename std::vector::iterator sharedIter = mShared.begin(); - for (; sharedIter != (mShared.begin()+mStatic.size()); ++sharedIter) { - if((*sharedIter)->mId == item.mId) { - mShared.erase(sharedIter); - break; - } - } - typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + typename std::vector::iterator end = sharedIter + mStatic.size(); + + while (sharedIter != mShared.end() && sharedIter != end) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); + break; + } + ++sharedIter; + } mStatic.erase(it); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 052ae4e028..3e85253123 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -13,94 +12,75 @@ #include "player.hpp" #include "esmstore.hpp" +#include "fallback.hpp" using namespace Ogre; using namespace MWWorld; using namespace MWSound; -#define lerp(x, y) (x * (1-factor) + y * factor) -std::string WeatherManager::getFallback (const std::string& key) const +namespace { - std::map::const_iterator it; - if((it = mFallback.find(key)) == mFallback.end()) + float lerp (float x, float y, float factor) { - return ""; + return x * (1-factor) + y * factor; + } + Ogre::ColourValue lerp (const Ogre::ColourValue& x, const Ogre::ColourValue& y, float factor) + { + return x * (1-factor) + y * factor; } - return it->second; -} -std::string WeatherManager::getFallbackString(const std::string& fall) const -{ - return getFallback(fall); } -float WeatherManager::getFallbackFloat(const std::string& fall) const -{ - std::string fallback=getFallbackString(fall); - return boost::lexical_cast(fallback); -} - -ColourValue WeatherManager::getFallbackColour(const std::string& fall) const -{ - std::string sum; - std::string ret[3]; - sum=getFallback(fall); - unsigned int j=0; - for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); -} void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = getFallbackFloat("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = getFallbackFloat("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = getFallbackFloat("Weather_"+upper+"_Glare_View"); + weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); + weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); + weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); + weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); + weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); + weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); + weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); + weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); + weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); + weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); + weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); + weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); + weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); + weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); + weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); + weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); + weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); + weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); + weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); + weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); + weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed"); + weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); + weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); mWeatherSettings[name] = weather; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std::map& fallbackMap) : +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), mMonth(0), mDay(0), - mTimePassed(0), mFallback(fallbackMap) + mTimePassed(0), mFallback(fallback) { mRendering = rendering; //Globals - mThunderSoundID0 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); + mHoursBetweenWeatherChanges = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mWeatherUpdateTime = mHoursBetweenWeatherChanges*3600; + mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; //Weather Weather clear; @@ -139,64 +119,14 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std:: blight.mAmbientLoopSoundID = "blight"; setFallbackWeather(blight,"blight"); - /* Weather snow; snow.mCloudTexture = "tx_bm_sky_snow.dds"; - snow.mCloudsMaximumPercent = 1.0; - snow.mTransitionDelta = 0.014; - snow.mSkySunriseColor = clr(196, 91, 91); - snow.mSkyDayColor = clr(153, 158, 166); - snow.mSkySunsetColor = clr(96, 115, 134); - snow.mSkyNightColor = clr(31, 35, 39); - snow.mFogSunriseColor = clr(106, 91, 91); - snow.mFogDayColor = clr(153, 158, 166); - snow.mFogSunsetColor = clr(96, 115, 134); - snow.mFogNightColor = clr(31, 35, 39); - snow.mAmbientSunriseColor = clr(92, 84, 84); - snow.mAmbientDayColor = clr(93, 96, 105); - snow.mAmbientSunsetColor = clr(70, 79, 87); - snow.mAmbientNightColor = clr(49, 58, 68); - snow.mSunSunriseColor = clr(141, 109, 109); - snow.mSunDayColor = clr(163, 169, 183); - snow.mSunSunsetColor = clr(101, 121, 141); - snow.mSunNightColor = clr(55, 66, 77); - snow.mSunDiscSunsetColor = clr(128, 128, 128); - snow.mLandFogDayDepth = 1.0; - snow.mLandFogNightDepth = 1.2; - snow.mWindSpeed = 0; - snow.mCloudSpeed = 1.5; - snow.mGlareView = 0; - mWeatherSettings["snow"] = snow; + setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; - blizzard.mCloudsMaximumPercent = 1.0; - blizzard.mTransitionDelta = 0.030; - blizzard.mSkySunriseColor = clr(91, 99, 106); - blizzard.mSkyDayColor = clr(121, 133, 145); - blizzard.mSkySunsetColor = clr(108, 115, 121); - blizzard.mSkyNightColor = clr(27, 29, 31); - blizzard.mFogSunriseColor = clr(91, 99, 106); - blizzard.mFogDayColor = clr(121, 133, 145); - blizzard.mFogSunsetColor = clr(108, 115, 121); - blizzard.mFogNightColor = clr(21, 24, 28); - blizzard.mAmbientSunriseColor = clr(84, 88, 92); - blizzard.mAmbientDayColor = clr(93, 96, 105); - blizzard.mAmbientSunsetColor = clr(83, 77, 75); - blizzard.mAmbientNightColor = clr(53, 62, 70); - blizzard.mSunSunriseColor = clr(114, 128, 146); - blizzard.mSunDayColor = clr(163, 169, 183); - blizzard.mSunSunsetColor = clr(106, 114, 136); - blizzard.mSunNightColor = clr(57, 66, 74); - blizzard.mSunDiscSunsetColor = clr(128, 128, 128); - blizzard.mLandFogDayDepth = 2.8; - blizzard.mLandFogNightDepth = 3.0; - blizzard.mWindSpeed = 0.9; - blizzard.mCloudSpeed = 7.5; - blizzard.mGlareView = 0; blizzard.mAmbientLoopSoundID = "BM Blizzard"; - mWeatherSettings["blizzard"] = blizzard; - */ + setFallbackWeather(blizzard,"blizzard"); } void WeatherManager::setWeather(const String& weather, bool instant) @@ -263,10 +193,10 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = 6-mHour; float factor = advance / 0.5f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor); + result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); result.mNightFade = factor; } else //if (mHour >= 6) @@ -274,10 +204,10 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade out float advance = mHour-6; float factor = advance / 3.f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor); + result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); } } @@ -298,20 +228,20 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = 19-mHour; float factor = (advance / 2); - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor); + result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); } else //if (mHour >= 19) { // fade out float advance = mHour-19; float factor = advance / 2.f; - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor); + result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); result.mNightFade = factor; } } @@ -329,19 +259,19 @@ WeatherResult WeatherManager::transition(float factor) result.mNextCloudTexture = other.mCloudTexture; result.mCloudBlendFactor = factor; - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); - result.mFogColor = lerp(current.mFogColor, other.mFogColor); - result.mSunColor = lerp(current.mSunColor, other.mSunColor); - result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor); + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + result.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + result.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor); - result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); - result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); - result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); - result.mGlareView = lerp(current.mGlareView, other.mGlareView); - result.mNightFade = lerp(current.mNightFade, other.mNightFade); + result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + result.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + result.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); result.mNight = current.mNight; @@ -365,7 +295,7 @@ void WeatherManager::update(float duration) if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { mCurrentRegion = regionstr; - mWeatherUpdateTime = mWeatherUpdateTime*3600; + mWeatherUpdateTime = mHoursBetweenWeatherChanges*3600; std::string weather = "clear"; @@ -387,19 +317,19 @@ void WeatherManager::update(float duration) float thunder = region->mData.mThunder/255.f; float ash = region->mData.mAsh/255.f; float blight = region->mData.mBlight/255.f; - //float snow = region->mData.a/255.f; - //float blizzard = region->mData.b/255.f; + float snow = region->mData.mA/255.f; + float blizzard = region->mData.mB/255.f; // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; float random = ((rand()%100)/100.f) * total; - //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "blizzard"; - //else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "snow"; - /*else*/ if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) + if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "blizzard"; + else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "snow"; + else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) weather = "blight"; else if (random >= thunder+rain+overcast+foggy+cloudy+clear) weather = "ashstorm"; @@ -495,34 +425,53 @@ void WeatherManager::update(float duration) mRendering->getSkyManager()->masserEnable(); mRendering->getSkyManager()->secundaEnable(); - float hour_fade; - if (mHour >= 7.f && mHour <= 14.f) - hour_fade = 1-(mHour-7)/3.f; - else if (mHour >= 14 && mHour <= 15.f) - hour_fade = mHour-14; - else - hour_fade = 1; + float secunda_hour_fade; + float secunda_fadeout_start=mFallback->getFallbackFloat("Moons_Secunda_Fade_Out_Start"); + float secunda_fadein_start=mFallback->getFallbackFloat("Moons_Secunda_Fade_In_Start"); + float secunda_fadein_finish=mFallback->getFallbackFloat("Moons_Secunda_Fade_In_Finish"); + + if (mHour >= secunda_fadeout_start && mHour <= secunda_fadein_start) + secunda_hour_fade = 1-(mHour-secunda_fadeout_start)/3.f; + else if (mHour >= secunda_fadein_start && mHour <= secunda_fadein_finish) + secunda_hour_fade = mHour-secunda_fadein_start; + else + secunda_hour_fade = 1; + + float masser_hour_fade; + float masser_fadeout_start=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Start"); + float masser_fadein_start=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); + float masser_fadein_finish=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Finish"); + if (mHour >= masser_fadeout_start && mHour <= masser_fadein_start) + masser_hour_fade = 1-(mHour-masser_fadeout_start)/3.f; + else if (mHour >= masser_fadein_start && mHour <= masser_fadein_finish) + masser_hour_fade = mHour-masser_fadein_start; + else + masser_hour_fade = 1; - float secunda_angle_fade; - float masser_angle_fade; float angle = moonHeight*90.f; - if (angle >= 30 && angle <= 50) - secunda_angle_fade = (angle-30)/20.f; - else if (angle <30) + float secunda_angle_fade; + float secunda_end_angle=mFallback->getFallbackFloat("Moons_Secunda_Fade_End_Angle"); + float secunda_start_angle=mFallback->getFallbackFloat("Moons_Secunda_Fade_Start_Angle"); + if (angle >= secunda_end_angle && angle <= secunda_start_angle) + secunda_angle_fade = (angle-secunda_end_angle)/20.f; + else if (angle < secunda_end_angle) secunda_angle_fade = 0.f; else secunda_angle_fade = 1.f; - if (angle >= 40 && angle <= 50) - masser_angle_fade = (angle-40)/10.f; - else if (angle <40) + float masser_angle_fade; + float masser_end_angle=mFallback->getFallbackFloat("Moons_Masser_Fade_End_Angle"); + float masser_start_angle=mFallback->getFallbackFloat("Moons_Masser_Fade_Start_Angle"); + if (angle >= masser_end_angle && angle <= masser_start_angle) + masser_angle_fade = (angle-masser_end_angle)/10.f; + else if (angle < masser_end_angle) masser_angle_fade = 0.f; else masser_angle_fade = 1.f; - masser_angle_fade *= hour_fade; - secunda_angle_fade *= hour_fade; + masser_angle_fade *= masser_hour_fade; + secunda_angle_fade *= secunda_hour_fade; mRendering->getSkyManager()->setMasserFade(masser_angle_fade); mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index b5bd0e10a0..f8c85b1fe7 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -11,6 +11,8 @@ namespace MWRender namespace MWWorld { + class Fallback; + /// Defines the actual weather that results from weather setting (see below), time of day and weather transition struct WeatherResult { @@ -112,7 +114,7 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*,const std::map& fallbackMap); + WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); /** * Change the weather in the specified region @@ -141,11 +143,7 @@ namespace MWWorld private: float mHour; int mDay, mMonth; - std::map mFallback; - std::string getFallback (const std::string& key) const; - std::string getFallbackString(const std::string& fall) const; - float getFallbackFloat(const std::string& fall) const; - Ogre::ColourValue getFallbackColour(const std::string& fall) const; + MWWorld::Fallback* mFallback; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; @@ -179,6 +177,7 @@ namespace MWWorld float mSunriseDuration; float mSunsetDuration; float mWeatherUpdateTime; + float mHoursBetweenWeatherChanges; float mThunderFrequency; float mThunderThreshold; float mThunderSoundDelay; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a933713dd7..5d6863c029 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -101,7 +101,7 @@ namespace MWWorld return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLights)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mMiscItems)) return Ptr (ref, &cell); @@ -154,26 +154,6 @@ namespace MWWorld mRendering->skyDisable(); } - void World::setFallbackValues (const std::map& fallbackMap) - { - mFallback = fallbackMap; - } - - std::string World::getFallback (const std::string& key) const - { - return getFallback(key, ""); - } - - std::string World::getFallback (const std::string& key, const std::string& def) const - { - std::map::const_iterator it; - if((it = mFallback.find(key)) == mFallback.end()) - { - return def; - } - return it->second; - } - World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, @@ -181,17 +161,16 @@ namespace MWWorld ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride), - mFallback (fallbackMap) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride),mFallback(fallbackMap) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); - mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); + mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,fallbackMap); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); int idx = 0; // NOTE: We might need to reserve one more for the running game / save. @@ -283,6 +262,11 @@ namespace MWWorld return 0; } + const MWWorld::Fallback *World::getFallback() const + { + return &mFallback; + } + Ptr::CellStore *World::getExterior (int x, int y) { return mCells.getExterior (x, y); @@ -687,10 +671,11 @@ namespace MWWorld return MWWorld::Ptr (); MWWorld::Ptr object = searchPtrViaHandle (result.second); - float ActivationDistance; - if (object.getTypeName ().find("NPC") != std::string::npos) + if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + ActivationDistance = getObjectActivationDistance ()*50; + else if (object.getTypeName ().find("NPC") != std::string::npos) ActivationDistance = getNpcActivationDistance (); else ActivationDistance = getObjectActivationDistance (); @@ -1026,6 +1011,8 @@ namespace MWWorld float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()); + if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50); } else { @@ -1275,7 +1262,7 @@ namespace MWWorld World::isFlying(const MWWorld::Ptr &ptr) const { const MWWorld::Class &cls = MWWorld::Class::get(ptr); - if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Levitate)).mMagnitude > 0) return true; return false; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e06b89f600..24565029fc 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -10,6 +10,7 @@ #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" +#include "fallback.hpp" #include "../mwbase/world.hpp" @@ -49,6 +50,7 @@ namespace MWWorld class World : public MWBase::World { + MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; MWWorld::WeatherManager* mWeatherManager; @@ -82,7 +84,6 @@ namespace MWWorld float mFaced1Distance; float mFaced2Distance; int mNumFacing; - std::map mFallback; unsigned long lastTick; Ogre::Timer mTimer; @@ -132,11 +133,7 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual void setFallbackValues (const std::map& fallbackMap); - - virtual std::string getFallback (const std::string& key) const; - - virtual std::string getFallback (const std::string& key, const std::string& def) const; + virtual const Fallback *getFallback() const; virtual Player& getPlayer(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f7b97056cb..88bf764445 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (file_finder add_component_dir (esm attr defs esmcommon esmreader esmwriter 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 + loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 ) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 027f3de712..94240c5eb9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -603,8 +603,8 @@ namespace Compiler switch (code) { - case Scanner::S_plus: pushBinaryOperator ('+'); return true; - case Scanner::S_minus: pushBinaryOperator ('-'); return true; + case Scanner::S_plus: c = '+'; break; + case Scanner::S_minus: c = '-'; break; case Scanner::S_mult: pushBinaryOperator ('*'); return true; case Scanner::S_div: pushBinaryOperator ('/'); return true; case Scanner::S_cmpEQ: c = 'e'; break; diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ac0ee63f1c..5b3d244b0d 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -2,6 +2,8 @@ #include "scriptparser.hpp" #include "scanner.hpp" +#include "skipparser.hpp" +#include "errorhandler.hpp" namespace Compiler { @@ -41,6 +43,17 @@ namespace Compiler return true; } + /// \todo add an option to disable this nonsense + if (keyword==Scanner::K_endif) + { + // surplus endif + getErrorHandler().warning ("endif without matching if/elseif", loc); + + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; + } + if (keyword==Scanner::K_end && mEnd) { return false; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index da60f76af8..0731a8ff80 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -14,7 +14,7 @@ namespace ESM { -/// Some overloaded copare operators. +/// Some overloaded compare operators. bool operator==(const MovedCellRef& ref, int pRefnum) { return (ref.mRefnum == pRefnum); @@ -43,13 +43,9 @@ void CellRef::save(ESMWriter &esm) esm.writeHNT("INDX", mFactIndex); } - if (mCharge != -1.0) { - esm.writeHNT("XCHG", mCharge); - } + if (mCharge != -1) + esm.writeHNT("INTV", mCharge); - if (mIntv != -1) { - esm.writeHNT("INTV", mIntv); - } if (mNam9 != 0) { esm.writeHNT("NAM9", mNam9); } @@ -285,12 +281,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mFactIndex = -2; esm.getHNOT(ref.mFactIndex, "INDX"); - ref.mCharge = -1.0; - esm.getHNOT(ref.mCharge, "XCHG"); - - ref.mIntv = -1; ref.mNam9 = 0; - esm.getHNOT(ref.mIntv, "INTV"); + ref.mCharge = -1; + esm.getHNOT(ref.mCharge, "INTV"); esm.getHNOT(ref.mNam9, "NAM9"); // Present for doors that teleport you to another cell. diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 7db6dbe77c..97aa86ba0f 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -52,15 +52,11 @@ public: // is -1, which I assume means "any rank". int mFactIndex; - // Depends on context - possibly weapon health, number of uses left - // or weapon magic charge? - float mCharge; + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int mCharge; - // I have no idea, these are present some times, often along with - // owner (ANAM) and sometimes otherwise. They are often (but not - // always) 1. INTV is big for lights (possibly a float?), might have - // something to do with remaining light "charge". - int mIntv, mNam9; + int mNam9; // For doors - true if this door teleports to somewhere else, false // if it should open through animation. diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp new file mode 100644 index 0000000000..02a36abfe6 --- /dev/null +++ b/components/esm/loadlock.cpp @@ -0,0 +1,31 @@ +#include "loadlock.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Lockpick::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "LKDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Lockpick::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + + +} diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp new file mode 100644 index 0000000000..0bbedf362f --- /dev/null +++ b/components/esm/loadlock.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_LOCK_H +#define OPENMW_ESM_LOCK_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Lockpick +{ + struct Data + { + float mWeight; + int mValue; + + float mQuality; + int mUses; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp deleted file mode 100644 index 057da595e7..0000000000 --- a/components/esm/loadlocks.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "loadlocks.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -namespace ESM -{ - -void Tool::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); - - esm.getSubName(); - NAME n = esm.retSubName(); - // The data name varies, RIDT for repair items, LKDT for lock - // picks, PBDT for probes - - esm.getHT(mData, 16); - - if (n == "RIDT") - { - mType = Type_Repair; - // Swap t.data.quality and t.data.uses for repair items (sigh) - float tmp = *((float*) &mData.mUses); - mData.mUses = *((int*) &mData.mQuality); - mData.mQuality = tmp; - } - else if (n == "LKDT") - mType = Type_Pick; - else if (n == "PBDT") - mType = Type_Probe; - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Tool::save(ESMWriter &esm) -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); - - std::string typeName; - switch(mType) - { - case Type_Repair: typeName = "RIDT"; break; - case Type_Pick: typeName = "LKDT"; break; - case Type_Probe: typeName = "PBDT"; break; - } - - Data write = mData; - if (mType == Type_Repair) - { - float tmp = *((float*) &write.mUses); - write.mUses = *((int*) &write.mQuality); - write.mQuality = tmp; - } - - esm.writeHNT(typeName, write, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} - - -} diff --git a/components/esm/loadlocks.hpp b/components/esm/loadlocks.hpp deleted file mode 100644 index 8e88c548e7..0000000000 --- a/components/esm/loadlocks.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef OPENMW_ESM_LOCKS_H -#define OPENMW_ESM_LOCKS_H - -#include - -namespace ESM -{ - -class ESMReader; -class ESMWriter; - -/* - * This file covers lockpicks (LOCK), probes (PROB) and armor repair - * items (REPA). These have nearly identical data structures. - */ - -struct Tool -{ - enum Type - { - Type_Pick, - Type_Probe, - Type_Repair - }; - - struct Data - { - float mWeight; - int mValue; - - float mQuality; // And when I say nearly identical structure, I - int mUses; // mean perfectly identical except that these two - // variables are swaped for repair items. Don't ask - // me why. - }; // Size = 16 - - Data mData; - Type mType; - std::string mId, mName, mModel, mIcon, mScript; - - void load(ESMReader &esm); - void save(ESMWriter &esm); -}; - -struct Probe: Tool -{ - Probe() { mType = Type_Probe; } -}; - -struct Repair: Tool -{ - Repair() { mType = Type_Repair; } -}; - -} -#endif diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 93c59f9cbe..7efc17aec5 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -66,6 +66,158 @@ struct MagicEffect void load(ESMReader &esm); void save(ESMWriter &esm); + + + enum Effects + { + WaterBreathing = 0, + SwiftSwim = 1, + WaterWalking = 2, + Shield = 3, + FireShield = 4, + LightningShield = 5, + FrostShield = 6, + Burden = 7, + Feather = 8, + Jump = 9, + Levitate = 10, + SlowFall = 11, + Lock = 12, + Open = 13, + FireDamage = 14, + ShockDamage = 15, + FrostDamage = 16, + DrainAttribute = 17, + DrainHealth = 18, + DrainMagicka = 19, + DrainFatigue = 20, + DrainSkill = 21, + DamageAttribute = 22, + DamageHealth = 23, + DamageMagicka = 24, + DamageFatigue = 25, + DamageSkill = 26, + Poison = 27, + WeaknessToFire = 28, + WeaknessToFrost = 29, + WeaknessToShock = 30, + WeaknessToMagicka = 31, + WeaknessToCommonDisease = 32, + WeaknessToBlightDisease = 33, + WeaknessToCorprusDisease = 34, + WeaknessToPoison = 35, + WeaknessToNormalWeapons = 36, + DisintegrateWeapon = 37, + DisintegrateArmor = 38, + Invisibility = 39, + Chameleon = 40, + Light = 41, + Sanctuary = 42, + NightEye = 43, + Charm = 44, + Paralyze = 45, + Silence = 46, + Blind = 47, + Sound = 48, + CalmHumanoid = 49, + CalmCreature = 50, + FrenzyHumanoid = 51, + FrenzyCreature = 52, + DemoralizeHumanoid = 53, + DemoralizeCreature = 54, + RallyHumanoid = 55, + RallyCreature = 56, + Dispel = 57, + Soultrap = 58, + Telekinesis = 59, + Mark = 60, + Recall = 61, + DivineIntervention = 62, + AlmsiviIntervention = 63, + DetectAnimal = 64, + DetectEnchantment = 65, + DetectKey = 66, + SpellAbsorption = 67, + Reflect = 68, + CureCommonDisease = 69, + CureBlightDisease = 70, + CureCorprusDisease = 71, + CurePoison = 72, + CureParalyzation = 73, + RestoreAttribute = 74, + RestoreHealth = 75, + RestoreMagicka = 76, + RestoreFatigue = 77, + RestoreSkill = 78, + FortifyAttribute = 79, + FortifyHealth = 80, + FortifyMagicka= 81, + FortifyFatigue = 82, + FortifySkill = 83, + FortifyMaximumMagicka = 84, + AbsorbAttribute = 85, + AbsorbHealth = 86, + AbsorbMagicka = 87, + AbsorbFatigue = 88, + AbsorbSkill = 89, + ResistFire = 90, + ResistFrost = 91, + ResistShock = 92, + ResistMagicka = 93, + ResistCommonDisease = 94, + ResistBlightDisease = 95, + ResistCorprusDisease = 96, + ResistPoison = 97, + ResistNormalWeapons = 98, + ResistParalysis = 99, + RemoveCurse = 100, + TurnUndead = 101, + SummonScamp = 102, + SummonClannfear = 103, + SummonDaedroth = 104, + SummonDremora = 105, + SummonAncestralGhost = 106, + SummonSkeletalMinion = 107, + SummonBonewalker = 108, + SummonGreaterBonewalker = 109, + SummonBonelord = 110, + SummonWingedTwilight = 111, + SummonHunger = 112, + SummonGoldenSaint = 113, + SummonFlameAtronach = 114, + SummonFrostAtronach = 115, + SummonStormAtronach = 116, + FortifyAttack = 117, + CommandCreature = 118, + CommandHumanoid = 119, + BoundDagger = 120, + BoundLongsword = 121, + BoundMace = 122, + BoundBattleAxe = 123, + BoundSpear = 124, + BoundLongbow = 125, + ExtraSpell = 126, + BoundCuirass = 127, + BoundHelm = 128, + BoundBoots = 129, + BoundShield = 130, + BoundGloves = 131, + Corprus = 132, + Vampirism = 133, + SummonCenturionSphere = 134, + SunDamage = 135, + StuntedMagicka = 136, + + // Tribunal only + SummonFabricant = 137, + + // Bloodmoon only + SummonWolf = 138, + SummonBear = 139, + SummonBonewolf = 140, + SummonCreature04 = 141, + SummonCreature05 = 142 + }; }; } #endif diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp new file mode 100644 index 0000000000..bbaec1ce2d --- /dev/null +++ b/components/esm/loadprob.cpp @@ -0,0 +1,30 @@ +#include "loadprob.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Probe::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "PBDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Probe::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + +} diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp new file mode 100644 index 0000000000..4a47a86005 --- /dev/null +++ b/components/esm/loadprob.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_PROBE_H +#define OPENMW_ESM_PROBE_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Probe +{ + struct Data + { + float mWeight; + int mValue; + + float mQuality; + int mUses; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp new file mode 100644 index 0000000000..f7eeddf961 --- /dev/null +++ b/components/esm/loadrepa.cpp @@ -0,0 +1,31 @@ +#include "loadrepa.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Repair::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "RIDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Repair::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("RIDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + + +} diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp new file mode 100644 index 0000000000..60ff5df905 --- /dev/null +++ b/components/esm/loadrepa.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_REPA_H +#define OPENMW_ESM_REPA_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Repair +{ + struct Data + { + float mWeight; + int mValue; + + int mUses; + float mQuality; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index a4d21c5912..b9d588eef4 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -1,5 +1,7 @@ #include "loadskil.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -98,6 +100,10 @@ void Skill::load(ESMReader &esm) esm.getHNT(mIndex, "INDX"); esm.getHNT(mData, "SKDT", 24); mDescription = esm.getHNOString("DESC"); + + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + mId = getIndexToId (mIndex); } void Skill::save(ESMWriter &esm) { @@ -105,4 +111,29 @@ void Skill::save(ESMWriter &esm) esm.writeHNT("SKDT", mData, 24); esm.writeHNOString("DESC", mDescription); } + + void Skill::blank() + { + mData.mAttribute = 0; + mData.mSpecialization = 0; + mData.mUseValue[0] = mData.mUseValue[1] = mData.mUseValue[2] = mData.mUseValue[3] = 1.0; + mDescription.clear(); + } + + std::string Skill::getIndexToId (int index) + { + std::ostringstream stream; + + stream << "#"; + + if (index<10) + stream << "0"; + + stream << index; + + if (index>=0 && indexgetString() << "\2"; + stream << "variant string: \"" << mData->getString() << "\""; break; } } diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 824fbd565e..9f2e470b26 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -237,10 +239,6 @@ bool lessThanDate(const EsmFile *e1, const EsmFile *e2) } else { return false; } -// if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) -// return false; - -// return e1->fileName().toLower() < e2->fileName().toLower(); } void DataFilesModel::sort(int column, Qt::SortOrder order) @@ -270,18 +268,33 @@ void DataFilesModel::addFiles(const QString &path) filters << "*.esp" << "*.esm"; dir.setNameFilters(filters); + // Create a decoder for non-latin characters in esx metadata + QTextCodec *codec; + + if (mEncoding == QLatin1String("win1252")) { + codec = QTextCodec::codecForName("windows-1252"); + } else if (mEncoding == QLatin1String("win1251")) { + codec = QTextCodec::codecForName("windows-1251"); + } else if (mEncoding == QLatin1String("win1250")) { + codec = QTextCodec::codecForName("windows-1250"); + } else { + return; // This should never happen; + } + + QTextDecoder *decoder = codec->makeDecoder(); + foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); EsmFile *file = new EsmFile(path); - try { ESM::ESMReader fileReader; - ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); + ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding.toStdString())); fileReader.setEncoder(&encoder); fileReader.open(dir.absoluteFilePath(path).toStdString()); std::vector mlist = fileReader.getMasters(); + QStringList masters; for (unsigned int i = 0; i < mlist.size(); ++i) { @@ -289,13 +302,13 @@ void DataFilesModel::addFiles(const QString &path) masters.append(master); } - file->setAuthor(QString::fromStdString(fileReader.getAuthor())); + file->setAuthor(decoder->toUnicode(fileReader.getAuthor().c_str())); file->setSize(info.size()); file->setDates(info.lastModified(), info.lastRead()); file->setVersion(fileReader.getFVer()); file->setPath(info.absoluteFilePath()); file->setMasters(masters); - file->setDescription(QString::fromStdString(fileReader.getDesc())); + file->setDescription(decoder->toUnicode(fileReader.getDesc().c_str())); // Put the file in the table @@ -308,6 +321,8 @@ void DataFilesModel::addFiles(const QString &path) } } + + delete decoder; } QModelIndex DataFilesModel::indexFromItem(EsmFile *item) const diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 04ac3d1410..08625ee9cb 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -112,7 +112,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) cShape->mHasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(mesh1, node,0,false,false); + handleNode(mesh1, node,0,false,false,false); if(mBoundingBox != NULL) { @@ -136,7 +136,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) btTriangleMesh* mesh2 = new btTriangleMesh(); - handleNode(mesh2, node,0,true,true); + handleNode(mesh2, node,0,true,true,false); if(mBoundingBox != NULL) { @@ -175,7 +175,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, bool isCollisionNode, - bool raycasting) + bool raycasting, bool isMarker) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -186,14 +186,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * else isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); - // Marker objects: no collision + // Marker objects /// \todo don't do this in the editor std::string nodename = node->name; Misc::StringUtils::toLower(nodename); if (nodename.find("marker") != std::string::npos) - { - return; - } + isMarker = true; // Check for extra data Nif::Extra const *e = node; @@ -219,11 +217,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * // Marker objects. These are only visible in the // editor. Until and unless we add an editor component to // the engine, just skip this entire node. - return; + isMarker = true; } } - if (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) + if ( (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) + && (!isMarker || (cShape->mHasCollisionNode && !raycasting))) { if(node->hasBounds) { @@ -246,7 +245,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting); + handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index c231b75b68..7958f3b7cb 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -82,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting, bool isMarker); /** *Helper function diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 30c71023bc..5aa5ff80cb 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -743,8 +743,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String blend_mode += getBlendFactor((alphaFlags>>5)&0xf); instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); if((alphaFlags>>9)&1) { @@ -754,9 +752,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String reject += Ogre::StringConverter::toString(alphaTest); instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } + else + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "force" : "off"))); + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( + ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); @@ -1113,7 +1114,7 @@ public: { // Marker objects. These are only visible in the // editor. - flags |= 0x01; + return; } } e = e->extra; diff --git a/files/launcher/launcher.rc b/files/launcher/launcher.rc new file mode 100644 index 0000000000..df2121f469 --- /dev/null +++ b/files/launcher/launcher.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "images/openmw.ico" diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader index 50d375efe4..ec8ae4174a 100644 --- a/files/materials/watersim_heightmap.shader +++ b/files/materials/watersim_heightmap.shader @@ -14,12 +14,21 @@ SH_START_PROGRAM { +#if !SH_HLSL const float3 offset[4] = float3[4]( float3(-1.0, 0.0, 0.25), float3( 1.0, 0.0, 0.25), float3( 0.0,-1.0, 0.25), float3( 0.0, 1.0, 0.25) ); +#else + const float3 offset[4] = { + float3(-1.0, 0.0, 0.25), + float3( 1.0, 0.0, 0.25), + float3( 0.0,-1.0, 0.25), + float3( 0.0, 1.0, 0.25) + }; +#endif float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader index 5402b6bb5e..eaa4af4983 100644 --- a/files/materials/watersim_heighttonormal.shader +++ b/files/materials/watersim_heighttonormal.shader @@ -8,12 +8,21 @@ SH_START_PROGRAM { - float2 offset[4] = float2[4] ( - vec2(-1.0, 0.0), - vec2( 1.0, 0.0), - vec2( 0.0,-1.0), - vec2( 0.0, 1.0) - ); +#if !SH_HLSL + float2 offset[4] = float2[4] ( + float2(-1.0, 0.0), + float2( 1.0, 0.0), + float2( 0.0,-1.0), + float2( 0.0, 1.0) + ); +#else + float2 offset[4] = { + float2(-1.0, 0.0), + float2( 1.0, 0.0), + float2( 0.0,-1.0), + float2( 0.0, 1.0) + }; +#endif float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index beace5b81e..7da28f0bfa 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -78,6 +78,8 @@ set(MYGUI_FILES openmw_trainingwindow.layout openmw_travel_window.layout openmw_persuasion_dialog.layout + openmw_merchantrepair.layout + openmw_repair.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 88cc5638d3..41bd40f923 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -17,7 +17,6 @@ - diff --git a/files/mygui/openmw_merchantrepair.layout b/files/mygui/openmw_merchantrepair.layout new file mode 100644 index 0000000000..360f5f4f09 --- /dev/null +++ b/files/mygui/openmw_merchantrepair.layout @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout new file mode 100644 index 0000000000..2881a5853a --- /dev/null +++ b/files/mygui/openmw_repair.layout @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_spell_buying_window.layout b/files/mygui/openmw_spell_buying_window.layout index 1e18fda236..c55cd0e22d 100644 --- a/files/mygui/openmw_spell_buying_window.layout +++ b/files/mygui/openmw_spell_buying_window.layout @@ -5,13 +5,13 @@ - - + + - - - + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 13b22ff93d..71e86091c8 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -154,8 +154,8 @@ - - + + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index f554e2b0d5..7291f2ca21 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -7,7 +7,17 @@ - + + + + + + + + + + + @@ -106,12 +116,14 @@ - + + - + + @@ -147,10 +159,12 @@ + - + + @@ -200,17 +214,23 @@ + + - + + - + + + + diff --git a/files/ui/mainwindow.ui b/files/ui/mainwindow.ui index 8143fa24df..a1dfb172b2 100644 --- a/files/ui/mainwindow.ui +++ b/files/ui/mainwindow.ui @@ -5,7 +5,7 @@ 575 - 525 + 535 diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index 6b8b66b208..c0320de1eb 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -19,6 +19,9 @@ QFrame::Plain + + 0 + 30 @@ -40,10 +43,14 @@ border-color: rgba(0, 0, 0, 125); border-style: solid; border-radius: 2px; + + font-size: 12pt; + font-family: "EB Garamond", "EB Garamond 08"; + color: black; } /*QComboBox gets the "on" state when the popup is open */ -#profilesComboBox:!editable:on, #ProfilesComboBox::drop-down:editable:on { +#profilesComboBox:!editable:on { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(0, 0, 0, 75), stop:0.1 rgba(0, 0, 0, 15), @@ -52,13 +59,9 @@ border: 1px solid rgba(0, 0, 0, 55); } -#profilesComboBox { /* shift the text when the popup opens */ +#profilesComboBox:on { /* shift the text when the popup opens */ padding-top: 3px; padding-left: 4px; - - font-size: 12pt; - font-family: "EB Garamond", "EB Garamond 08"; - color: black; } #profilesComboBox::drop-down { @@ -82,7 +85,6 @@ left: 1px; } - #profilesComboBox QAbstractItemView { border: 0px; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 6e6490a411..8de931bbf8 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -608,6 +608,14 @@ namespace Physic btTransform trans; trans.setIdentity(); - shape->mCollisionShape->getAabb(trans, min, max); + if (shape->mRaycastingShape) + shape->mRaycastingShape->getAabb(trans, min, max); + else if (shape->mCollisionShape) + shape->mCollisionShape->getAabb(trans, min, max); + else + { + min = btVector3(0,0,0); + max = btVector3(0,0,0); + } } }} diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index c4f35e0872..309ba8a060 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -229,15 +229,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& assert(mRoot); mRoot->initialise(false); - // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window - NameValuePairList params_; - params_.insert(std::make_pair("title", title)); - params_.insert(std::make_pair("FSAA", "0")); - params_.insert(std::make_pair("vsync", "false")); - params_.insert(std::make_pair("hidden", "true")); - Ogre::RenderWindow* hiddenWindow = mRoot->createRenderWindow("InactiveHidden", 1, 1, false, ¶ms_); - hiddenWindow->setActive(false); - NameValuePairList params; params.insert(std::make_pair("title", title)); params.insert(std::make_pair("FSAA", settings.fsaa)); diff --git a/readme.txt b/readme.txt index 228278a919..8edb0c4b31 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.21.0 +Version: 0.22.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -94,6 +94,82 @@ Allowed options: CHANGELOG +0.22.0 + +Bug #311: Potential infinite recursion in script compiler +Bug #355: Keyboard repeat rate (in Xorg) are left disabled after game exit. +Bug #382: Weird effect in 3rd person on water +Bug #387: Always use detailed shape for physics raycasts +Bug #420: Potion/ingredient effects do not stack +Bug #429: Parts of dwemer door not picked up correctly for activation/tooltips +Bug #434/Bug #605: Object movement between cells not properly implemented +Bug #502: Duplicate player collision model at origin +Bug #509: Dialogue topic list shifts inappropriately +Bug #513: Sliding stairs +Bug #515: Launcher does not support non-latin strings +Bug #525: Race selection preview camera wrong position +Bug #526: Attributes / skills should not go below zero +Bug #529: Class and Birthsign menus options should be preselected +Bug #530: Lock window button graphic missing +Bug #532: Missing map menu graphics +Bug #545: ESX selector does not list ESM files properly +Bug #547: Global variables of type short are read incorrectly +Bug #550: Invisible meshes collision and tooltip +Bug #551: Performance drop when loading multiple ESM files +Bug #552: Don't list CG in options if it is not available +Bug #555: Character creation windows "OK" button broken +Bug #558: Segmentation fault when Alt-tabbing with console opened +Bug #559: Dialog window should not be available before character creation is finished +Bug #560: Tooltip borders should be stretched +Bug #562: Sound should not be played when an object cannot be picked up +Bug #565: Water animation speed + timescale +Bug #572: Better Bodies' textures don't work +Bug #573: OpenMW doesn't load if TR_Mainland.esm is enabled (Tamriel Rebuilt mod) +Bug #574: Moving left/right should not cancel auto-run +Bug #575: Crash entering the Chamber of Song +Bug #576: Missing includes +Bug #577: Left Gloves Addon causes ESMReader exception +Bug #579: Unable to open container "Kvama Egg Sack" +Bug #581: Mimicking vanilla Morrowind water +Bug #583: Gender not recognized +Bug #586: Wrong char gen behaviour +Bug #587: "End" script statements with spaces don't work +Bug #589: Closing message boxes by pressing the activation key +Bug #590: Ugly Dagoth Ur rendering +Bug #591: Race selection issues +Bug #593: Persuasion response should be random +Bug #595: Footless guard +Bug #599: Waterfalls are invisible from a certain distance +Bug #600: Waterfalls rendered incorrectly, cut off by water +Bug #607: New beast bodies mod crashes +Bug #608: Crash in cell "Mournhold, Royal Palace" +Bug #611: OpenMW doesn't find some of textures used in Tamriel Rebuilt +Bug #613: Messagebox causing assert to fail +Bug #615: Meshes invisible from above water +Bug #617: Potion effects should be hidden until discovered +Bug #619: certain moss hanging from tree has rendering bug +Bug #621: Batching bloodmoon's trees +Bug #623: NiMaterialProperty alpha unhandled +Bug #628: Launcher in latest master crashes the game +Bug #633: Crash on startup: Better Heads +Bug #636: Incorrect Char Gen Menu Behavior +Feature #29: Allow ESPs and multiple ESMs +Feature #94: Finish class selection-dialogue +Feature #149: Texture Alphas +Feature #237: Run Morrowind-ini importer from launcher +Feature #286: Update Active Spell Icons +Feature #334: Swimming animation +Feature #335: Walking animation +Feature #360: Proper collision shapes for NPCs and creatures +Feature #367: Lights that behave more like original morrowind implementation +Feature #477: Special local scripting variables +Feature #528: Message boxes should close when enter is pressed under certain conditions. +Feature #543: Add bsa files to the settings imported by the ini importer +Feature #594: coordinate space and utility functions +Feature #625: Zoom in vanity mode +Task #464: Refactor launcher ESX selector into a re-usable component +Task #624: Unified implementation of type-variable sub-records + 0.21.0 Bug #253: Dialogs don't work for Russian version of Morrowind