diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f986e8dea..656299fec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Bug #7084: Resurrecting an actor doesn't take into account base record changes Bug #7088: Deleting last save game of last character doesn't clear character name/details Bug #7092: BSA archives from higher priority directories don't take priority + Bug #7103: Multiple paths pointing to the same plugin but with different cases lead to automatically removed config entries Bug #7122: Teleportation to underwater should cancel active water walking effect Bug #7131: MyGUI log spam when post processing HUD is open Bug #7134: Saves with an invalid last generated RefNum can be loaded @@ -99,6 +100,7 @@ Bug #7604: Goblins Grunt becomes idle once injured Bug #7609: ForceGreeting should not open dialogue for werewolves Bug #7611: Beast races' idle animations slide after turning or jumping in place + Bug #7617: The death prompt asks the player if they wanted to load the character's last created save Bug #7619: Long map notes may get cut off Bug #7630: Charm can be cast on creatures Bug #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing @@ -121,8 +123,10 @@ Bug #7712: Casting doesn't support spells and enchantments with no effects Bug #7723: Assaulting vampires and werewolves shouldn't be a crime Bug #7724: Guards don't help vs werewolves + Bug #7733: Launcher shows incorrect data paths when there's two plugins with the same name Bug #7742: Governing attribute training limit should use the modified attribute Bug #7758: Water walking is not taken into account to compute path cost on the water + Bug #7761: Rain and ambient loop sounds are mutually exclusive Feature #2566: Handle NAM9 records for manual cell references Feature #3537: Shader-based water ripples Feature #5173: Support for NiFogProperty diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index e340d501ed..dd54030dfb 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -19,9 +19,8 @@ command -v cmake >/dev/null 2>&1 || brew install cmake command -v qmake >/dev/null 2>&1 || brew install qt@5 export PATH="/opt/homebrew/opt/qt@5/bin:$PATH" - # Install deps -brew install icu4c yaml-cpp sqlite +brew install openal-soft icu4c yaml-cpp sqlite ccache --version cmake --version diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index c956f27514..cab67b6e4d 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -10,12 +10,13 @@ DEPENDENCIES_ROOT="/tmp/openmw-deps" QT_PATH=$(brew --prefix qt@5) ICU_PATH=$(brew --prefix icu4c) +OPENAL_PATH=$(brew --prefix openal-soft) CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache mkdir build cd build cmake \ --D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \ +-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH;$OPENAL_PATH" \ -D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \ -D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \ -D CMAKE_CXX_FLAGS="-stdlib=libc++" \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 34df0216da..28109bd01b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ IF(NOT CMAKE_BUILD_TYPE) ENDIF() if (APPLE) + set(CMAKE_FIND_FRAMEWORK LAST) # prefer dylibs over frameworks set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index dc2c07d9bd..114221ce92 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -125,27 +125,6 @@ namespace Launcher { return Settings::navigator().mMaxNavmeshdbFileSize / (1024 * 1024); } - - std::optional findFirstPath(const QStringList& directories, const QString& fileName) - { - for (const QString& directoryPath : directories) - { - const QString filePath = QDir(directoryPath).absoluteFilePath(fileName); - if (QFile::exists(filePath)) - return filePath; - } - return std::nullopt; - } - - QStringList findAllFilePaths(const QStringList& directories, const QStringList& fileNames) - { - QStringList result; - result.reserve(fileNames.size()); - for (const QString& fileName : fileNames) - if (const auto filepath = findFirstPath(directories, fileName)) - result.append(*filepath); - return result; - } } } @@ -366,8 +345,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName) row++; } - mSelector->setProfileContent( - findAllFilePaths(directories, mLauncherSettings.getContentListFiles(contentModelName))); + mSelector->setProfileContent(mLauncherSettings.getContentListFiles(contentModelName)); } void Launcher::DataFilesPage::saveSettings(const QString& profile) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index fa9d5eb479..b360c215e6 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -154,7 +154,7 @@ bool Launcher::GraphicsPage::loadSettings() if (Settings::shadows().mEnableIndoorShadows) indoorShadowsCheckBox->setCheckState(Qt::Checked); - auto boundMethod = Settings::shadows().mComputeSceneBounds.get(); + const auto& boundMethod = Settings::shadows().mComputeSceneBounds.get(); if (boundMethod == "bounds") shadowComputeSceneBoundsComboBox->setCurrentIndex(0); else if (boundMethod == "primitives") diff --git a/apps/launcher/utils/openalutil.cpp b/apps/launcher/utils/openalutil.cpp index 1a332e9788..9a9ae9981b 100644 --- a/apps/launcher/utils/openalutil.cpp +++ b/apps/launcher/utils/openalutil.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include "apps/openmw/mwsound/alext.h" #include "openalutil.hpp" diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 70efd06090..610c5157aa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -1,5 +1,4 @@ set (OPENCS_SRC - ${CMAKE_SOURCE_DIR}/files/windows/opencs.rc ) opencs_units (. editor) @@ -146,6 +145,9 @@ source_group (openmw-cs FILES main.cpp ${OPENCS_SRC} ${OPENCS_HDR}) if(WIN32) set(QT_USE_QTMAIN TRUE) + set(OPENCS_RC_FILE ${CMAKE_SOURCE_DIR}/files/windows/opencs.rc) +else(WIN32) + set(OPENCS_RC_FILE "") endif(WIN32) if (QT_VERSION_MAJOR VERSION_EQUAL 5) @@ -186,6 +188,7 @@ if(BUILD_OPENCS) ${OPENCS_CFG} ${OPENCS_DEFAULT_FILTERS_FILE} ${OPENCS_OPENMW_CFG} + ${OPENCS_RC_FILE} main.cpp ) diff --git a/apps/opencs/model/prefs/coloursetting.cpp b/apps/opencs/model/prefs/coloursetting.cpp index 9e237dd7a8..10ca9d7f68 100644 --- a/apps/opencs/model/prefs/coloursetting.cpp +++ b/apps/opencs/model/prefs/coloursetting.cpp @@ -14,7 +14,7 @@ #include "state.hpp" CSMPrefs::ColourSetting::ColourSetting( - Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index) + Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index) : TypedSetting(parent, mutex, key, label, index) , mWidget(nullptr) { diff --git a/apps/opencs/model/prefs/coloursetting.hpp b/apps/opencs/model/prefs/coloursetting.hpp index f5af627491..85e43f28bd 100644 --- a/apps/opencs/model/prefs/coloursetting.hpp +++ b/apps/opencs/model/prefs/coloursetting.hpp @@ -6,6 +6,7 @@ #include #include +#include #include class QMutex; @@ -30,7 +31,7 @@ namespace CSMPrefs public: explicit ColourSetting( - Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index); + Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index); ColourSetting& setTooltip(const std::string& tooltip); diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 3089281c91..d6686d31d9 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -43,7 +43,7 @@ namespace CSMPrefs mEventHandler->removeShortcut(shortcut); } - bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence) const + bool ShortcutManager::getSequence(std::string_view name, QKeySequence& sequence) const { SequenceMap::const_iterator item = mSequences.find(name); if (item != mSequences.end()) @@ -56,7 +56,7 @@ namespace CSMPrefs return false; } - void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence) + void ShortcutManager::setSequence(std::string_view name, const QKeySequence& sequence) { // Add to map/modify SequenceMap::iterator item = mSequences.find(name); diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index 87d2f2256c..0cfe3ad86a 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -28,8 +28,8 @@ namespace CSMPrefs /// The shortcut class will do this automatically void removeShortcut(Shortcut* shortcut); - bool getSequence(const std::string& name, QKeySequence& sequence) const; - void setSequence(const std::string& name, const QKeySequence& sequence); + bool getSequence(std::string_view name, QKeySequence& sequence) const; + void setSequence(std::string_view name, const QKeySequence& sequence); bool getModifier(const std::string& name, int& modifier) const; void setModifier(std::string_view name, int modifier); @@ -50,7 +50,7 @@ namespace CSMPrefs private: // Need a multimap in case multiple shortcuts share the same name typedef std::multimap> ShortcutMap; - typedef std::map SequenceMap; + typedef std::map> SequenceMap; typedef std::map> ModifierMap; typedef std::map NameMap; typedef std::map KeyMap; diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 33bb521290..bdaf3a0fda 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -19,7 +19,7 @@ namespace CSMPrefs { ShortcutSetting::ShortcutSetting( - Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index) + Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index) : TypedSetting(parent, mutex, key, label, index) , mButton(nullptr) , mEditorActive(false) diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp index 84857a9bc7..bcb7b89488 100644 --- a/apps/opencs/model/prefs/shortcutsetting.hpp +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -2,6 +2,7 @@ #define CSM_PREFS_SHORTCUTSETTING_H #include +#include #include #include @@ -24,7 +25,7 @@ namespace CSMPrefs public: explicit ShortcutSetting( - Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index); + Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index); SettingWidgets makeWidgets(QWidget* parent) override; diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index b05a4b7473..c11996a6ea 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -126,14 +126,14 @@ void CSMPrefs::State::declare() .setRange(0, 10000); declareInt(mValues->mScripts.mErrorHeight, "Initial height of the error panel").setRange(100, 10000); declareBool(mValues->mScripts.mHighlightOccurrences, "Highlight other occurrences of selected names"); - declareColour("colour-highlight", "Colour of highlighted occurrences", QColor("lightcyan")); - declareColour("colour-int", "Highlight Colour: Integer Literals", QColor("darkmagenta")); - declareColour("colour-float", "Highlight Colour: Float Literals", QColor("magenta")); - declareColour("colour-name", "Highlight Colour: Names", QColor("grey")); - declareColour("colour-keyword", "Highlight Colour: Keywords", QColor("red")); - declareColour("colour-special", "Highlight Colour: Special Characters", QColor("darkorange")); - declareColour("colour-comment", "Highlight Colour: Comments", QColor("green")); - declareColour("colour-id", "Highlight Colour: IDs", QColor("blue")); + declareColour(mValues->mScripts.mColourHighlight, "Colour of highlighted occurrences"); + declareColour(mValues->mScripts.mColourInt, "Highlight Colour: Integer Literals"); + declareColour(mValues->mScripts.mColourFloat, "Highlight Colour: Float Literals"); + declareColour(mValues->mScripts.mColourName, "Highlight Colour: Names"); + declareColour(mValues->mScripts.mColourKeyword, "Highlight Colour: Keywords"); + declareColour(mValues->mScripts.mColourSpecial, "Highlight Colour: Special Characters"); + declareColour(mValues->mScripts.mColourComment, "Highlight Colour: Comments"); + declareColour(mValues->mScripts.mColourId, "Highlight Colour: IDs"); declareCategory("General Input"); declareBool(mValues->mGeneralInput.mCycle, "Cyclic next/previous") @@ -185,18 +185,18 @@ void CSMPrefs::State::declare() .setRange(10, 10000); declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1); declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background"); - declareColour("scene-day-background-colour", "Day Background Colour", QColor(110, 120, 128, 255)); - declareColour("scene-day-gradient-colour", "Day Gradient Colour", QColor(47, 51, 51, 255)) + declareColour(mValues->mRendering.mSceneDayBackgroundColour, "Day Background Colour"); + declareColour(mValues->mRendering.mSceneDayGradientColour, "Day Gradient Colour") .setTooltip( "Sets the gradient color to use in conjunction with the day background color. Ignored if " "the gradient option is disabled."); - declareColour("scene-bright-background-colour", "Scene Bright Background Colour", QColor(79, 87, 92, 255)); - declareColour("scene-bright-gradient-colour", "Scene Bright Gradient Colour", QColor(47, 51, 51, 255)) + declareColour(mValues->mRendering.mSceneBrightBackgroundColour, "Scene Bright Background Colour"); + declareColour(mValues->mRendering.mSceneBrightGradientColour, "Scene Bright Gradient Colour") .setTooltip( "Sets the gradient color to use in conjunction with the bright background color. Ignored if " "the gradient option is disabled."); - declareColour("scene-night-background-colour", "Scene Night Background Colour", QColor(64, 77, 79, 255)); - declareColour("scene-night-gradient-colour", "Scene Night Gradient Colour", QColor(47, 51, 51, 255)) + declareColour(mValues->mRendering.mSceneNightBackgroundColour, "Scene Night Background Colour"); + declareColour(mValues->mRendering.mSceneNightGradientColour, "Scene Night Gradient Colour") .setTooltip( "Sets the gradient color to use in conjunction with the night background color. Ignored if " "the gradient option is disabled."); @@ -250,157 +250,154 @@ void CSMPrefs::State::declare() declareCategory("Key Bindings"); declareSubcategory("Document"); - declareShortcut("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N)); - declareShortcut("document-file-newaddon", "New Addon", QKeySequence()); - declareShortcut("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O)); - declareShortcut("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); - declareShortcut("document-help-help", "Help", QKeySequence(Qt::Key_F1)); - declareShortcut("document-help-tutorial", "Tutorial", QKeySequence()); - declareShortcut("document-file-verify", "Verify", QKeySequence()); - declareShortcut("document-file-merge", "Merge", QKeySequence()); - declareShortcut("document-file-errorlog", "Open Load Error Log", QKeySequence()); - declareShortcut("document-file-metadata", "Meta Data", QKeySequence()); - declareShortcut("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W)); - declareShortcut("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q)); - declareShortcut("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z)); - declareShortcut("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z)); - declareShortcut("document-edit-preferences", "Open Preferences", QKeySequence()); - declareShortcut("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F)); - declareShortcut("document-view-newview", "New View", QKeySequence()); - declareShortcut("document-view-statusbar", "Toggle Status Bar", QKeySequence()); - declareShortcut("document-view-filters", "Open Filter List", QKeySequence()); - declareShortcut("document-world-regions", "Open Region List", QKeySequence()); - declareShortcut("document-world-cells", "Open Cell List", QKeySequence()); - declareShortcut("document-world-referencables", "Open Object List", QKeySequence()); - declareShortcut("document-world-references", "Open Instance List", QKeySequence()); - declareShortcut("document-world-lands", "Open Lands List", QKeySequence()); - declareShortcut("document-world-landtextures", "Open Land Textures List", QKeySequence()); - declareShortcut("document-world-pathgrid", "Open Pathgrid List", QKeySequence()); - declareShortcut("document-world-regionmap", "Open Region Map", QKeySequence()); - declareShortcut("document-mechanics-globals", "Open Global List", QKeySequence()); - declareShortcut("document-mechanics-gamesettings", "Open Game Settings", QKeySequence()); - declareShortcut("document-mechanics-scripts", "Open Script List", QKeySequence()); - declareShortcut("document-mechanics-spells", "Open Spell List", QKeySequence()); - declareShortcut("document-mechanics-enchantments", "Open Enchantment List", QKeySequence()); - declareShortcut("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence()); - declareShortcut("document-mechanics-startscripts", "Open Start Script List", QKeySequence()); - declareShortcut("document-character-skills", "Open Skill List", QKeySequence()); - declareShortcut("document-character-classes", "Open Class List", QKeySequence()); - declareShortcut("document-character-factions", "Open Faction List", QKeySequence()); - declareShortcut("document-character-races", "Open Race List", QKeySequence()); - declareShortcut("document-character-birthsigns", "Open Birthsign List", QKeySequence()); - declareShortcut("document-character-topics", "Open Topic List", QKeySequence()); - declareShortcut("document-character-journals", "Open Journal List", QKeySequence()); - declareShortcut("document-character-topicinfos", "Open Topic Info List", QKeySequence()); - declareShortcut("document-character-journalinfos", "Open Journal Info List", QKeySequence()); - declareShortcut("document-character-bodyparts", "Open Body Part List", QKeySequence()); - declareShortcut("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5)); - declareShortcut("document-assets-sounds", "Open Sound Asset List", QKeySequence()); - declareShortcut("document-assets-soundgens", "Open Sound Generator List", QKeySequence()); - declareShortcut("document-assets-meshes", "Open Mesh Asset List", QKeySequence()); - declareShortcut("document-assets-icons", "Open Icon Asset List", QKeySequence()); - declareShortcut("document-assets-music", "Open Music Asset List", QKeySequence()); - declareShortcut("document-assets-soundres", "Open Sound File List", QKeySequence()); - declareShortcut("document-assets-textures", "Open Texture Asset List", QKeySequence()); - declareShortcut("document-assets-videos", "Open Video Asset List", QKeySequence()); - declareShortcut("document-debug-run", "Run Debug", QKeySequence()); - declareShortcut("document-debug-shutdown", "Stop Debug", QKeySequence()); - declareShortcut("document-debug-profiles", "Debug Profiles", QKeySequence()); - declareShortcut("document-debug-runlog", "Open Run Log", QKeySequence()); + declareShortcut(mValues->mKeyBindings.mDocumentFileNewgame, "New Game"); + declareShortcut(mValues->mKeyBindings.mDocumentFileNewaddon, "New Addon"); + declareShortcut(mValues->mKeyBindings.mDocumentFileOpen, "Open"); + declareShortcut(mValues->mKeyBindings.mDocumentFileSave, "Save"); + declareShortcut(mValues->mKeyBindings.mDocumentHelpHelp, "Help"); + declareShortcut(mValues->mKeyBindings.mDocumentHelpTutorial, "Tutorial"); + declareShortcut(mValues->mKeyBindings.mDocumentFileVerify, "Verify"); + declareShortcut(mValues->mKeyBindings.mDocumentFileMerge, "Merge"); + declareShortcut(mValues->mKeyBindings.mDocumentFileErrorlog, "Open Load Error Log"); + declareShortcut(mValues->mKeyBindings.mDocumentFileMetadata, "Meta Data"); + declareShortcut(mValues->mKeyBindings.mDocumentFileClose, "Close Document"); + declareShortcut(mValues->mKeyBindings.mDocumentFileExit, "Exit Application"); + declareShortcut(mValues->mKeyBindings.mDocumentEditUndo, "Undo"); + declareShortcut(mValues->mKeyBindings.mDocumentEditRedo, "Redo"); + declareShortcut(mValues->mKeyBindings.mDocumentEditPreferences, "Open Preferences"); + declareShortcut(mValues->mKeyBindings.mDocumentEditSearch, "Search"); + declareShortcut(mValues->mKeyBindings.mDocumentViewNewview, "New View"); + declareShortcut(mValues->mKeyBindings.mDocumentViewStatusbar, "Toggle Status Bar"); + declareShortcut(mValues->mKeyBindings.mDocumentViewFilters, "Open Filter List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldRegions, "Open Region List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldCells, "Open Cell List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldReferencables, "Open Object List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldReferences, "Open Instance List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldLands, "Open Lands List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldLandtextures, "Open Land Textures List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldPathgrid, "Open Pathgrid List"); + declareShortcut(mValues->mKeyBindings.mDocumentWorldRegionmap, "Open Region Map"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsGlobals, "Open Global List"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsGamesettings, "Open Game Settings"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsScripts, "Open Script List"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsSpells, "Open Spell List"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsEnchantments, "Open Enchantment List"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsMagiceffects, "Open Magic Effect List"); + declareShortcut(mValues->mKeyBindings.mDocumentMechanicsStartscripts, "Open Start Script List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterSkills, "Open Skill List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterClasses, "Open Class List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterFactions, "Open Faction List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterRaces, "Open Race List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterBirthsigns, "Open Birthsign List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterTopics, "Open Topic List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterJournals, "Open Journal List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterTopicinfos, "Open Topic Info List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterJournalinfos, "Open Journal Info List"); + declareShortcut(mValues->mKeyBindings.mDocumentCharacterBodyparts, "Open Body Part List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsReload, "Reload Assets"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsSounds, "Open Sound Asset List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsSoundgens, "Open Sound Generator List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsMeshes, "Open Mesh Asset List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsIcons, "Open Icon Asset List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsMusic, "Open Music Asset List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsSoundres, "Open Sound File List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsTextures, "Open Texture Asset List"); + declareShortcut(mValues->mKeyBindings.mDocumentAssetsVideos, "Open Video Asset List"); + declareShortcut(mValues->mKeyBindings.mDocumentDebugRun, "Run Debug"); + declareShortcut(mValues->mKeyBindings.mDocumentDebugShutdown, "Stop Debug"); + declareShortcut(mValues->mKeyBindings.mDocumentDebugProfiles, "Debug Profiles"); + declareShortcut(mValues->mKeyBindings.mDocumentDebugRunlog, "Open Run Log"); declareSubcategory("Table"); - declareShortcut("table-edit", "Edit Record", QKeySequence()); - declareShortcut("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A)); - declareShortcut("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D)); - declareShortcut("touch-record", "Touch Record", QKeySequence()); - declareShortcut("table-revert", "Revert Record", QKeySequence()); - declareShortcut("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); - declareShortcut("table-moveup", "Move Record Up", QKeySequence()); - declareShortcut("table-movedown", "Move Record Down", QKeySequence()); - declareShortcut("table-view", "View Record", QKeySequence(Qt::ShiftModifier | Qt::Key_C)); - declareShortcut("table-preview", "Preview Record", QKeySequence(Qt::ShiftModifier | Qt::Key_V)); - declareShortcut("table-extendeddelete", "Extended Record Deletion", QKeySequence()); - declareShortcut("table-extendedrevert", "Extended Record Revertion", QKeySequence()); + declareShortcut(mValues->mKeyBindings.mTableEdit, "Edit Record"); + declareShortcut(mValues->mKeyBindings.mTableAdd, "Add Row/Record"); + declareShortcut(mValues->mKeyBindings.mTableClone, "Clone Record"); + declareShortcut(mValues->mKeyBindings.mTouchRecord, "Touch Record"); + declareShortcut(mValues->mKeyBindings.mTableRevert, "Revert Record"); + declareShortcut(mValues->mKeyBindings.mTableRemove, "Remove Row/Record"); + declareShortcut(mValues->mKeyBindings.mTableMoveup, "Move Record Up"); + declareShortcut(mValues->mKeyBindings.mTableMovedown, "Move Record Down"); + declareShortcut(mValues->mKeyBindings.mTableView, "View Record"); + declareShortcut(mValues->mKeyBindings.mTablePreview, "Preview Record"); + declareShortcut(mValues->mKeyBindings.mTableExtendeddelete, "Extended Record Deletion"); + declareShortcut(mValues->mKeyBindings.mTableExtendedrevert, "Extended Record Revertion"); declareSubcategory("Report Table"); - declareShortcut("reporttable-show", "Show Report", QKeySequence()); - declareShortcut("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete)); - declareShortcut("reporttable-replace", "Replace Report", QKeySequence()); - declareShortcut("reporttable-refresh", "Refresh Report", QKeySequence()); + declareShortcut(mValues->mKeyBindings.mReporttableShow, "Show Report"); + declareShortcut(mValues->mKeyBindings.mReporttableRemove, "Remove Report"); + declareShortcut(mValues->mKeyBindings.mReporttableReplace, "Replace Report"); + declareShortcut(mValues->mKeyBindings.mReporttableRefresh, "Refresh Report"); declareSubcategory("Scene"); - declareShortcut("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); - declareShortcut("scene-navi-secondary", "Camera Translation From Mouse Movement", - QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); - declareShortcut("scene-open-primary", "Primary Open", QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton)); - declareShortcut("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton)); - declareShortcut("scene-edit-secondary", "Secondary Edit", QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); - declareShortcut("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); - declareShortcut( - "scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); - declareShortcut( - "scene-select-tertiary", "Tertiary Select", QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton)); + declareShortcut(mValues->mKeyBindings.mSceneNaviPrimary, "Camera Rotation From Mouse Movement"); + declareShortcut(mValues->mKeyBindings.mSceneNaviSecondary, "Camera Translation From Mouse Movement"); + declareShortcut(mValues->mKeyBindings.mSceneOpenPrimary, "Primary Open"); + declareShortcut(mValues->mKeyBindings.mSceneEditPrimary, "Primary Edit"); + declareShortcut(mValues->mKeyBindings.mSceneEditSecondary, "Secondary Edit"); + declareShortcut(mValues->mKeyBindings.mSceneSelectPrimary, "Primary Select"); + declareShortcut(mValues->mKeyBindings.mSceneSelectSecondary, "Secondary Select"); + declareShortcut(mValues->mKeyBindings.mSceneSelectTertiary, "Tertiary Select"); declareModifier(mValues->mKeyBindings.mSceneSpeedModifier, "Speed Modifier"); - declareShortcut("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete)); - declareShortcut("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G)); - declareShortcut("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H)); - declareShortcut("scene-instance-drop-terrain-separately", "Drop to terrain level separately", QKeySequence()); - declareShortcut("scene-instance-drop-collision-separately", "Drop to collision separately", QKeySequence()); - declareShortcut("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); - declareShortcut("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); - declareShortcut("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); - declareShortcut("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4)); - declareShortcut("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2)); - declareShortcut("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); - declareShortcut("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T)); - declareShortcut("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3)); - declareShortcut("scene-duplicate", "Duplicate Instance", QKeySequence(Qt::ShiftModifier | Qt::Key_C)); - declareShortcut("scene-clear-selection", "Clear Selection", QKeySequence(Qt::Key_Space)); - declareShortcut("scene-unhide-all", "Unhide All Objects", QKeySequence(Qt::AltModifier | Qt::Key_H)); - declareShortcut("scene-toggle-visibility", "Toggle Selection Visibility", QKeySequence(Qt::Key_H)); - declareShortcut("scene-group-1", "Select Group 1", QKeySequence(Qt::Key_1)); - declareShortcut("scene-save-1", "Save Group 1", QKeySequence(Qt::ControlModifier | Qt::Key_1)); - declareShortcut("scene-group-2", "Select Group 2", QKeySequence(Qt::Key_2)); - declareShortcut("scene-save-2", "Save Group 2", QKeySequence(Qt::ControlModifier | Qt::Key_2)); - declareShortcut("scene-group-3", "Select Group 3", QKeySequence(Qt::Key_3)); - declareShortcut("scene-save-3", "Save Group 3", QKeySequence(Qt::ControlModifier | Qt::Key_3)); - declareShortcut("scene-group-4", "Select Group 4", QKeySequence(Qt::Key_4)); - declareShortcut("scene-save-4", "Save Group 4", QKeySequence(Qt::ControlModifier | Qt::Key_4)); - declareShortcut("scene-group-5", "Selection Group 5", QKeySequence(Qt::Key_5)); - declareShortcut("scene-save-5", "Save Group 5", QKeySequence(Qt::ControlModifier | Qt::Key_5)); - declareShortcut("scene-group-6", "Selection Group 6", QKeySequence(Qt::Key_6)); - declareShortcut("scene-save-6", "Save Group 6", QKeySequence(Qt::ControlModifier | Qt::Key_6)); - declareShortcut("scene-group-7", "Selection Group 7", QKeySequence(Qt::Key_7)); - declareShortcut("scene-save-7", "Save Group 7", QKeySequence(Qt::ControlModifier | Qt::Key_7)); - declareShortcut("scene-group-8", "Selection Group 8", QKeySequence(Qt::Key_8)); - declareShortcut("scene-save-8", "Save Group 8", QKeySequence(Qt::ControlModifier | Qt::Key_8)); - declareShortcut("scene-group-9", "Selection Group 9", QKeySequence(Qt::Key_9)); - declareShortcut("scene-save-9", "Save Group 9", QKeySequence(Qt::ControlModifier | Qt::Key_9)); - declareShortcut("scene-group-0", "Selection Group 10", QKeySequence(Qt::Key_0)); - declareShortcut("scene-save-0", "Save Group 10", QKeySequence(Qt::ControlModifier | Qt::Key_0)); + declareShortcut(mValues->mKeyBindings.mSceneDelete, "Delete Instance"); + declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrain, "Drop to terrain level"); + declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollision, "Drop to collision"); + declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrainSeparately, "Drop to terrain level separately"); + declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollisionSeparately, "Drop to collision separately"); + declareShortcut(mValues->mKeyBindings.mSceneLoadCamCell, "Load Camera Cell"); + declareShortcut(mValues->mKeyBindings.mSceneLoadCamEastcell, "Load East Cell"); + declareShortcut(mValues->mKeyBindings.mSceneLoadCamNorthcell, "Load North Cell"); + declareShortcut(mValues->mKeyBindings.mSceneLoadCamWestcell, "Load West Cell"); + declareShortcut(mValues->mKeyBindings.mSceneLoadCamSouthcell, "Load South Cell"); + declareShortcut(mValues->mKeyBindings.mSceneEditAbort, "Abort"); + declareShortcut(mValues->mKeyBindings.mSceneFocusToolbar, "Toggle Toolbar Focus"); + declareShortcut(mValues->mKeyBindings.mSceneRenderStats, "Debug Rendering Stats"); + declareShortcut(mValues->mKeyBindings.mSceneDuplicate, "Duplicate Instance"); + declareShortcut(mValues->mKeyBindings.mSceneClearSelection, "Clear Selection"); + declareShortcut(mValues->mKeyBindings.mSceneUnhideAll, "Unhide All Objects"); + declareShortcut(mValues->mKeyBindings.mSceneToggleVisibility, "Toggle Selection Visibility"); + declareShortcut(mValues->mKeyBindings.mSceneGroup0, "Selection Group 0"); + declareShortcut(mValues->mKeyBindings.mSceneSave0, "Save Group 0"); + declareShortcut(mValues->mKeyBindings.mSceneGroup1, "Select Group 1"); + declareShortcut(mValues->mKeyBindings.mSceneSave1, "Save Group 1"); + declareShortcut(mValues->mKeyBindings.mSceneGroup2, "Select Group 2"); + declareShortcut(mValues->mKeyBindings.mSceneSave2, "Save Group 2"); + declareShortcut(mValues->mKeyBindings.mSceneGroup3, "Select Group 3"); + declareShortcut(mValues->mKeyBindings.mSceneSave3, "Save Group 3"); + declareShortcut(mValues->mKeyBindings.mSceneGroup4, "Select Group 4"); + declareShortcut(mValues->mKeyBindings.mSceneSave4, "Save Group 4"); + declareShortcut(mValues->mKeyBindings.mSceneGroup5, "Selection Group 5"); + declareShortcut(mValues->mKeyBindings.mSceneSave5, "Save Group 5"); + declareShortcut(mValues->mKeyBindings.mSceneGroup6, "Selection Group 6"); + declareShortcut(mValues->mKeyBindings.mSceneSave6, "Save Group 6"); + declareShortcut(mValues->mKeyBindings.mSceneGroup7, "Selection Group 7"); + declareShortcut(mValues->mKeyBindings.mSceneSave7, "Save Group 7"); + declareShortcut(mValues->mKeyBindings.mSceneGroup8, "Selection Group 8"); + declareShortcut(mValues->mKeyBindings.mSceneSave8, "Save Group 8"); + declareShortcut(mValues->mKeyBindings.mSceneGroup9, "Selection Group 9"); + declareShortcut(mValues->mKeyBindings.mSceneSave9, "Save Group 9"); declareSubcategory("1st/Free Camera"); - declareShortcut("free-forward", "Forward", QKeySequence(Qt::Key_W)); - declareShortcut("free-backward", "Backward", QKeySequence(Qt::Key_S)); - declareShortcut("free-left", "Left", QKeySequence(Qt::Key_A)); - declareShortcut("free-right", "Right", QKeySequence(Qt::Key_D)); - declareShortcut("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); - declareShortcut("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); - declareShortcut("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); + declareShortcut(mValues->mKeyBindings.mFreeForward, "Forward"); + declareShortcut(mValues->mKeyBindings.mFreeBackward, "Backward"); + declareShortcut(mValues->mKeyBindings.mFreeLeft, "Left"); + declareShortcut(mValues->mKeyBindings.mFreeRight, "Right"); + declareShortcut(mValues->mKeyBindings.mFreeRollLeft, "Roll Left"); + declareShortcut(mValues->mKeyBindings.mFreeRollRight, "Roll Right"); + declareShortcut(mValues->mKeyBindings.mFreeSpeedMode, "Toggle Speed Mode"); declareSubcategory("Orbit Camera"); - declareShortcut("orbit-up", "Up", QKeySequence(Qt::Key_W)); - declareShortcut("orbit-down", "Down", QKeySequence(Qt::Key_S)); - declareShortcut("orbit-left", "Left", QKeySequence(Qt::Key_A)); - declareShortcut("orbit-right", "Right", QKeySequence(Qt::Key_D)); - declareShortcut("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); - declareShortcut("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); - declareShortcut("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); - declareShortcut("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); + declareShortcut(mValues->mKeyBindings.mOrbitUp, "Up"); + declareShortcut(mValues->mKeyBindings.mOrbitDown, "Down"); + declareShortcut(mValues->mKeyBindings.mOrbitLeft, "Left"); + declareShortcut(mValues->mKeyBindings.mOrbitRight, "Right"); + declareShortcut(mValues->mKeyBindings.mOrbitRollLeft, "Roll Left"); + declareShortcut(mValues->mKeyBindings.mOrbitRollRight, "Roll Right"); + declareShortcut(mValues->mKeyBindings.mOrbitSpeedMode, "Toggle Speed Mode"); + declareShortcut(mValues->mKeyBindings.mOrbitCenterSelection, "Center On Selected"); declareSubcategory("Script Editor"); - declareShortcut("script-editor-comment", "Comment Selection", QKeySequence()); - declareShortcut("script-editor-uncomment", "Uncomment Selection", QKeySequence()); + declareShortcut(mValues->mKeyBindings.mScriptEditorComment, "Comment Selection"); + declareShortcut(mValues->mKeyBindings.mScriptEditorUncomment, "Uncomment Selection"); declareCategory("Models"); declareString(mValues->mModels.mBaseanim, "base animations").setTooltip("3rd person base model with textkeys-data"); @@ -477,13 +474,14 @@ CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum(EnumSettingValue& value, con return *setting; } -CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(const std::string& key, const QString& label, QColor default_) +CSMPrefs::ColourSetting& CSMPrefs::State::declareColour( + Settings::SettingValue& value, const QString& label) { if (mCurrentCategory == mCategories.end()) throw std::logic_error("no category for setting"); CSMPrefs::ColourSetting* setting - = new CSMPrefs::ColourSetting(&mCurrentCategory->second, &mMutex, key, label, *mIndex); + = new CSMPrefs::ColourSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex); mCurrentCategory->second.addSetting(setting); @@ -491,7 +489,7 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(const std::string& key, } CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut( - const std::string& key, const QString& label, const QKeySequence& default_) + Settings::SettingValue& value, const QString& label) { if (mCurrentCategory == mCategories.end()) throw std::logic_error("no category for setting"); @@ -499,11 +497,11 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut( // Setup with actual data QKeySequence sequence; - getShortcutManager().convertFromString(mIndex->get(mCurrentCategory->second.getKey(), key), sequence); - getShortcutManager().setSequence(key, sequence); + getShortcutManager().convertFromString(value, sequence); + getShortcutManager().setSequence(value.mName, sequence); CSMPrefs::ShortcutSetting* setting - = new CSMPrefs::ShortcutSetting(&mCurrentCategory->second, &mMutex, key, label, *mIndex); + = new CSMPrefs::ShortcutSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex); mCurrentCategory->second.addSetting(setting); return *setting; diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index f3e580ea5a..821322d586 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -72,9 +72,9 @@ namespace CSMPrefs EnumSetting& declareEnum(EnumSettingValue& value, const QString& label); - ColourSetting& declareColour(const std::string& key, const QString& label, QColor default_); + ColourSetting& declareColour(Settings::SettingValue& value, const QString& label); - ShortcutSetting& declareShortcut(const std::string& key, const QString& label, const QKeySequence& default_); + ShortcutSetting& declareShortcut(Settings::SettingValue& value, const QString& label); StringSetting& declareString(Settings::SettingValue& value, const QString& label); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 330a48daeb..4f295f7b35 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -61,6 +61,23 @@ namespace { + struct NpcParts + { + const ESM::RefId mSwimLeft = ESM::RefId::stringRefId("Swim Left"); + const ESM::RefId mSwimRight = ESM::RefId::stringRefId("Swim Right"); + const ESM::RefId mFootWaterLeft = ESM::RefId::stringRefId("FootWaterLeft"); + const ESM::RefId mFootWaterRight = ESM::RefId::stringRefId("FootWaterRight"); + const ESM::RefId mFootBareLeft = ESM::RefId::stringRefId("FootBareLeft"); + const ESM::RefId mFootBareRight = ESM::RefId::stringRefId("FootBareRight"); + const ESM::RefId mFootLightLeft = ESM::RefId::stringRefId("footLightLeft"); + const ESM::RefId mFootLightRight = ESM::RefId::stringRefId("footLightRight"); + const ESM::RefId mFootMediumRight = ESM::RefId::stringRefId("FootMedRight"); + const ESM::RefId mFootMediumLeft = ESM::RefId::stringRefId("FootMedLeft"); + const ESM::RefId mFootHeavyLeft = ESM::RefId::stringRefId("footHeavyLeft"); + const ESM::RefId mFootHeavyRight = ESM::RefId::stringRefId("footHeavyRight"); + }; + + const NpcParts npcParts; int is_even(double d) { @@ -1225,19 +1242,6 @@ namespace MWClass ESM::RefId Npc::getSoundIdFromSndGen(const MWWorld::Ptr& ptr, std::string_view name) const { - static const ESM::RefId swimLeft = ESM::RefId::stringRefId("Swim Left"); - static const ESM::RefId swimRight = ESM::RefId::stringRefId("Swim Right"); - static const ESM::RefId footWaterLeft = ESM::RefId::stringRefId("FootWaterLeft"); - static const ESM::RefId footWaterRight = ESM::RefId::stringRefId("FootWaterRight"); - static const ESM::RefId footBareLeft = ESM::RefId::stringRefId("FootBareLeft"); - static const ESM::RefId footBareRight = ESM::RefId::stringRefId("FootBareRight"); - static const ESM::RefId footLightLeft = ESM::RefId::stringRefId("footLightLeft"); - static const ESM::RefId footLightRight = ESM::RefId::stringRefId("footLightRight"); - static const ESM::RefId footMediumRight = ESM::RefId::stringRefId("FootMedRight"); - static const ESM::RefId footMediumLeft = ESM::RefId::stringRefId("FootMedLeft"); - static const ESM::RefId footHeavyLeft = ESM::RefId::stringRefId("footHeavyLeft"); - static const ESM::RefId footHeavyRight = ESM::RefId::stringRefId("footHeavyRight"); - if (name == "left" || name == "right") { MWBase::World* world = MWBase::Environment::get().getWorld(); @@ -1245,9 +1249,9 @@ namespace MWClass return ESM::RefId(); osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); if (world->isSwimming(ptr)) - return (name == "left") ? swimLeft : swimRight; + return (name == "left") ? npcParts.mSwimLeft : npcParts.mSwimRight; if (world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr)) - return (name == "left") ? footWaterLeft : footWaterRight; + return (name == "left") ? npcParts.mFootWaterLeft : npcParts.mFootWaterRight; if (world->isOnGround(ptr)) { if (getNpcStats(ptr).isWerewolf() @@ -1262,15 +1266,15 @@ namespace MWClass const MWWorld::InventoryStore& inv = Npc::getInventoryStore(ptr); MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); if (boots == inv.end() || boots->getType() != ESM::Armor::sRecordId) - return (name == "left") ? footBareLeft : footBareRight; + return (name == "left") ? npcParts.mFootBareLeft : npcParts.mFootBareRight; ESM::RefId skill = boots->getClass().getEquipmentSkill(*boots); if (skill == ESM::Skill::LightArmor) - return (name == "left") ? footLightLeft : footLightRight; + return (name == "left") ? npcParts.mFootLightLeft : npcParts.mFootLightRight; else if (skill == ESM::Skill::MediumArmor) - return (name == "left") ? footMediumLeft : footMediumRight; + return (name == "left") ? npcParts.mFootMediumLeft : npcParts.mFootMediumRight; else if (skill == ESM::Skill::HeavyArmor) - return (name == "left") ? footHeavyLeft : footHeavyRight; + return (name == "left") ? npcParts.mFootHeavyLeft : npcParts.mFootHeavyRight; } return ESM::RefId(); } @@ -1279,9 +1283,9 @@ namespace MWClass if (name == "land") return ESM::RefId(); if (name == "swimleft") - return swimLeft; + return npcParts.mSwimLeft; if (name == "swimright") - return swimRight; + return npcParts.mSwimRight; // TODO: I have no idea what these are supposed to do for NPCs since they use // voiced dialog for various conditions like health loss and combat taunts. Maybe // only for biped creatures? diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 4215782e2f..5a6245fca0 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -395,8 +395,10 @@ namespace MWGui { std::string suggestedName = mAlchemy->suggestPotionName(); if (suggestedName != mSuggestedPotionName) + { mNameEdit->setCaptionWithReplacing(suggestedName); - mSuggestedPotionName = suggestedName; + mSuggestedPotionName = std::move(suggestedName); + } mSortModel->clearDragItems(); diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 5d9256b20d..1966442513 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -1065,7 +1065,7 @@ namespace MWGui { createActiveFormats(newBook); - mBook = newBook; + mBook = std::move(newBook); setPage(newPage); if (newPage < mBook->mPages.size()) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 19f7d97176..4141e61e34 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -333,10 +333,10 @@ namespace MWGui if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - const ESM::Class* klass = MWBase::Environment::get().getESMStore()->get().find(classId); - if (klass) + const ESM::Class* pickedClass = MWBase::Environment::get().getESMStore()->get().find(classId); + if (pickedClass) { - mPlayerClass = *klass; + mPlayerClass = *pickedClass; } MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mPickClassDialog)); } @@ -454,30 +454,30 @@ namespace MWGui { if (mCreateClassDialog) { - ESM::Class klass; - klass.mName = mCreateClassDialog->getName(); - klass.mDescription = mCreateClassDialog->getDescription(); - klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); - klass.mData.mIsPlayable = 0x1; - klass.mRecordFlags = 0; + ESM::Class createdClass; + createdClass.mName = mCreateClassDialog->getName(); + createdClass.mDescription = mCreateClassDialog->getDescription(); + createdClass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); + createdClass.mData.mIsPlayable = 0x1; + createdClass.mRecordFlags = 0; std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); - assert(attributes.size() >= klass.mData.mAttribute.size()); - for (size_t i = 0; i < klass.mData.mAttribute.size(); ++i) - klass.mData.mAttribute[i] = ESM::Attribute::refIdToIndex(attributes[i]); + assert(attributes.size() >= createdClass.mData.mAttribute.size()); + for (size_t i = 0; i < createdClass.mData.mAttribute.size(); ++i) + createdClass.mData.mAttribute[i] = ESM::Attribute::refIdToIndex(attributes[i]); std::vector majorSkills = mCreateClassDialog->getMajorSkills(); std::vector minorSkills = mCreateClassDialog->getMinorSkills(); - assert(majorSkills.size() >= klass.mData.mSkills.size()); - assert(minorSkills.size() >= klass.mData.mSkills.size()); - for (size_t i = 0; i < klass.mData.mSkills.size(); ++i) + assert(majorSkills.size() >= createdClass.mData.mSkills.size()); + assert(minorSkills.size() >= createdClass.mData.mSkills.size()); + for (size_t i = 0; i < createdClass.mData.mSkills.size(); ++i) { - klass.mData.mSkills[i][1] = ESM::Skill::refIdToIndex(majorSkills[i]); - klass.mData.mSkills[i][0] = ESM::Skill::refIdToIndex(minorSkills[i]); + createdClass.mData.mSkills[i][1] = ESM::Skill::refIdToIndex(majorSkills[i]); + createdClass.mData.mSkills[i][0] = ESM::Skill::refIdToIndex(minorSkills[i]); } - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); - mPlayerClass = klass; + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(createdClass); + mPlayerClass = std::move(createdClass); // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later mCreateClassDialog->setVisible(false); @@ -666,9 +666,10 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - const ESM::Class* klass = MWBase::Environment::get().getESMStore()->get().find(mGenerateClass); + const ESM::Class* generatedClass + = MWBase::Environment::get().getESMStore()->get().find(mGenerateClass); - mPlayerClass = *klass; + mPlayerClass = *generatedClass; } void CharacterCreation::onGenerateClassBack() diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index d6b4e7f635..839f0f5072 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -248,27 +248,27 @@ namespace MWGui if (mCurrentClassId.empty()) return; const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); - const ESM::Class* klass = store.get().search(mCurrentClassId); - if (!klass) + const ESM::Class* currentClass = store.get().search(mCurrentClassId); + if (!currentClass) return; ESM::Class::Specialization specialization - = static_cast(klass->mData.mSpecialization); + = static_cast(currentClass->mData.mSpecialization); std::string specName{ MWBase::Environment::get().getWindowManager()->getGameSettingString( ESM::Class::sGmstSpecializationIds[specialization], ESM::Class::sGmstSpecializationIds[specialization]) }; mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); - mFavoriteAttribute[0]->setAttributeId(ESM::Attribute::indexToRefId(klass->mData.mAttribute[0])); - mFavoriteAttribute[1]->setAttributeId(ESM::Attribute::indexToRefId(klass->mData.mAttribute[1])); + mFavoriteAttribute[0]->setAttributeId(ESM::Attribute::indexToRefId(currentClass->mData.mAttribute[0])); + mFavoriteAttribute[1]->setAttributeId(ESM::Attribute::indexToRefId(currentClass->mData.mAttribute[1])); ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); - for (size_t i = 0; i < klass->mData.mSkills.size(); ++i) + for (size_t i = 0; i < currentClass->mData.mSkills.size(); ++i) { - ESM::RefId minor = ESM::Skill::indexToRefId(klass->mData.mSkills[i][0]); - ESM::RefId major = ESM::Skill::indexToRefId(klass->mData.mSkills[i][1]); + ESM::RefId minor = ESM::Skill::indexToRefId(currentClass->mData.mSkills[i][0]); + ESM::RefId major = ESM::Skill::indexToRefId(currentClass->mData.mSkills[i][1]); mMinorSkill[i]->setSkillId(minor); mMajorSkill[i]->setSkillId(major); ToolTips::createSkillToolTip(mMinorSkill[i], minor); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index d4553b9664..b430e08142 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -20,6 +19,8 @@ #include #include +#include "apps/openmw/mwgui/textcolours.hpp" + #include "../mwscript/extensions.hpp" #include "../mwscript/interpretercontext.hpp" @@ -439,7 +440,7 @@ namespace MWGui // If new search term reset position, otherwise continue from current position if (newSearchTerm != mCurrentSearchTerm) { - mCurrentSearchTerm = newSearchTerm; + mCurrentSearchTerm = std::move(newSearchTerm); mCurrentOccurrenceIndex = std::string::npos; } diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 7f62bbf49c..b2d9415897 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -221,7 +221,7 @@ namespace MWGui::Formatting } } - mAttributes[key] = value; + mAttributes[key] = std::move(value); } } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 6d79b5f9d7..cb6ba79f9e 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -300,11 +300,9 @@ namespace MWGui return MyGUI::IntCoord(position.left - halfMarkerSize, position.top - halfMarkerSize, markerSize, markerSize); } - MyGUI::Widget* LocalMapBase::createDoorMarker( - const std::string& name, const MyGUI::VectorString& notes, float x, float y) const + MyGUI::Widget* LocalMapBase::createDoorMarker(const std::string& name, float x, float y) const { MarkerUserData data(mLocalMapRender); - data.notes = notes; data.caption = name; MarkerWidget* markerWidget = mLocalMap->createWidget( "MarkerButton", getMarkerCoordinates(x, y, data, 8), MyGUI::Align::Default); @@ -662,8 +660,9 @@ namespace MWGui MarkerUserData* data; if (mDoorMarkersToRecycle.empty()) { - markerWidget = createDoorMarker(marker.name, destNotes, marker.x, marker.y); + markerWidget = createDoorMarker(marker.name, marker.x, marker.y); data = markerWidget->getUserData(); + data->notes = std::move(destNotes); doorMarkerCreated(markerWidget); } else @@ -672,7 +671,7 @@ namespace MWGui mDoorMarkersToRecycle.pop_back(); data = markerWidget->getUserData(); - data->notes = destNotes; + data->notes = std::move(destNotes); data->caption = marker.name; markerWidget->setCoord(getMarkerCoordinates(marker.x, marker.y, *data, 8)); markerWidget->setVisible(true); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 5afc8c7c8a..29759a4365 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -170,8 +170,7 @@ namespace MWGui MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const; MyGUI::IntCoord getMarkerCoordinates( float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const; - MyGUI::Widget* createDoorMarker( - const std::string& name, const MyGUI::VectorString& notes, float x, float y) const; + MyGUI::Widget* createDoorMarker(const std::string& name, float x, float y) const; MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const; virtual void notifyPlayerUpdate() {} diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 4ea21df00c..ddce2c5f50 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -148,11 +148,11 @@ namespace MWGui mUpdateSkillArea = true; } - void ReviewDialog::setClass(const ESM::Class& class_) + void ReviewDialog::setClass(const ESM::Class& playerClass) { - mKlass = class_; - mClassWidget->setCaption(mKlass.mName); - ToolTips::createClassToolTip(mClassWidget, mKlass); + mClass = playerClass; + mClassWidget->setCaption(mClass.mName); + ToolTips::createClassToolTip(mClassWidget, mClass); } void ReviewDialog::setBirthSign(const ESM::RefId& signId) diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 6f594c60f0..7226ad628d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -30,7 +30,7 @@ namespace MWGui void setPlayerName(const std::string& name); void setRace(const ESM::RefId& raceId); - void setClass(const ESM::Class& class_); + void setClass(const ESM::Class& playerClass); void setBirthSign(const ESM::RefId& signId); void setHealth(const MWMechanics::DynamicStat& value); @@ -96,7 +96,7 @@ namespace MWGui std::map mSkillWidgetMap; ESM::RefId mRaceId, mBirthSignId; std::string mName; - ESM::Class mKlass; + ESM::Class mClass; std::vector mSkillWidgets; //< Skills and other information bool mUpdateSkillArea; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index bb97ccb82f..d668db1dec 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -472,7 +472,7 @@ namespace MWGui ESM::EffectList effectList; effectList.mList = mEffects; - mSpell.mEffects = effectList; + mSpell.mEffects = std::move(effectList); mSpell.mData.mCost = int(y); mSpell.mData.mType = ESM::Spell::ST_Spell; mSpell.mData.mFlags = 0; diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 5337e2f798..aa29dfc156 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -172,7 +172,7 @@ namespace MWGui w += 16; ToolTipInfo* tooltipInfo = image->getUserData(); - tooltipInfo->text = sourcesDescription; + tooltipInfo->text = std::move(sourcesDescription); // Fade out if (totalDuration >= fadeTime && fadeTime > 0.f) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9ee7d08f31..0a0343831d 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -251,7 +251,7 @@ namespace MWGui if (!cost.empty() && cost != "0") info.text += MWGui::ToolTips::getValueString(MWMechanics::calcSpellCost(*spell), "#{sCastCost}"); - info.effects = effects; + info.effects = std::move(effects); tooltipSize = createToolTip(info); } else if (type == "Layout") diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 62dcc69330..081df13a0e 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -43,6 +43,8 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/worldmodel.hpp" diff --git a/apps/openmw/mwlua/factionbindings.cpp b/apps/openmw/mwlua/factionbindings.cpp index a43cec874f..87ce6ced39 100644 --- a/apps/openmw/mwlua/factionbindings.cpp +++ b/apps/openmw/mwlua/factionbindings.cpp @@ -122,7 +122,8 @@ namespace MWLua return "ESM3_FactionRank[" + rec.mFactionId.toDebugString() + ", " + std::to_string(rec.mRankIndex + 1) + "]"; }; - rankT["name"] = sol::readonly_property([](const FactionRank& rec) { return rec.mRankName; }); + rankT["name"] + = sol::readonly_property([](const FactionRank& rec) -> std::string_view { return rec.mRankName; }); rankT["primarySkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mPrimarySkill; }); rankT["favouredSkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFavouredSkill; }); rankT["factionReaction"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFactReaction; }); diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index df1e97b885..6f1d265340 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -22,11 +22,13 @@ #include #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwrender/postprocessor.hpp" #include "../mwworld/datetimemanager.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/scene.hpp" #include "../mwworld/worldmodel.hpp" diff --git a/apps/openmw/mwlua/magicbindings.cpp b/apps/openmw/mwlua/magicbindings.cpp index 0a34c008a7..3d57ab24fc 100644 --- a/apps/openmw/mwlua/magicbindings.cpp +++ b/apps/openmw/mwlua/magicbindings.cpp @@ -769,8 +769,13 @@ namespace MWLua sol::state_view lua(ts); self.reset(); return sol::as_function([lua, self]() mutable -> std::pair { - if (!self.isEnd()) + while (!self.isEnd()) { + if (self.mIterator->second.getBase() == 0 && self.mIterator->second.getModifier() == 0.f) + { + self.advance(); + continue; + } ActiveEffect effect = ActiveEffect{ self.mIterator->first, self.mIterator->second }; auto result = sol::make_object(lua, effect); @@ -778,10 +783,7 @@ namespace MWLua self.advance(); return { key, result }; } - else - { - return { sol::lua_nil, sol::lua_nil }; - } + return { sol::lua_nil, sol::lua_nil }; }); }; @@ -823,7 +825,7 @@ namespace MWLua if (auto* store = effects.getStore()) if (auto effect = store->get(key)) return ActiveEffect{ key, effect.value() }; - return sol::nullopt; + return ActiveEffect{ key, MWMechanics::EffectParam() }; }; // types.Actor.activeEffects(o):removeEffect(id, ?arg) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index f45decea3c..748d963bdc 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -20,6 +20,9 @@ #include "../mwmechanics/creaturestats.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + #include "luaevents.hpp" #include "luamanagerimp.hpp" #include "types/types.hpp" diff --git a/apps/openmw/mwlua/types/activator.cpp b/apps/openmw/mwlua/types/activator.cpp index 5ffae0ccd7..43e03952f7 100644 --- a/apps/openmw/mwlua/types/activator.cpp +++ b/apps/openmw/mwlua/types/activator.cpp @@ -5,10 +5,6 @@ #include #include -#include -#include -#include - namespace sol { template <> diff --git a/apps/openmw/mwlua/types/actor.cpp b/apps/openmw/mwlua/types/actor.cpp index a4449f6fb0..473b0d3301 100644 --- a/apps/openmw/mwlua/types/actor.cpp +++ b/apps/openmw/mwlua/types/actor.cpp @@ -6,8 +6,10 @@ #include #include +#include "apps/openmw/mwbase/environment.hpp" #include "apps/openmw/mwbase/mechanicsmanager.hpp" #include "apps/openmw/mwbase/windowmanager.hpp" +#include "apps/openmw/mwbase/world.hpp" #include "apps/openmw/mwmechanics/actorutil.hpp" #include "apps/openmw/mwmechanics/creaturestats.hpp" #include "apps/openmw/mwmechanics/drawstate.hpp" diff --git a/apps/openmw/mwlua/types/actor.hpp b/apps/openmw/mwlua/types/actor.hpp index 4a16b65cbf..6700b4a403 100644 --- a/apps/openmw/mwlua/types/actor.hpp +++ b/apps/openmw/mwlua/types/actor.hpp @@ -4,16 +4,15 @@ #include #include -#include - -#include "apps/openmw/mwworld/esmstore.hpp" -#include -#include #include #include +#include + +#include "apps/openmw/mwbase/environment.hpp" +#include "apps/openmw/mwworld/esmstore.hpp" #include "../context.hpp" -#include "../object.hpp" + namespace MWLua { diff --git a/apps/openmw/mwlua/types/apparatus.cpp b/apps/openmw/mwlua/types/apparatus.cpp index 05eae8b2aa..282dd0669d 100644 --- a/apps/openmw/mwlua/types/apparatus.cpp +++ b/apps/openmw/mwlua/types/apparatus.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/armor.cpp b/apps/openmw/mwlua/types/armor.cpp index b0df533327..91a4c05d8b 100644 --- a/apps/openmw/mwlua/types/armor.cpp +++ b/apps/openmw/mwlua/types/armor.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/book.cpp b/apps/openmw/mwlua/types/book.cpp index dfdbcff1ca..ce2138127d 100644 --- a/apps/openmw/mwlua/types/book.cpp +++ b/apps/openmw/mwlua/types/book.cpp @@ -4,14 +4,12 @@ #include #include +#include #include #include #include -#include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/clothing.cpp b/apps/openmw/mwlua/types/clothing.cpp index 74b03148cb..894748946d 100644 --- a/apps/openmw/mwlua/types/clothing.cpp +++ b/apps/openmw/mwlua/types/clothing.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/container.cpp b/apps/openmw/mwlua/types/container.cpp index ac2e75dea4..332cf6ac2e 100644 --- a/apps/openmw/mwlua/types/container.cpp +++ b/apps/openmw/mwlua/types/container.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include "apps/openmw/mwworld/class.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/creature.cpp b/apps/openmw/mwlua/types/creature.cpp index 54a3c37750..ddf90bf8c5 100644 --- a/apps/openmw/mwlua/types/creature.cpp +++ b/apps/openmw/mwlua/types/creature.cpp @@ -6,10 +6,6 @@ #include #include -#include -#include -#include - namespace sol { template <> diff --git a/apps/openmw/mwlua/types/door.cpp b/apps/openmw/mwlua/types/door.cpp index a4185434c3..df1d10015a 100644 --- a/apps/openmw/mwlua/types/door.cpp +++ b/apps/openmw/mwlua/types/door.cpp @@ -7,7 +7,6 @@ #include #include -#include "apps/openmw/mwworld/esmstore.hpp" #include "apps/openmw/mwworld/worldmodel.hpp" namespace sol diff --git a/apps/openmw/mwlua/types/ingredient.cpp b/apps/openmw/mwlua/types/ingredient.cpp index 72b9f27263..abfd2329ce 100644 --- a/apps/openmw/mwlua/types/ingredient.cpp +++ b/apps/openmw/mwlua/types/ingredient.cpp @@ -6,10 +6,7 @@ #include #include -#include - -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/light.cpp b/apps/openmw/mwlua/types/light.cpp index d2cf195219..5a357994a3 100644 --- a/apps/openmw/mwlua/types/light.cpp +++ b/apps/openmw/mwlua/types/light.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/lockable.cpp b/apps/openmw/mwlua/types/lockable.cpp index e7413edef5..2569f42ee4 100644 --- a/apps/openmw/mwlua/types/lockable.cpp +++ b/apps/openmw/mwlua/types/lockable.cpp @@ -1,11 +1,11 @@ - #include "types.hpp" + #include #include #include #include -#include +#include "apps/openmw/mwworld/esmstore.hpp" namespace MWLua { diff --git a/apps/openmw/mwlua/types/lockpick.cpp b/apps/openmw/mwlua/types/lockpick.cpp index 6de1f7f670..373de4b24d 100644 --- a/apps/openmw/mwlua/types/lockpick.cpp +++ b/apps/openmw/mwlua/types/lockpick.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/misc.cpp b/apps/openmw/mwlua/types/misc.cpp index 9e6b2d6ae5..f83864477f 100644 --- a/apps/openmw/mwlua/types/misc.cpp +++ b/apps/openmw/mwlua/types/misc.cpp @@ -6,9 +6,8 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" +#include "apps/openmw/mwworld/esmstore.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/npc.cpp b/apps/openmw/mwlua/types/npc.cpp index 177c0327ab..30c8fd60d9 100644 --- a/apps/openmw/mwlua/types/npc.cpp +++ b/apps/openmw/mwlua/types/npc.cpp @@ -5,12 +5,12 @@ #include #include -#include -#include -#include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" +#include "apps/openmw/mwbase/mechanicsmanager.hpp" +#include "apps/openmw/mwbase/world.hpp" +#include "apps/openmw/mwmechanics/npcstats.hpp" +#include "apps/openmw/mwworld/class.hpp" +#include "apps/openmw/mwworld/esmstore.hpp" #include "../classbindings.hpp" #include "../localscripts.hpp" diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 1be84b04fa..812296daf8 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -1,12 +1,13 @@ #include "types.hpp" #include "../luamanagerimp.hpp" -#include -#include -#include -#include -#include -#include + +#include "apps/openmw/mwbase/inputmanager.hpp" +#include "apps/openmw/mwbase/journal.hpp" +#include "apps/openmw/mwbase/world.hpp" +#include "apps/openmw/mwmechanics/npcstats.hpp" +#include "apps/openmw/mwworld/class.hpp" +#include "apps/openmw/mwworld/globals.hpp" namespace MWLua { diff --git a/apps/openmw/mwlua/types/potion.cpp b/apps/openmw/mwlua/types/potion.cpp index 33302a3d34..50aca6d9e7 100644 --- a/apps/openmw/mwlua/types/potion.cpp +++ b/apps/openmw/mwlua/types/potion.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/probe.cpp b/apps/openmw/mwlua/types/probe.cpp index 6a3784b41a..30c84326a5 100644 --- a/apps/openmw/mwlua/types/probe.cpp +++ b/apps/openmw/mwlua/types/probe.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/repair.cpp b/apps/openmw/mwlua/types/repair.cpp index 5e97e8c787..880a74d131 100644 --- a/apps/openmw/mwlua/types/repair.cpp +++ b/apps/openmw/mwlua/types/repair.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { diff --git a/apps/openmw/mwlua/types/static.cpp b/apps/openmw/mwlua/types/static.cpp index 960218ca68..78f8cffd67 100644 --- a/apps/openmw/mwlua/types/static.cpp +++ b/apps/openmw/mwlua/types/static.cpp @@ -5,10 +5,6 @@ #include #include -#include -#include -#include - namespace sol { template <> diff --git a/apps/openmw/mwlua/types/types.hpp b/apps/openmw/mwlua/types/types.hpp index adac372277..b52846508a 100644 --- a/apps/openmw/mwlua/types/types.hpp +++ b/apps/openmw/mwlua/types/types.hpp @@ -7,7 +7,6 @@ #include #include "apps/openmw/mwbase/environment.hpp" -#include "apps/openmw/mwbase/world.hpp" #include "apps/openmw/mwworld/esmstore.hpp" #include "apps/openmw/mwworld/store.hpp" diff --git a/apps/openmw/mwlua/types/weapon.cpp b/apps/openmw/mwlua/types/weapon.cpp index de9b2efb95..f09cd96dad 100644 --- a/apps/openmw/mwlua/types/weapon.cpp +++ b/apps/openmw/mwlua/types/weapon.cpp @@ -5,9 +5,7 @@ #include #include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" namespace sol { @@ -16,7 +14,6 @@ namespace sol { }; } -#include namespace { diff --git a/apps/openmw/mwlua/vfsbindings.cpp b/apps/openmw/mwlua/vfsbindings.cpp index ad32520649..0eccb336c2 100644 --- a/apps/openmw/mwlua/vfsbindings.cpp +++ b/apps/openmw/mwlua/vfsbindings.cpp @@ -161,7 +161,8 @@ namespace MWLua auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); sol::usertype handle = context.mLua->sol().new_usertype("FileHandle"); - handle["fileName"] = sol::readonly_property([](const FileHandle& self) { return self.mFileName; }); + handle["fileName"] + = sol::readonly_property([](const FileHandle& self) -> std::string_view { return self.mFileName; }); handle[sol::meta_function::to_string] = [](const FileHandle& self) { return "FileHandle{'" + self.mFileName + "'" + (!self.mFilePtr ? ", closed" : "") + "}"; }; diff --git a/apps/openmw/mwlua/worker.cpp b/apps/openmw/mwlua/worker.cpp index e8b06cf210..193d340208 100644 --- a/apps/openmw/mwlua/worker.cpp +++ b/apps/openmw/mwlua/worker.cpp @@ -2,7 +2,7 @@ #include "luamanagerimp.hpp" -#include +#include "apps/openmw/profile.hpp" #include #include diff --git a/apps/openmw/mwrender/actorspaths.hpp b/apps/openmw/mwrender/actorspaths.hpp index d18197b974..239806576f 100644 --- a/apps/openmw/mwrender/actorspaths.hpp +++ b/apps/openmw/mwrender/actorspaths.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWRENDER_AGENTSPATHS_H #define OPENMW_MWRENDER_AGENTSPATHS_H -#include +#include "apps/openmw/mwworld/ptr.hpp" #include diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index ef8de1cb2e..b75fb507ed 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include "apps/openmw/mwworld/cell.hpp" namespace MWRender { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 1559ebdd5d..84522ee86e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -510,11 +510,15 @@ namespace MWRender if (!isWerewolf) addAnimSource(base, smodel); - if (smodel != defaultSkeleton && base != defaultSkeleton) - addAnimSource(defaultSkeleton, smodel); - if (!isBase) + { + addAnimSource(defaultSkeleton, smodel); addAnimSource(smodel, smodel); + } + else if (base != defaultSkeleton) + { + addAnimSource(defaultSkeleton, smodel); + } if (!isWerewolf && isBeast && mNpc->mRace.contains("argonian")) addAnimSource("meshes\\xargonian_swimkna.nif", smodel); diff --git a/apps/openmw/mwrender/skyutil.hpp b/apps/openmw/mwrender/skyutil.hpp index 1018724595..da038e6c58 100644 --- a/apps/openmw/mwrender/skyutil.hpp +++ b/apps/openmw/mwrender/skyutil.hpp @@ -65,6 +65,7 @@ namespace MWRender bool mIsStorm; ESM::RefId mAmbientLoopSoundID; + ESM::RefId mRainLoopSoundID; float mAmbientSoundVolume; std::string mParticleEffect; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 363a0d06b5..99003d5ce3 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1034,65 +1034,6 @@ namespace MWSound return ret; } - void OpenAL_Output::setHrtf(const std::string& hrtfname, HrtfMode hrtfmode) - { - if (!mDevice || !ALC.SOFT_HRTF) - { - Log(Debug::Info) << "HRTF extension not present"; - return; - } - - LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr; - getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); - - LPALCRESETDEVICESOFT alcResetDeviceSOFT = nullptr; - getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); - - std::vector attrs; - attrs.reserve(15); - - attrs.push_back(ALC_HRTF_SOFT); - attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE - : hrtfmode == HrtfMode::Enable ? ALC_TRUE - : - /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT); - if (!hrtfname.empty()) - { - ALCint index = -1; - ALCint num_hrtf; - alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); - for (ALCint i = 0; i < num_hrtf; ++i) - { - const ALCchar* entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); - if (hrtfname == entry) - { - index = i; - break; - } - } - - if (index < 0) - Log(Debug::Warning) << "Failed to find HRTF name \"" << hrtfname << "\", using default"; - else - { - attrs.push_back(ALC_HRTF_ID_SOFT); - attrs.push_back(index); - } - } - attrs.push_back(0); - alcResetDeviceSOFT(mDevice, attrs.data()); - - ALCint hrtf_state; - alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); - if (!hrtf_state) - Log(Debug::Info) << "HRTF disabled"; - else - { - const ALCchar* hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT); - Log(Debug::Info) << "Enabled HRTF " << hrtf; - } - } - std::pair OpenAL_Output::loadSound(const std::string& fname) { getALError(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index eed23ac659..7636f7bda9 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -84,7 +84,6 @@ namespace MWSound void deinit() override; std::vector enumerateHrtf() override; - void setHrtf(const std::string& hrtfname, HrtfMode hrtfmode) override; std::pair loadSound(const std::string& fname) override; size_t unloadSound(Sound_Handle data) override; diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 8eec20bcba..df95f0909e 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -38,7 +38,6 @@ namespace MWSound virtual void deinit() = 0; virtual std::vector enumerateHrtf() = 0; - virtual void setHrtf(const std::string& hrtfname, HrtfMode hrtfmode) = 0; virtual std::pair loadSound(const std::string& fname) = 0; virtual size_t unloadSound(Sound_Handle data) = 0; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index a8df64e3e3..4c4d0de7a1 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -64,6 +64,7 @@ void MWState::StateManager::cleanup(bool force) mState = State_NoGame; mCharacterManager.setCurrentCharacter(nullptr); mTimePlayed = 0; + mLastSavegame.clear(); MWMechanics::CreatureStats::cleanup(); } @@ -119,14 +120,27 @@ void MWState::StateManager::askLoadRecent() if (!mAskLoadRecent) { - const MWState::Character* character = getCurrentCharacter(); - if (!character || character->begin() == character->end()) // no saves + if (mLastSavegame.empty()) // no saves { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); } else { - MWState::Slot lastSave = *character->begin(); + std::string saveName = Files::pathToUnicodeString(mLastSavegame.filename()); + // Assume the last saved game belongs to the current character's slot list. + const Character* character = getCurrentCharacter(); + if (character) + { + for (const auto& slot : *character) + { + if (slot.mPath == mLastSavegame) + { + saveName = slot.mProfile.mDescription; + break; + } + } + } + std::vector buttons; buttons.emplace_back("#{Interface:Yes}"); buttons.emplace_back("#{Interface:No}"); @@ -134,7 +148,7 @@ void MWState::StateManager::askLoadRecent() = MWBase::Environment::get().getL10nManager()->getMessage("OMWEngine", "AskLoadLastSave"); std::string_view tag = "%s"; size_t pos = message.find(tag); - message.replace(pos, tag.length(), lastSave.mProfile.mDescription); + message.replace(pos, tag.length(), saveName); MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons); mAskLoadRecent = true; } @@ -324,6 +338,7 @@ void MWState::StateManager::saveGame(std::string_view description, const Slot* s throw std::runtime_error("Write operation failed (file stream)"); Settings::saves().mCharacter.set(Files::pathToUnicodeString(slot->mPath.parent_path().filename())); + mLastSavegame = slot->mPath; const auto finish = std::chrono::steady_clock::now(); @@ -563,6 +578,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file if (character) Settings::saves().mCharacter.set(Files::pathToUnicodeString(character->getPath().filename())); + mLastSavegame = filepath; MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWorld()->saveLoaded(); @@ -641,7 +657,15 @@ void MWState::StateManager::quickLoad() void MWState::StateManager::deleteGame(const MWState::Character* character, const MWState::Slot* slot) { + const std::filesystem::path savePath = slot->mPath; mCharacterManager.deleteSlot(character, slot); + if (mLastSavegame == savePath) + { + if (character->begin() != character->end()) + mLastSavegame = character->begin()->mPath; + else + mLastSavegame.clear(); + } } MWState::Character* MWState::StateManager::getCurrentCharacter() @@ -672,9 +696,9 @@ void MWState::StateManager::update(float duration) { mAskLoadRecent = false; // Load last saved game for current character - - MWState::Slot lastSave = *curCharacter->begin(); - loadGame(curCharacter, lastSave.mPath); + // loadGame resets the game state along with mLastSavegame so we want to preserve it + const std::filesystem::path filePath = std::move(mLastSavegame); + loadGame(curCharacter, filePath); } else if (iButton == 1) { diff --git a/apps/openmw/mwstate/statemanagerimp.hpp b/apps/openmw/mwstate/statemanagerimp.hpp index 03843163d1..d632d11137 100644 --- a/apps/openmw/mwstate/statemanagerimp.hpp +++ b/apps/openmw/mwstate/statemanagerimp.hpp @@ -19,6 +19,7 @@ namespace MWState State mState; CharacterManager mCharacterManager; double mTimePlayed; + std::filesystem::path mLastSavegame; private: void cleanup(bool force = false); diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index fda7157010..854348c2a8 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -8,10 +8,10 @@ #include #include -#include -#include -#include -#include +#include "apps/openmw/mwbase/environment.hpp" +#include "apps/openmw/mwbase/world.hpp" +#include "apps/openmw/mwmechanics/spellutil.hpp" +#include "apps/openmw/mwworld/esmstore.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/groundcoverstore.cpp b/apps/openmw/mwworld/groundcoverstore.cpp index 17bf72b5d3..f45b49babe 100644 --- a/apps/openmw/mwworld/groundcoverstore.cpp +++ b/apps/openmw/mwworld/groundcoverstore.cpp @@ -9,8 +9,6 @@ #include #include -#include - #include "store.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 72b2dc3022..80f52f2375 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -111,11 +111,16 @@ namespace std::string model = getModel(ptr); const auto rotation = makeDirectNodeRotation(ptr); + // Null node meant to distinguish objects that aren't in the scene from paged objects + // TODO: find a more clever way to make paging exclusion more reliable? + static const osg::ref_ptr pagedNode( + new SceneUtil::PositionAttitudeTransform); + ESM::RefNum refnum = ptr.getCellRef().getRefNum(); if (!refnum.hasContentFile() || !std::binary_search(pagedRefs.begin(), pagedRefs.end(), refnum)) ptr.getClass().insertObjectRendering(ptr, model, rendering); else - ptr.getRefData().setBaseNode(nullptr); + ptr.getRefData().setBaseNode(pagedNode); setNodeRotation(ptr, rendering, rotation); if (ptr.getClass().useAnim()) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index aa75730b40..2c9b80bc5f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -195,21 +195,19 @@ namespace MWWorld mThunderSoundID[3] = ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Thunder_Sound_ID_3")); - // TODO: support weathers that have both "Ambient Loop Sound ID" and "Rain Loop Sound ID", need to play both - // sounds at the same time. - if (!mRainEffect.empty()) // NOTE: in vanilla, the weathers with rain seem to be hardcoded; changing // Using_Precip has no effect { - mAmbientLoopSoundID + mRainLoopSoundID = ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Rain_Loop_Sound_ID")); - if (mAmbientLoopSoundID.empty()) // default to "rain" if not set - mAmbientLoopSoundID = ESM::RefId::stringRefId("rain"); + if (mRainLoopSoundID.empty()) // default to "rain" if not set + mRainLoopSoundID = ESM::RefId::stringRefId("rain"); + else if (mRainLoopSoundID == "None") + mRainLoopSoundID = ESM::RefId(); } - else - mAmbientLoopSoundID - = ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Ambient_Loop_Sound_ID")); + mAmbientLoopSoundID + = ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Ambient_Loop_Sound_ID")); if (mAmbientLoopSoundID == "None") mAmbientLoopSoundID = ESM::RefId(); } @@ -552,8 +550,6 @@ namespace MWWorld , mQueuedWeather(0) , mRegions() , mResult() - , mAmbientSound(nullptr) - , mPlayingSoundID() { mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; mTimeSettings.mNightEnd = mSunriseTime; @@ -794,24 +790,52 @@ namespace MWWorld mRendering.getSkyManager()->setWeather(mResult); // Play sounds - if (mPlayingSoundID != mResult.mAmbientLoopSoundID) + if (mPlayingAmbientSoundID != mResult.mAmbientLoopSoundID) { - stopSounds(); + if (mAmbientSound) + { + MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); + mAmbientSound = nullptr; + } if (!mResult.mAmbientLoopSoundID.empty()) mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, mResult.mAmbientSoundVolume, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::Loop); - mPlayingSoundID = mResult.mAmbientLoopSoundID; + mPlayingAmbientSoundID = mResult.mAmbientLoopSoundID; } else if (mAmbientSound) mAmbientSound->setVolume(mResult.mAmbientSoundVolume); + + if (mPlayingRainSoundID != mResult.mRainLoopSoundID) + { + if (mRainSound) + { + MWBase::Environment::get().getSoundManager()->stopSound(mRainSound); + mRainSound = nullptr; + } + if (!mResult.mRainLoopSoundID.empty()) + mRainSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mRainLoopSoundID, + mResult.mAmbientSoundVolume, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::Loop); + mPlayingRainSoundID = mResult.mRainLoopSoundID; + } + else if (mRainSound) + mRainSound->setVolume(mResult.mAmbientSoundVolume); } void WeatherManager::stopSounds() { if (mAmbientSound) + { MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); - mAmbientSound = nullptr; - mPlayingSoundID = ESM::RefId(); + mAmbientSound = nullptr; + } + mPlayingAmbientSoundID = ESM::RefId(); + + if (mRainSound) + { + MWBase::Environment::get().getSoundManager()->stopSound(mRainSound); + mRainSound = nullptr; + } + mPlayingRainSoundID = ESM::RefId(); } float WeatherManager::getWindSpeed() const @@ -1118,6 +1142,7 @@ namespace MWWorld mResult.mCloudSpeed = current.mCloudSpeed; mResult.mGlareView = current.mGlareView; mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mRainLoopSoundID = current.mRainLoopSoundID; mResult.mAmbientSoundVolume = 1.f; mResult.mPrecipitationAlpha = 1.f; @@ -1237,6 +1262,7 @@ namespace MWWorld mResult.mAmbientSoundVolume = 1.f - factor / threshold; mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mRainLoopSoundID = current.mRainLoopSoundID; mResult.mRainDiameter = current.mRainDiameter; mResult.mRainMinHeight = current.mRainMinHeight; mResult.mRainMaxHeight = current.mRainMaxHeight; @@ -1252,6 +1278,7 @@ namespace MWWorld mResult.mAmbientSoundVolume = (factor - threshold) / (1 - threshold); mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + mResult.mRainLoopSoundID = other.mRainLoopSoundID; mResult.mRainDiameter = other.mRainDiameter; mResult.mRainMinHeight = other.mRainMinHeight; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 65f926c096..327136a859 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -156,9 +156,11 @@ namespace MWWorld float FogOffset; } mDL; - // Sound effect + // Sound effects // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) ESM::RefId mAmbientLoopSoundID; + // This is used for Rain and Thunderstorm + ESM::RefId mRainLoopSoundID; // Is this an ash storm / blight storm? If so, the following will happen: // - The particles and clouds will be oriented so they appear to come from the Red Mountain. @@ -369,8 +371,10 @@ namespace MWWorld std::map mRegions; MWRender::WeatherResult mResult; - MWBase::Sound* mAmbientSound; - ESM::RefId mPlayingSoundID; + MWBase::Sound* mAmbientSound{ nullptr }; + ESM::RefId mPlayingAmbientSoundID; + MWBase::Sound* mRainSound{ nullptr }; + ESM::RefId mPlayingRainSoundID; void addWeather( const std::string& name, float dlFactor, float dlOffset, const std::string& particleEffect = ""); diff --git a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp index b97f30b319..a3f0d8d3c0 100644 --- a/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp +++ b/apps/openmw_test_suite/mwdialogue/test_keywordsearch.cpp @@ -1,4 +1,5 @@ #include "apps/openmw/mwdialogue/keywordsearch.hpp" + #include struct KeywordSearchTest : public ::testing::Test diff --git a/apps/openmw_test_suite/openmw/options.cpp b/apps/openmw_test_suite/openmw/options.cpp index d79a387645..fc89264f8c 100644 --- a/apps/openmw_test_suite/openmw/options.cpp +++ b/apps/openmw_test_suite/openmw/options.cpp @@ -1,4 +1,5 @@ -#include +#include "apps/openmw/options.hpp" + #include #include diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 9b7bb11f09..0aab06ac90 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -2,12 +2,15 @@ #include "esmfile.hpp" #include +#include #include #include +#include #include #include #include +#include #include #include @@ -127,7 +130,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex& index continue; noGameFiles = false; - if (isChecked(depFile->filePath())) + if (mCheckedFiles.contains(depFile)) { gamefileChecked = true; break; @@ -214,7 +217,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int if (file == mGameFile) return QVariant(); - return mCheckStates[file->filePath()]; + return mCheckedFiles.contains(file) ? Qt::Checked : Qt::Unchecked; } case Qt::UserRole: @@ -228,7 +231,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int } case Qt::UserRole + 1: - return isChecked(file->filePath()); + return mCheckedFiles.contains(file); } return QVariant(); } @@ -276,12 +279,12 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const { int checkValue = value.toInt(); bool setState = false; - if ((checkValue == Qt::Checked) && !isChecked(file->filePath())) + if (checkValue == Qt::Checked && !mCheckedFiles.contains(file)) { setState = true; success = true; } - else if ((checkValue == Qt::Checked) && isChecked(file->filePath())) + else if (checkValue == Qt::Checked && mCheckedFiles.contains(file)) setState = true; else if (checkValue == Qt::Unchecked) setState = true; @@ -314,34 +317,12 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const bool ContentSelectorModel::ContentModel::insertRows(int position, int rows, const QModelIndex& parent) { - if (parent.isValid()) - return false; - - beginInsertRows(parent, position, position + rows - 1); - { - for (int row = 0; row < rows; ++row) - mFiles.insert(position, new EsmFile); - } - endInsertRows(); - - return true; + return false; } bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, const QModelIndex& parent) { - if (parent.isValid()) - return false; - - beginRemoveRows(parent, position, position + rows - 1); - { - for (int row = 0; row < rows; ++row) - delete mFiles.takeAt(position); - } - endRemoveRows(); - - // at this point we know that drag and drop has finished. - checkForLoadOrderErrors(); - return true; + return false; } Qt::DropActions ContentSelectorModel::ContentModel::supportedDropActions() const @@ -357,13 +338,14 @@ QStringList ContentSelectorModel::ContentModel::mimeTypes() const QMimeData* ContentSelectorModel::ContentModel::mimeData(const QModelIndexList& indexes) const { QByteArray encodedData; + QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex& index : indexes) { if (!index.isValid()) continue; - encodedData.append(item(index.row())->encodedData()); + stream << index.row(); } QMimeData* mimeData = new QMimeData(); @@ -395,26 +377,31 @@ bool ContentSelectorModel::ContentModel::dropMimeData( QByteArray encodedData = data->data(mMimeType); QDataStream stream(&encodedData, QIODevice::ReadOnly); + std::vector toMove; while (!stream.atEnd()) { - - QString value; - QStringList values; - QStringList gamefiles; - - for (int i = 0; i < EsmFile::FileProperty_GameFile; ++i) - { - stream >> value; - values << value; - } - - stream >> gamefiles; - - insertRows(beginRow, 1); - - QModelIndex idx = index(beginRow++, 0, QModelIndex()); - setData(idx, QStringList() << values << gamefiles, Qt::EditRole); + int sourceRow; + stream >> sourceRow; + toMove.emplace_back(mFiles.at(sourceRow)); } + int minRow = mFiles.size(); + int maxRow = 0; + for (EsmFile* file : toMove) + { + int from = mFiles.indexOf(file); + int to = beginRow; + if (from < beginRow) + to--; + else if (from > beginRow) + beginRow++; + minRow = std::min(minRow, std::min(to, from)); + maxRow = std::max(maxRow, std::max(to, from)); + mFiles.move(from, to); + } + + dataChanged(index(minRow, 0), index(maxRow, 0)); + // at this point we know that drag and drop has finished. + checkForLoadOrderErrors(); return true; } @@ -447,26 +434,37 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf { QFileInfo info(dir.absoluteFilePath(path2)); - if (item(info.fileName())) - continue; - // Enabled by default in system openmw.cfg; shouldn't be shown in content list. if (info.fileName().compare("builtin.omwscripts", Qt::CaseInsensitive) == 0) continue; + EsmFile* file = const_cast(item(info.fileName())); + bool add = file == nullptr; + std::unique_ptr newFile; + if (add) + { + newFile = std::make_unique(path2); + file = newFile.get(); + } + else + { + // We've found the same file in a higher priority dir, update our existing entry + file->setFileName(path2); + file->setGameFiles({}); + } + if (info.fileName().endsWith(".omwscripts", Qt::CaseInsensitive)) { - EsmFile* file = new EsmFile(path2); file->setDate(info.lastModified()); file->setFilePath(info.absoluteFilePath()); - addFile(file); + if (add) + addFile(newFile.release()); setNew(file->fileName(), newfiles); continue; } try { - EsmFile* file = new EsmFile(path2); file->setDate(info.lastModified()); file->setFilePath(info.absoluteFilePath()); std::filesystem::path filepath = Files::pathFromQString(info.absoluteFilePath()); @@ -522,14 +520,14 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf } // Put the file in the table - addFile(file); + if (add) + addFile(newFile.release()); setNew(file->fileName(), newfiles); } catch (std::runtime_error& e) { // An error occurred while reading the .esp qWarning() << "Error reading addon file: " << e.what(); - continue; } } } @@ -554,6 +552,7 @@ void ContentSelectorModel::ContentModel::clearFiles() if (filesCount > 0) { beginRemoveRows(QModelIndex(), 0, filesCount - 1); + qDeleteAll(mFiles); mFiles.clear(); endRemoveRows(); } @@ -616,14 +615,6 @@ void ContentSelectorModel::ContentModel::sortFiles() emit layoutChanged(); } -bool ContentSelectorModel::ContentModel::isChecked(const QString& filepath) const -{ - const auto it = mCheckStates.find(filepath); - if (it == mCheckStates.end()) - return false; - return it.value() == Qt::Checked; -} - bool ContentSelectorModel::ContentModel::isEnabled(const QModelIndex& index) const { return (flags(index) & Qt::ItemIsEnabled); @@ -684,7 +675,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() { for (int row = 0; row < mFiles.count(); ++row) { - EsmFile* file = item(row); + EsmFile* file = mFiles.at(row); bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0; if (isRowInError) { @@ -711,7 +702,7 @@ QList ContentSelectorModel::ContentModel:: } else { - if (!isChecked(dependentFile->filePath())) + if (!mCheckedFiles.contains(dependentFile)) { errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); } @@ -761,19 +752,18 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath, if (!file) return false; - Qt::CheckState state = Qt::Unchecked; - if (checkState) - state = Qt::Checked; + mCheckedFiles.insert(file); + else + mCheckedFiles.erase(file); - mCheckStates[filepath] = state; emit dataChanged(indexFromItem(item(filepath)), indexFromItem(item(filepath))); if (file->isGameFile()) refreshModel(); // if we're checking an item, ensure all "upstream" files (dependencies) are checked as well. - if (state == Qt::Checked) + if (checkState) { for (const QString& upstreamName : file->gameFiles()) { @@ -782,14 +772,13 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath, if (!upstreamFile) continue; - if (!isChecked(upstreamFile->filePath())) - mCheckStates[upstreamFile->filePath()] = Qt::Checked; + mCheckedFiles.insert(upstreamFile); emit dataChanged(indexFromItem(upstreamFile), indexFromItem(upstreamFile)); } } // otherwise, if we're unchecking an item (or the file is a game file) ensure all downstream files are unchecked. - if (state == Qt::Unchecked) + else { for (const EsmFile* downstreamFile : mFiles) { @@ -798,8 +787,7 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath, if (downstreamFile->gameFiles().contains(filename, Qt::CaseInsensitive)) { - if (mCheckStates.contains(downstreamFile->filePath())) - mCheckStates[downstreamFile->filePath()] = Qt::Unchecked; + mCheckedFiles.erase(downstreamFile); emit dataChanged(indexFromItem(downstreamFile), indexFromItem(downstreamFile)); } @@ -817,7 +805,7 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke // First search for game files and next addons, // so we get more or less correct game files vs addons order. for (EsmFile* file : mFiles) - if (isChecked(file->filePath())) + if (mCheckedFiles.contains(file)) list << file; return list; @@ -826,6 +814,6 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke void ContentSelectorModel::ContentModel::uncheckAll() { emit layoutAboutToBeChanged(); - mCheckStates.clear(); + mCheckedFiles.clear(); emit layoutChanged(); } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index d56f8f9a3b..1ba3090a32 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace ContentSelectorModel { class EsmFile; @@ -57,7 +59,6 @@ namespace ContentSelectorModel void setCurrentGameFile(const EsmFile* file); bool isEnabled(const QModelIndex& index) const; - bool isChecked(const QString& filepath) const; bool setCheckState(const QString& filepath, bool isChecked); bool isNew(const QString& filepath) const; void setNew(const QString& filepath, bool isChecked); @@ -85,7 +86,7 @@ namespace ContentSelectorModel const EsmFile* mGameFile; ContentFileList mFiles; QStringList mArchives; - QHash mCheckStates; + std::set mCheckedFiles; QHash mNewFiles; QSet mPluginsWithLoadOrderError; QString mEncoding; diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index 39a33e710e..e4280baef7 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -1,10 +1,5 @@ #include "esmfile.hpp" -#include -#include - -int ContentSelectorModel::EsmFile::sPropertyCount = 7; - ContentSelectorModel::EsmFile::EsmFile(const QString& fileName, ModelItem* parent) : ModelItem(parent) , mFileName(fileName) @@ -46,17 +41,6 @@ void ContentSelectorModel::EsmFile::setDescription(const QString& description) mDescription = description; } -QByteArray ContentSelectorModel::EsmFile::encodedData() const -{ - QByteArray encodedData; - QDataStream stream(&encodedData, QIODevice::WriteOnly); - - stream << mFileName << mAuthor << mVersion << mModified.toString(Qt::ISODate) << mPath << mDescription - << mGameFiles; - - return encodedData; -} - bool ContentSelectorModel::EsmFile::isGameFile() const { return (mGameFiles.size() == 0) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index a65c778294..606cc3d319 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -30,15 +30,11 @@ namespace ContentSelectorModel }; EsmFile(const QString& fileName = QString(), ModelItem* parent = nullptr); - // EsmFile(const EsmFile &); - - ~EsmFile() {} void setFileProperty(const FileProperty prop, const QString& value); void setFileName(const QString& fileName); void setAuthor(const QString& author); - void setSize(const int size); void setDate(const QDateTime& modified); void setFormat(const QString& format); void setFilePath(const QString& path); @@ -68,10 +64,6 @@ namespace ContentSelectorModel } bool isGameFile() const; - QByteArray encodedData() const; - - public: - static int sPropertyCount; private: QString mTooltipTemlate = tr( diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 3f75b82487..00c32e272d 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -108,6 +108,7 @@ void ContentSelectorView::ContentSelector::buildAddonView() connect(ui->addonView, &QTableView::activated, this, &ContentSelector::slotAddonTableItemActivated); connect(mContentModel, &ContentSelectorModel::ContentModel::dataChanged, this, &ContentSelector::signalAddonDataChanged); + connect(mContentModel, &ContentSelectorModel::ContentModel::dataChanged, this, &ContentSelector::slotRowsMoved); buildContextMenu(); } @@ -331,3 +332,8 @@ void ContentSelectorView::ContentSelector::slotSearchFilterTextChanged(const QSt { ui->addonView->setDragEnabled(newText.isEmpty()); } + +void ContentSelectorView::ContentSelector::slotRowsMoved() +{ + ui->addonView->selectionModel()->clearSelection(); +} \ No newline at end of file diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 48377acb86..2b739645ba 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -85,6 +85,7 @@ namespace ContentSelectorView void slotUncheckMultiSelectedItems(); void slotCopySelectedItemsPaths(); void slotSearchFilterTextChanged(const QString& newText); + void slotRowsMoved(); }; } diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index 1684e3e542..6c15b441e7 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -189,42 +189,18 @@ namespace DetourNavigator void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType) { constexpr std::array indices{ { - 0, - 2, - 3, - 3, - 1, - 0, - 0, - 4, - 6, - 6, - 2, - 0, - 0, - 1, - 5, - 5, - 4, - 0, - 7, - 5, - 1, - 1, - 3, - 7, - 7, - 3, - 2, - 2, - 6, - 7, - 7, - 6, - 4, - 4, - 5, - 7, + 0, 2, 3, // triangle 0 + 3, 1, 0, // triangle 1 + 0, 4, 6, // triangle 2 + 6, 2, 0, // triangle 3 + 0, 1, 5, // triangle 4 + 5, 4, 0, // triangle 5 + 7, 5, 1, // triangle 6 + 1, 3, 7, // triangle 7 + 7, 3, 2, // triangle 8 + 2, 6, 7, // triangle 9 + 7, 6, 4, // triangle 10 + 4, 5, 7, // triangle 11 } }; for (std::size_t i = 0; i < indices.size(); i += 3) diff --git a/components/detournavigator/settingsutils.hpp b/components/detournavigator/settingsutils.hpp index 10e99d002f..c9d8665d51 100644 --- a/components/detournavigator/settingsutils.hpp +++ b/components/detournavigator/settingsutils.hpp @@ -47,6 +47,7 @@ namespace DetourNavigator return position; } + // Returns value in NavMesh coordinates inline float getTileSize(const RecastSettings& settings) { return static_cast(settings.mTileSize) * settings.mCellSize; @@ -62,16 +63,19 @@ namespace DetourNavigator return static_cast(v); } + // Returns integer tile position for position in navmesh coordinates inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec2f& position) { return TilePosition(getTilePosition(settings, position.x()), getTilePosition(settings, position.y())); } + // Returns integer tile position for position in navmesh coordinates inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec3f& position) { return getTilePosition(settings, osg::Vec2f(position.x(), position.z())); } + // Returns tile bounds in navmesh coordinates inline TileBounds makeTileBounds(const RecastSettings& settings, const TilePosition& tilePosition) { return TileBounds{ @@ -80,6 +84,7 @@ namespace DetourNavigator }; } + // Returns border size relative to cell size inline float getBorderSize(const RecastSettings& settings) { return static_cast(settings.mBorderSize) * settings.mCellSize; @@ -95,6 +100,7 @@ namespace DetourNavigator return std::floor(std::sqrt(settings.mMaxTilesNumber / osg::PI)) - 1; } + // Returns tile bounds in real coordinates inline TileBounds makeRealTileBoundsWithBorder(const RecastSettings& settings, const TilePosition& tilePosition) { TileBounds result = makeTileBounds(settings, tilePosition); diff --git a/components/lua_ui/element.cpp b/components/lua_ui/element.cpp index b74938b044..9d124d2a0e 100644 --- a/components/lua_ui/element.cpp +++ b/components/lua_ui/element.cpp @@ -288,6 +288,7 @@ namespace LuaUi auto children = parent->children(); auto it = std::find(children.begin(), children.end(), mRoot); mRoot = createWidget(layout(), 0); + assert(it != children.end()); *it = mRoot; parent->setChildren(children); mRoot->updateCoord(); diff --git a/components/stereo/stereomanager.cpp b/components/stereo/stereomanager.cpp index a2eea0fda2..c3d7f1d320 100644 --- a/components/stereo/stereomanager.cpp +++ b/components/stereo/stereomanager.cpp @@ -315,8 +315,7 @@ namespace Stereo else { auto* ds = osg::DisplaySettings::instance().get(); - auto viewMatrix = mMainCamera->getViewMatrix(); - auto projectionMatrix = mMainCamera->getProjectionMatrix(); + const auto& projectionMatrix = mMainCamera->getProjectionMatrix(); auto s = ds->getEyeSeparation() * Constants::UnitsPerMeter; mViewOffsetMatrix[0] = osg::Matrixd(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, s, 0.0, 0.0, 1.0); diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index a4d8ecee45..08382870f0 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -682,7 +682,6 @@ --- -- @type ActiveEffect -- Magic effect that is currently active on an actor. --- Note that when this effect expires or is removed, it will remain temporarily. Magnitude will be set to 0 for effects that expire. -- @field #string affectedSkill Optional skill ID -- @field #string affectedAttribute Optional attribute ID -- @field #string id Effect id string diff --git a/files/lua_api/openmw/types.lua b/files/lua_api/openmw/types.lua index 6abb209b2c..64b5c74866 100644 --- a/files/lua_api/openmw/types.lua +++ b/files/lua_api/openmw/types.lua @@ -210,14 +210,14 @@ -- end -- @usage -- Check for a specific effect -- local effect = Actor.activeEffects(self):getEffect(core.magic.EFFECT_TYPE.Telekinesis) --- if effect then +-- if effect.magnitude ~= 0 then -- print(effect.id..', attribute='..tostring(effect.affectedAttribute)..', skill='..tostring(effect.affectedSkill)..', magnitude='..tostring(effect.magnitude)) -- else -- print('No Telekinesis effect') -- end -- @usage -- Check for a specific effect targeting a specific attribute. -- local effect = Actor.activeEffects(self):getEffect(core.magic.EFFECT_TYPE.FortifyAttribute, core.ATTRIBUTE.Luck) --- if effect then +-- if effect.magnitude ~= 0 then -- print(effect.id..', attribute='..tostring(effect.affectedAttribute)..', skill='..tostring(effect.affectedSkill)..', magnitude='..tostring(effect.magnitude)) -- else -- print('No Fortify Luck effect') @@ -229,7 +229,7 @@ -- @param self -- @param #string effectId effect ID -- @param #string extraParam Optional skill or attribute ID --- @return openmw.core#ActiveEffect if such an effect is active, nil otherwise +-- @return openmw.core#ActiveEffect --- -- Completely removes the active effect from the actor.