1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-04-13 15:06:43 +00:00

Merge branch 'master' into menuscripts

This commit is contained in:
uramer 2024-01-10 23:21:42 +01:00
commit 4ed2af7666
88 changed files with 521 additions and 595 deletions

View file

@ -64,6 +64,7 @@
Bug #7084: Resurrecting an actor doesn't take into account base record changes 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 #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 #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 #7122: Teleportation to underwater should cancel active water walking effect
Bug #7131: MyGUI log spam when post processing HUD is open Bug #7131: MyGUI log spam when post processing HUD is open
Bug #7134: Saves with an invalid last generated RefNum can be loaded 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 #7604: Goblins Grunt becomes idle once injured
Bug #7609: ForceGreeting should not open dialogue for werewolves Bug #7609: ForceGreeting should not open dialogue for werewolves
Bug #7611: Beast races' idle animations slide after turning or jumping in place 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 #7619: Long map notes may get cut off
Bug #7630: Charm can be cast on creatures Bug #7630: Charm can be cast on creatures
Bug #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing 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 #7712: Casting doesn't support spells and enchantments with no effects
Bug #7723: Assaulting vampires and werewolves shouldn't be a crime Bug #7723: Assaulting vampires and werewolves shouldn't be a crime
Bug #7724: Guards don't help vs werewolves 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 #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 #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 #2566: Handle NAM9 records for manual cell references
Feature #3537: Shader-based water ripples Feature #3537: Shader-based water ripples
Feature #5173: Support for NiFogProperty Feature #5173: Support for NiFogProperty

View file

@ -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 command -v qmake >/dev/null 2>&1 || brew install qt@5
export PATH="/opt/homebrew/opt/qt@5/bin:$PATH" export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"
# Install deps # Install deps
brew install icu4c yaml-cpp sqlite brew install openal-soft icu4c yaml-cpp sqlite
ccache --version ccache --version
cmake --version cmake --version

View file

@ -10,12 +10,13 @@ DEPENDENCIES_ROOT="/tmp/openmw-deps"
QT_PATH=$(brew --prefix qt@5) QT_PATH=$(brew --prefix qt@5)
ICU_PATH=$(brew --prefix icu4c) ICU_PATH=$(brew --prefix icu4c)
OPENAL_PATH=$(brew --prefix openal-soft)
CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache
mkdir build mkdir build
cd build cd build
cmake \ 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_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
-D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \ -D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
-D CMAKE_CXX_FLAGS="-stdlib=libc++" \ -D CMAKE_CXX_FLAGS="-stdlib=libc++" \

View file

@ -54,6 +54,7 @@ IF(NOT CMAKE_BUILD_TYPE)
ENDIF() ENDIF()
if (APPLE) if (APPLE)
set(CMAKE_FIND_FRAMEWORK LAST) # prefer dylibs over frameworks
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")

View file

@ -125,27 +125,6 @@ namespace Launcher
{ {
return Settings::navigator().mMaxNavmeshdbFileSize / (1024 * 1024); return Settings::navigator().mMaxNavmeshdbFileSize / (1024 * 1024);
} }
std::optional<QString> 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++; row++;
} }
mSelector->setProfileContent( mSelector->setProfileContent(mLauncherSettings.getContentListFiles(contentModelName));
findAllFilePaths(directories, mLauncherSettings.getContentListFiles(contentModelName)));
} }
void Launcher::DataFilesPage::saveSettings(const QString& profile) void Launcher::DataFilesPage::saveSettings(const QString& profile)

View file

@ -154,7 +154,7 @@ bool Launcher::GraphicsPage::loadSettings()
if (Settings::shadows().mEnableIndoorShadows) if (Settings::shadows().mEnableIndoorShadows)
indoorShadowsCheckBox->setCheckState(Qt::Checked); indoorShadowsCheckBox->setCheckState(Qt::Checked);
auto boundMethod = Settings::shadows().mComputeSceneBounds.get(); const auto& boundMethod = Settings::shadows().mComputeSceneBounds.get();
if (boundMethod == "bounds") if (boundMethod == "bounds")
shadowComputeSceneBoundsComboBox->setCurrentIndex(0); shadowComputeSceneBoundsComboBox->setCurrentIndex(0);
else if (boundMethod == "primitives") else if (boundMethod == "primitives")

View file

@ -1,7 +1,7 @@
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include <apps/openmw/mwsound/alext.h> #include "apps/openmw/mwsound/alext.h"
#include "openalutil.hpp" #include "openalutil.hpp"

View file

@ -1,5 +1,4 @@
set (OPENCS_SRC set (OPENCS_SRC
${CMAKE_SOURCE_DIR}/files/windows/opencs.rc
) )
opencs_units (. editor) opencs_units (. editor)
@ -146,6 +145,9 @@ source_group (openmw-cs FILES main.cpp ${OPENCS_SRC} ${OPENCS_HDR})
if(WIN32) if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
set(OPENCS_RC_FILE ${CMAKE_SOURCE_DIR}/files/windows/opencs.rc)
else(WIN32)
set(OPENCS_RC_FILE "")
endif(WIN32) endif(WIN32)
if (QT_VERSION_MAJOR VERSION_EQUAL 5) if (QT_VERSION_MAJOR VERSION_EQUAL 5)
@ -186,6 +188,7 @@ if(BUILD_OPENCS)
${OPENCS_CFG} ${OPENCS_CFG}
${OPENCS_DEFAULT_FILTERS_FILE} ${OPENCS_DEFAULT_FILTERS_FILE}
${OPENCS_OPENMW_CFG} ${OPENCS_OPENMW_CFG}
${OPENCS_RC_FILE}
main.cpp main.cpp
) )

View file

@ -14,7 +14,7 @@
#include "state.hpp" #include "state.hpp"
CSMPrefs::ColourSetting::ColourSetting( 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) : TypedSetting(parent, mutex, key, label, index)
, mWidget(nullptr) , mWidget(nullptr)
{ {

View file

@ -6,6 +6,7 @@
#include <QColor> #include <QColor>
#include <string> #include <string>
#include <string_view>
#include <utility> #include <utility>
class QMutex; class QMutex;
@ -30,7 +31,7 @@ namespace CSMPrefs
public: public:
explicit ColourSetting( 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); ColourSetting& setTooltip(const std::string& tooltip);

View file

@ -43,7 +43,7 @@ namespace CSMPrefs
mEventHandler->removeShortcut(shortcut); 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); SequenceMap::const_iterator item = mSequences.find(name);
if (item != mSequences.end()) if (item != mSequences.end())
@ -56,7 +56,7 @@ namespace CSMPrefs
return false; 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 // Add to map/modify
SequenceMap::iterator item = mSequences.find(name); SequenceMap::iterator item = mSequences.find(name);

View file

@ -28,8 +28,8 @@ namespace CSMPrefs
/// The shortcut class will do this automatically /// The shortcut class will do this automatically
void removeShortcut(Shortcut* shortcut); void removeShortcut(Shortcut* shortcut);
bool getSequence(const std::string& name, QKeySequence& sequence) const; bool getSequence(std::string_view name, QKeySequence& sequence) const;
void setSequence(const std::string& name, const QKeySequence& sequence); void setSequence(std::string_view name, const QKeySequence& sequence);
bool getModifier(const std::string& name, int& modifier) const; bool getModifier(const std::string& name, int& modifier) const;
void setModifier(std::string_view name, int modifier); void setModifier(std::string_view name, int modifier);
@ -50,7 +50,7 @@ namespace CSMPrefs
private: private:
// Need a multimap in case multiple shortcuts share the same name // Need a multimap in case multiple shortcuts share the same name
typedef std::multimap<std::string, Shortcut*, std::less<>> ShortcutMap; typedef std::multimap<std::string, Shortcut*, std::less<>> ShortcutMap;
typedef std::map<std::string, QKeySequence> SequenceMap; typedef std::map<std::string, QKeySequence, std::less<>> SequenceMap;
typedef std::map<std::string, int, std::less<>> ModifierMap; typedef std::map<std::string, int, std::less<>> ModifierMap;
typedef std::map<int, std::string> NameMap; typedef std::map<int, std::string> NameMap;
typedef std::map<std::string, int> KeyMap; typedef std::map<std::string, int> KeyMap;

View file

@ -19,7 +19,7 @@
namespace CSMPrefs namespace CSMPrefs
{ {
ShortcutSetting::ShortcutSetting( 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) : TypedSetting(parent, mutex, key, label, index)
, mButton(nullptr) , mButton(nullptr)
, mEditorActive(false) , mEditorActive(false)

View file

@ -2,6 +2,7 @@
#define CSM_PREFS_SHORTCUTSETTING_H #define CSM_PREFS_SHORTCUTSETTING_H
#include <string> #include <string>
#include <string_view>
#include <utility> #include <utility>
#include <QKeySequence> #include <QKeySequence>
@ -24,7 +25,7 @@ namespace CSMPrefs
public: public:
explicit ShortcutSetting( 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; SettingWidgets makeWidgets(QWidget* parent) override;

View file

@ -126,14 +126,14 @@ void CSMPrefs::State::declare()
.setRange(0, 10000); .setRange(0, 10000);
declareInt(mValues->mScripts.mErrorHeight, "Initial height of the error panel").setRange(100, 10000); declareInt(mValues->mScripts.mErrorHeight, "Initial height of the error panel").setRange(100, 10000);
declareBool(mValues->mScripts.mHighlightOccurrences, "Highlight other occurrences of selected names"); declareBool(mValues->mScripts.mHighlightOccurrences, "Highlight other occurrences of selected names");
declareColour("colour-highlight", "Colour of highlighted occurrences", QColor("lightcyan")); declareColour(mValues->mScripts.mColourHighlight, "Colour of highlighted occurrences");
declareColour("colour-int", "Highlight Colour: Integer Literals", QColor("darkmagenta")); declareColour(mValues->mScripts.mColourInt, "Highlight Colour: Integer Literals");
declareColour("colour-float", "Highlight Colour: Float Literals", QColor("magenta")); declareColour(mValues->mScripts.mColourFloat, "Highlight Colour: Float Literals");
declareColour("colour-name", "Highlight Colour: Names", QColor("grey")); declareColour(mValues->mScripts.mColourName, "Highlight Colour: Names");
declareColour("colour-keyword", "Highlight Colour: Keywords", QColor("red")); declareColour(mValues->mScripts.mColourKeyword, "Highlight Colour: Keywords");
declareColour("colour-special", "Highlight Colour: Special Characters", QColor("darkorange")); declareColour(mValues->mScripts.mColourSpecial, "Highlight Colour: Special Characters");
declareColour("colour-comment", "Highlight Colour: Comments", QColor("green")); declareColour(mValues->mScripts.mColourComment, "Highlight Colour: Comments");
declareColour("colour-id", "Highlight Colour: IDs", QColor("blue")); declareColour(mValues->mScripts.mColourId, "Highlight Colour: IDs");
declareCategory("General Input"); declareCategory("General Input");
declareBool(mValues->mGeneralInput.mCycle, "Cyclic next/previous") declareBool(mValues->mGeneralInput.mCycle, "Cyclic next/previous")
@ -185,18 +185,18 @@ void CSMPrefs::State::declare()
.setRange(10, 10000); .setRange(10, 10000);
declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1); declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1);
declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background"); declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background");
declareColour("scene-day-background-colour", "Day Background Colour", QColor(110, 120, 128, 255)); declareColour(mValues->mRendering.mSceneDayBackgroundColour, "Day Background Colour");
declareColour("scene-day-gradient-colour", "Day Gradient Colour", QColor(47, 51, 51, 255)) declareColour(mValues->mRendering.mSceneDayGradientColour, "Day Gradient Colour")
.setTooltip( .setTooltip(
"Sets the gradient color to use in conjunction with the day background color. Ignored if " "Sets the gradient color to use in conjunction with the day background color. Ignored if "
"the gradient option is disabled."); "the gradient option is disabled.");
declareColour("scene-bright-background-colour", "Scene Bright Background Colour", QColor(79, 87, 92, 255)); declareColour(mValues->mRendering.mSceneBrightBackgroundColour, "Scene Bright Background Colour");
declareColour("scene-bright-gradient-colour", "Scene Bright Gradient Colour", QColor(47, 51, 51, 255)) declareColour(mValues->mRendering.mSceneBrightGradientColour, "Scene Bright Gradient Colour")
.setTooltip( .setTooltip(
"Sets the gradient color to use in conjunction with the bright background color. Ignored if " "Sets the gradient color to use in conjunction with the bright background color. Ignored if "
"the gradient option is disabled."); "the gradient option is disabled.");
declareColour("scene-night-background-colour", "Scene Night Background Colour", QColor(64, 77, 79, 255)); declareColour(mValues->mRendering.mSceneNightBackgroundColour, "Scene Night Background Colour");
declareColour("scene-night-gradient-colour", "Scene Night Gradient Colour", QColor(47, 51, 51, 255)) declareColour(mValues->mRendering.mSceneNightGradientColour, "Scene Night Gradient Colour")
.setTooltip( .setTooltip(
"Sets the gradient color to use in conjunction with the night background color. Ignored if " "Sets the gradient color to use in conjunction with the night background color. Ignored if "
"the gradient option is disabled."); "the gradient option is disabled.");
@ -250,157 +250,154 @@ void CSMPrefs::State::declare()
declareCategory("Key Bindings"); declareCategory("Key Bindings");
declareSubcategory("Document"); declareSubcategory("Document");
declareShortcut("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N)); declareShortcut(mValues->mKeyBindings.mDocumentFileNewgame, "New Game");
declareShortcut("document-file-newaddon", "New Addon", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentFileNewaddon, "New Addon");
declareShortcut("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O)); declareShortcut(mValues->mKeyBindings.mDocumentFileOpen, "Open");
declareShortcut("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S)); declareShortcut(mValues->mKeyBindings.mDocumentFileSave, "Save");
declareShortcut("document-help-help", "Help", QKeySequence(Qt::Key_F1)); declareShortcut(mValues->mKeyBindings.mDocumentHelpHelp, "Help");
declareShortcut("document-help-tutorial", "Tutorial", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentHelpTutorial, "Tutorial");
declareShortcut("document-file-verify", "Verify", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentFileVerify, "Verify");
declareShortcut("document-file-merge", "Merge", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentFileMerge, "Merge");
declareShortcut("document-file-errorlog", "Open Load Error Log", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentFileErrorlog, "Open Load Error Log");
declareShortcut("document-file-metadata", "Meta Data", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentFileMetadata, "Meta Data");
declareShortcut("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W)); declareShortcut(mValues->mKeyBindings.mDocumentFileClose, "Close Document");
declareShortcut("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q)); declareShortcut(mValues->mKeyBindings.mDocumentFileExit, "Exit Application");
declareShortcut("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z)); declareShortcut(mValues->mKeyBindings.mDocumentEditUndo, "Undo");
declareShortcut("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z)); declareShortcut(mValues->mKeyBindings.mDocumentEditRedo, "Redo");
declareShortcut("document-edit-preferences", "Open Preferences", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentEditPreferences, "Open Preferences");
declareShortcut("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F)); declareShortcut(mValues->mKeyBindings.mDocumentEditSearch, "Search");
declareShortcut("document-view-newview", "New View", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentViewNewview, "New View");
declareShortcut("document-view-statusbar", "Toggle Status Bar", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentViewStatusbar, "Toggle Status Bar");
declareShortcut("document-view-filters", "Open Filter List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentViewFilters, "Open Filter List");
declareShortcut("document-world-regions", "Open Region List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldRegions, "Open Region List");
declareShortcut("document-world-cells", "Open Cell List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldCells, "Open Cell List");
declareShortcut("document-world-referencables", "Open Object List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldReferencables, "Open Object List");
declareShortcut("document-world-references", "Open Instance List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldReferences, "Open Instance List");
declareShortcut("document-world-lands", "Open Lands List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldLands, "Open Lands List");
declareShortcut("document-world-landtextures", "Open Land Textures List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldLandtextures, "Open Land Textures List");
declareShortcut("document-world-pathgrid", "Open Pathgrid List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldPathgrid, "Open Pathgrid List");
declareShortcut("document-world-regionmap", "Open Region Map", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentWorldRegionmap, "Open Region Map");
declareShortcut("document-mechanics-globals", "Open Global List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsGlobals, "Open Global List");
declareShortcut("document-mechanics-gamesettings", "Open Game Settings", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsGamesettings, "Open Game Settings");
declareShortcut("document-mechanics-scripts", "Open Script List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsScripts, "Open Script List");
declareShortcut("document-mechanics-spells", "Open Spell List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsSpells, "Open Spell List");
declareShortcut("document-mechanics-enchantments", "Open Enchantment List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsEnchantments, "Open Enchantment List");
declareShortcut("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsMagiceffects, "Open Magic Effect List");
declareShortcut("document-mechanics-startscripts", "Open Start Script List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentMechanicsStartscripts, "Open Start Script List");
declareShortcut("document-character-skills", "Open Skill List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterSkills, "Open Skill List");
declareShortcut("document-character-classes", "Open Class List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterClasses, "Open Class List");
declareShortcut("document-character-factions", "Open Faction List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterFactions, "Open Faction List");
declareShortcut("document-character-races", "Open Race List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterRaces, "Open Race List");
declareShortcut("document-character-birthsigns", "Open Birthsign List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterBirthsigns, "Open Birthsign List");
declareShortcut("document-character-topics", "Open Topic List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterTopics, "Open Topic List");
declareShortcut("document-character-journals", "Open Journal List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterJournals, "Open Journal List");
declareShortcut("document-character-topicinfos", "Open Topic Info List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterTopicinfos, "Open Topic Info List");
declareShortcut("document-character-journalinfos", "Open Journal Info List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterJournalinfos, "Open Journal Info List");
declareShortcut("document-character-bodyparts", "Open Body Part List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentCharacterBodyparts, "Open Body Part List");
declareShortcut("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5)); declareShortcut(mValues->mKeyBindings.mDocumentAssetsReload, "Reload Assets");
declareShortcut("document-assets-sounds", "Open Sound Asset List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsSounds, "Open Sound Asset List");
declareShortcut("document-assets-soundgens", "Open Sound Generator List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsSoundgens, "Open Sound Generator List");
declareShortcut("document-assets-meshes", "Open Mesh Asset List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsMeshes, "Open Mesh Asset List");
declareShortcut("document-assets-icons", "Open Icon Asset List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsIcons, "Open Icon Asset List");
declareShortcut("document-assets-music", "Open Music Asset List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsMusic, "Open Music Asset List");
declareShortcut("document-assets-soundres", "Open Sound File List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsSoundres, "Open Sound File List");
declareShortcut("document-assets-textures", "Open Texture Asset List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsTextures, "Open Texture Asset List");
declareShortcut("document-assets-videos", "Open Video Asset List", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentAssetsVideos, "Open Video Asset List");
declareShortcut("document-debug-run", "Run Debug", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentDebugRun, "Run Debug");
declareShortcut("document-debug-shutdown", "Stop Debug", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentDebugShutdown, "Stop Debug");
declareShortcut("document-debug-profiles", "Debug Profiles", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentDebugProfiles, "Debug Profiles");
declareShortcut("document-debug-runlog", "Open Run Log", QKeySequence()); declareShortcut(mValues->mKeyBindings.mDocumentDebugRunlog, "Open Run Log");
declareSubcategory("Table"); declareSubcategory("Table");
declareShortcut("table-edit", "Edit Record", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTableEdit, "Edit Record");
declareShortcut("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A)); declareShortcut(mValues->mKeyBindings.mTableAdd, "Add Row/Record");
declareShortcut("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D)); declareShortcut(mValues->mKeyBindings.mTableClone, "Clone Record");
declareShortcut("touch-record", "Touch Record", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTouchRecord, "Touch Record");
declareShortcut("table-revert", "Revert Record", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTableRevert, "Revert Record");
declareShortcut("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); declareShortcut(mValues->mKeyBindings.mTableRemove, "Remove Row/Record");
declareShortcut("table-moveup", "Move Record Up", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTableMoveup, "Move Record Up");
declareShortcut("table-movedown", "Move Record Down", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTableMovedown, "Move Record Down");
declareShortcut("table-view", "View Record", QKeySequence(Qt::ShiftModifier | Qt::Key_C)); declareShortcut(mValues->mKeyBindings.mTableView, "View Record");
declareShortcut("table-preview", "Preview Record", QKeySequence(Qt::ShiftModifier | Qt::Key_V)); declareShortcut(mValues->mKeyBindings.mTablePreview, "Preview Record");
declareShortcut("table-extendeddelete", "Extended Record Deletion", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTableExtendeddelete, "Extended Record Deletion");
declareShortcut("table-extendedrevert", "Extended Record Revertion", QKeySequence()); declareShortcut(mValues->mKeyBindings.mTableExtendedrevert, "Extended Record Revertion");
declareSubcategory("Report Table"); declareSubcategory("Report Table");
declareShortcut("reporttable-show", "Show Report", QKeySequence()); declareShortcut(mValues->mKeyBindings.mReporttableShow, "Show Report");
declareShortcut("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete)); declareShortcut(mValues->mKeyBindings.mReporttableRemove, "Remove Report");
declareShortcut("reporttable-replace", "Replace Report", QKeySequence()); declareShortcut(mValues->mKeyBindings.mReporttableReplace, "Replace Report");
declareShortcut("reporttable-refresh", "Refresh Report", QKeySequence()); declareShortcut(mValues->mKeyBindings.mReporttableRefresh, "Refresh Report");
declareSubcategory("Scene"); declareSubcategory("Scene");
declareShortcut("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); declareShortcut(mValues->mKeyBindings.mSceneNaviPrimary, "Camera Rotation From Mouse Movement");
declareShortcut("scene-navi-secondary", "Camera Translation From Mouse Movement", declareShortcut(mValues->mKeyBindings.mSceneNaviSecondary, "Camera Translation From Mouse Movement");
QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton)); declareShortcut(mValues->mKeyBindings.mSceneOpenPrimary, "Primary Open");
declareShortcut("scene-open-primary", "Primary Open", QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton)); declareShortcut(mValues->mKeyBindings.mSceneEditPrimary, "Primary Edit");
declareShortcut("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton)); declareShortcut(mValues->mKeyBindings.mSceneEditSecondary, "Secondary Edit");
declareShortcut("scene-edit-secondary", "Secondary Edit", QKeySequence(Qt::ControlModifier | (int)Qt::RightButton)); declareShortcut(mValues->mKeyBindings.mSceneSelectPrimary, "Primary Select");
declareShortcut("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); declareShortcut(mValues->mKeyBindings.mSceneSelectSecondary, "Secondary Select");
declareShortcut( declareShortcut(mValues->mKeyBindings.mSceneSelectTertiary, "Tertiary Select");
"scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
declareShortcut(
"scene-select-tertiary", "Tertiary Select", QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton));
declareModifier(mValues->mKeyBindings.mSceneSpeedModifier, "Speed Modifier"); declareModifier(mValues->mKeyBindings.mSceneSpeedModifier, "Speed Modifier");
declareShortcut("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete)); declareShortcut(mValues->mKeyBindings.mSceneDelete, "Delete Instance");
declareShortcut("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G)); declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrain, "Drop to terrain level");
declareShortcut("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H)); declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollision, "Drop to collision");
declareShortcut("scene-instance-drop-terrain-separately", "Drop to terrain level separately", QKeySequence()); declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrainSeparately, "Drop to terrain level separately");
declareShortcut("scene-instance-drop-collision-separately", "Drop to collision separately", QKeySequence()); declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollisionSeparately, "Drop to collision separately");
declareShortcut("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut(mValues->mKeyBindings.mSceneLoadCamCell, "Load Camera Cell");
declareShortcut("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut(mValues->mKeyBindings.mSceneLoadCamEastcell, "Load East Cell");
declareShortcut("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); declareShortcut(mValues->mKeyBindings.mSceneLoadCamNorthcell, "Load North Cell");
declareShortcut("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4)); declareShortcut(mValues->mKeyBindings.mSceneLoadCamWestcell, "Load West Cell");
declareShortcut("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2)); declareShortcut(mValues->mKeyBindings.mSceneLoadCamSouthcell, "Load South Cell");
declareShortcut("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); declareShortcut(mValues->mKeyBindings.mSceneEditAbort, "Abort");
declareShortcut("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T)); declareShortcut(mValues->mKeyBindings.mSceneFocusToolbar, "Toggle Toolbar Focus");
declareShortcut("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3)); declareShortcut(mValues->mKeyBindings.mSceneRenderStats, "Debug Rendering Stats");
declareShortcut("scene-duplicate", "Duplicate Instance", QKeySequence(Qt::ShiftModifier | Qt::Key_C)); declareShortcut(mValues->mKeyBindings.mSceneDuplicate, "Duplicate Instance");
declareShortcut("scene-clear-selection", "Clear Selection", QKeySequence(Qt::Key_Space)); declareShortcut(mValues->mKeyBindings.mSceneClearSelection, "Clear Selection");
declareShortcut("scene-unhide-all", "Unhide All Objects", QKeySequence(Qt::AltModifier | Qt::Key_H)); declareShortcut(mValues->mKeyBindings.mSceneUnhideAll, "Unhide All Objects");
declareShortcut("scene-toggle-visibility", "Toggle Selection Visibility", QKeySequence(Qt::Key_H)); declareShortcut(mValues->mKeyBindings.mSceneToggleVisibility, "Toggle Selection Visibility");
declareShortcut("scene-group-1", "Select Group 1", QKeySequence(Qt::Key_1)); declareShortcut(mValues->mKeyBindings.mSceneGroup0, "Selection Group 0");
declareShortcut("scene-save-1", "Save Group 1", QKeySequence(Qt::ControlModifier | Qt::Key_1)); declareShortcut(mValues->mKeyBindings.mSceneSave0, "Save Group 0");
declareShortcut("scene-group-2", "Select Group 2", QKeySequence(Qt::Key_2)); declareShortcut(mValues->mKeyBindings.mSceneGroup1, "Select Group 1");
declareShortcut("scene-save-2", "Save Group 2", QKeySequence(Qt::ControlModifier | Qt::Key_2)); declareShortcut(mValues->mKeyBindings.mSceneSave1, "Save Group 1");
declareShortcut("scene-group-3", "Select Group 3", QKeySequence(Qt::Key_3)); declareShortcut(mValues->mKeyBindings.mSceneGroup2, "Select Group 2");
declareShortcut("scene-save-3", "Save Group 3", QKeySequence(Qt::ControlModifier | Qt::Key_3)); declareShortcut(mValues->mKeyBindings.mSceneSave2, "Save Group 2");
declareShortcut("scene-group-4", "Select Group 4", QKeySequence(Qt::Key_4)); declareShortcut(mValues->mKeyBindings.mSceneGroup3, "Select Group 3");
declareShortcut("scene-save-4", "Save Group 4", QKeySequence(Qt::ControlModifier | Qt::Key_4)); declareShortcut(mValues->mKeyBindings.mSceneSave3, "Save Group 3");
declareShortcut("scene-group-5", "Selection Group 5", QKeySequence(Qt::Key_5)); declareShortcut(mValues->mKeyBindings.mSceneGroup4, "Select Group 4");
declareShortcut("scene-save-5", "Save Group 5", QKeySequence(Qt::ControlModifier | Qt::Key_5)); declareShortcut(mValues->mKeyBindings.mSceneSave4, "Save Group 4");
declareShortcut("scene-group-6", "Selection Group 6", QKeySequence(Qt::Key_6)); declareShortcut(mValues->mKeyBindings.mSceneGroup5, "Selection Group 5");
declareShortcut("scene-save-6", "Save Group 6", QKeySequence(Qt::ControlModifier | Qt::Key_6)); declareShortcut(mValues->mKeyBindings.mSceneSave5, "Save Group 5");
declareShortcut("scene-group-7", "Selection Group 7", QKeySequence(Qt::Key_7)); declareShortcut(mValues->mKeyBindings.mSceneGroup6, "Selection Group 6");
declareShortcut("scene-save-7", "Save Group 7", QKeySequence(Qt::ControlModifier | Qt::Key_7)); declareShortcut(mValues->mKeyBindings.mSceneSave6, "Save Group 6");
declareShortcut("scene-group-8", "Selection Group 8", QKeySequence(Qt::Key_8)); declareShortcut(mValues->mKeyBindings.mSceneGroup7, "Selection Group 7");
declareShortcut("scene-save-8", "Save Group 8", QKeySequence(Qt::ControlModifier | Qt::Key_8)); declareShortcut(mValues->mKeyBindings.mSceneSave7, "Save Group 7");
declareShortcut("scene-group-9", "Selection Group 9", QKeySequence(Qt::Key_9)); declareShortcut(mValues->mKeyBindings.mSceneGroup8, "Selection Group 8");
declareShortcut("scene-save-9", "Save Group 9", QKeySequence(Qt::ControlModifier | Qt::Key_9)); declareShortcut(mValues->mKeyBindings.mSceneSave8, "Save Group 8");
declareShortcut("scene-group-0", "Selection Group 10", QKeySequence(Qt::Key_0)); declareShortcut(mValues->mKeyBindings.mSceneGroup9, "Selection Group 9");
declareShortcut("scene-save-0", "Save Group 10", QKeySequence(Qt::ControlModifier | Qt::Key_0)); declareShortcut(mValues->mKeyBindings.mSceneSave9, "Save Group 9");
declareSubcategory("1st/Free Camera"); declareSubcategory("1st/Free Camera");
declareShortcut("free-forward", "Forward", QKeySequence(Qt::Key_W)); declareShortcut(mValues->mKeyBindings.mFreeForward, "Forward");
declareShortcut("free-backward", "Backward", QKeySequence(Qt::Key_S)); declareShortcut(mValues->mKeyBindings.mFreeBackward, "Backward");
declareShortcut("free-left", "Left", QKeySequence(Qt::Key_A)); declareShortcut(mValues->mKeyBindings.mFreeLeft, "Left");
declareShortcut("free-right", "Right", QKeySequence(Qt::Key_D)); declareShortcut(mValues->mKeyBindings.mFreeRight, "Right");
declareShortcut("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); declareShortcut(mValues->mKeyBindings.mFreeRollLeft, "Roll Left");
declareShortcut("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); declareShortcut(mValues->mKeyBindings.mFreeRollRight, "Roll Right");
declareShortcut("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); declareShortcut(mValues->mKeyBindings.mFreeSpeedMode, "Toggle Speed Mode");
declareSubcategory("Orbit Camera"); declareSubcategory("Orbit Camera");
declareShortcut("orbit-up", "Up", QKeySequence(Qt::Key_W)); declareShortcut(mValues->mKeyBindings.mOrbitUp, "Up");
declareShortcut("orbit-down", "Down", QKeySequence(Qt::Key_S)); declareShortcut(mValues->mKeyBindings.mOrbitDown, "Down");
declareShortcut("orbit-left", "Left", QKeySequence(Qt::Key_A)); declareShortcut(mValues->mKeyBindings.mOrbitLeft, "Left");
declareShortcut("orbit-right", "Right", QKeySequence(Qt::Key_D)); declareShortcut(mValues->mKeyBindings.mOrbitRight, "Right");
declareShortcut("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); declareShortcut(mValues->mKeyBindings.mOrbitRollLeft, "Roll Left");
declareShortcut("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); declareShortcut(mValues->mKeyBindings.mOrbitRollRight, "Roll Right");
declareShortcut("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); declareShortcut(mValues->mKeyBindings.mOrbitSpeedMode, "Toggle Speed Mode");
declareShortcut("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); declareShortcut(mValues->mKeyBindings.mOrbitCenterSelection, "Center On Selected");
declareSubcategory("Script Editor"); declareSubcategory("Script Editor");
declareShortcut("script-editor-comment", "Comment Selection", QKeySequence()); declareShortcut(mValues->mKeyBindings.mScriptEditorComment, "Comment Selection");
declareShortcut("script-editor-uncomment", "Uncomment Selection", QKeySequence()); declareShortcut(mValues->mKeyBindings.mScriptEditorUncomment, "Uncomment Selection");
declareCategory("Models"); declareCategory("Models");
declareString(mValues->mModels.mBaseanim, "base animations").setTooltip("3rd person base model with textkeys-data"); 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; return *setting;
} }
CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(const std::string& key, const QString& label, QColor default_) CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
Settings::SettingValue<std::string>& value, const QString& label)
{ {
if (mCurrentCategory == mCategories.end()) if (mCurrentCategory == mCategories.end())
throw std::logic_error("no category for setting"); throw std::logic_error("no category for setting");
CSMPrefs::ColourSetting* 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); mCurrentCategory->second.addSetting(setting);
@ -491,7 +489,7 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(const std::string& key,
} }
CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut( CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut(
const std::string& key, const QString& label, const QKeySequence& default_) Settings::SettingValue<std::string>& value, const QString& label)
{ {
if (mCurrentCategory == mCategories.end()) if (mCurrentCategory == mCategories.end())
throw std::logic_error("no category for setting"); throw std::logic_error("no category for setting");
@ -499,11 +497,11 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut(
// Setup with actual data // Setup with actual data
QKeySequence sequence; QKeySequence sequence;
getShortcutManager().convertFromString(mIndex->get<std::string>(mCurrentCategory->second.getKey(), key), sequence); getShortcutManager().convertFromString(value, sequence);
getShortcutManager().setSequence(key, sequence); getShortcutManager().setSequence(value.mName, sequence);
CSMPrefs::ShortcutSetting* setting 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); mCurrentCategory->second.addSetting(setting);
return *setting; return *setting;

View file

@ -72,9 +72,9 @@ namespace CSMPrefs
EnumSetting& declareEnum(EnumSettingValue& value, const QString& label); EnumSetting& declareEnum(EnumSettingValue& value, const QString& label);
ColourSetting& declareColour(const std::string& key, const QString& label, QColor default_); ColourSetting& declareColour(Settings::SettingValue<std::string>& value, const QString& label);
ShortcutSetting& declareShortcut(const std::string& key, const QString& label, const QKeySequence& default_); ShortcutSetting& declareShortcut(Settings::SettingValue<std::string>& value, const QString& label);
StringSetting& declareString(Settings::SettingValue<std::string>& value, const QString& label); StringSetting& declareString(Settings::SettingValue<std::string>& value, const QString& label);

View file

@ -61,6 +61,23 @@
namespace 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) int is_even(double d)
{ {
@ -1225,19 +1242,6 @@ namespace MWClass
ESM::RefId Npc::getSoundIdFromSndGen(const MWWorld::Ptr& ptr, std::string_view name) const 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") if (name == "left" || name == "right")
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
@ -1245,9 +1249,9 @@ namespace MWClass
return ESM::RefId(); return ESM::RefId();
osg::Vec3f pos(ptr.getRefData().getPosition().asVec3()); osg::Vec3f pos(ptr.getRefData().getPosition().asVec3());
if (world->isSwimming(ptr)) 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)) 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 (world->isOnGround(ptr))
{ {
if (getNpcStats(ptr).isWerewolf() if (getNpcStats(ptr).isWerewolf()
@ -1262,15 +1266,15 @@ namespace MWClass
const MWWorld::InventoryStore& inv = Npc::getInventoryStore(ptr); const MWWorld::InventoryStore& inv = Npc::getInventoryStore(ptr);
MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
if (boots == inv.end() || boots->getType() != ESM::Armor::sRecordId) 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); ESM::RefId skill = boots->getClass().getEquipmentSkill(*boots);
if (skill == ESM::Skill::LightArmor) if (skill == ESM::Skill::LightArmor)
return (name == "left") ? footLightLeft : footLightRight; return (name == "left") ? npcParts.mFootLightLeft : npcParts.mFootLightRight;
else if (skill == ESM::Skill::MediumArmor) else if (skill == ESM::Skill::MediumArmor)
return (name == "left") ? footMediumLeft : footMediumRight; return (name == "left") ? npcParts.mFootMediumLeft : npcParts.mFootMediumRight;
else if (skill == ESM::Skill::HeavyArmor) else if (skill == ESM::Skill::HeavyArmor)
return (name == "left") ? footHeavyLeft : footHeavyRight; return (name == "left") ? npcParts.mFootHeavyLeft : npcParts.mFootHeavyRight;
} }
return ESM::RefId(); return ESM::RefId();
} }
@ -1279,9 +1283,9 @@ namespace MWClass
if (name == "land") if (name == "land")
return ESM::RefId(); return ESM::RefId();
if (name == "swimleft") if (name == "swimleft")
return swimLeft; return npcParts.mSwimLeft;
if (name == "swimright") if (name == "swimright")
return swimRight; return npcParts.mSwimRight;
// TODO: I have no idea what these are supposed to do for NPCs since they use // 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 // voiced dialog for various conditions like health loss and combat taunts. Maybe
// only for biped creatures? // only for biped creatures?

View file

@ -395,8 +395,10 @@ namespace MWGui
{ {
std::string suggestedName = mAlchemy->suggestPotionName(); std::string suggestedName = mAlchemy->suggestPotionName();
if (suggestedName != mSuggestedPotionName) if (suggestedName != mSuggestedPotionName)
{
mNameEdit->setCaptionWithReplacing(suggestedName); mNameEdit->setCaptionWithReplacing(suggestedName);
mSuggestedPotionName = suggestedName; mSuggestedPotionName = std::move(suggestedName);
}
mSortModel->clearDragItems(); mSortModel->clearDragItems();

View file

@ -1065,7 +1065,7 @@ namespace MWGui
{ {
createActiveFormats(newBook); createActiveFormats(newBook);
mBook = newBook; mBook = std::move(newBook);
setPage(newPage); setPage(newPage);
if (newPage < mBook->mPages.size()) if (newPage < mBook->mPages.size())

View file

@ -333,10 +333,10 @@ namespace MWGui
if (!classId.empty()) if (!classId.empty())
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId);
const ESM::Class* klass = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(classId); const ESM::Class* pickedClass = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(classId);
if (klass) if (pickedClass)
{ {
mPlayerClass = *klass; mPlayerClass = *pickedClass;
} }
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mPickClassDialog)); MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mPickClassDialog));
} }
@ -454,30 +454,30 @@ namespace MWGui
{ {
if (mCreateClassDialog) if (mCreateClassDialog)
{ {
ESM::Class klass; ESM::Class createdClass;
klass.mName = mCreateClassDialog->getName(); createdClass.mName = mCreateClassDialog->getName();
klass.mDescription = mCreateClassDialog->getDescription(); createdClass.mDescription = mCreateClassDialog->getDescription();
klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); createdClass.mData.mSpecialization = mCreateClassDialog->getSpecializationId();
klass.mData.mIsPlayable = 0x1; createdClass.mData.mIsPlayable = 0x1;
klass.mRecordFlags = 0; createdClass.mRecordFlags = 0;
std::vector<ESM::RefId> attributes = mCreateClassDialog->getFavoriteAttributes(); std::vector<ESM::RefId> attributes = mCreateClassDialog->getFavoriteAttributes();
assert(attributes.size() >= klass.mData.mAttribute.size()); assert(attributes.size() >= createdClass.mData.mAttribute.size());
for (size_t i = 0; i < klass.mData.mAttribute.size(); ++i) for (size_t i = 0; i < createdClass.mData.mAttribute.size(); ++i)
klass.mData.mAttribute[i] = ESM::Attribute::refIdToIndex(attributes[i]); createdClass.mData.mAttribute[i] = ESM::Attribute::refIdToIndex(attributes[i]);
std::vector<ESM::RefId> majorSkills = mCreateClassDialog->getMajorSkills(); std::vector<ESM::RefId> majorSkills = mCreateClassDialog->getMajorSkills();
std::vector<ESM::RefId> minorSkills = mCreateClassDialog->getMinorSkills(); std::vector<ESM::RefId> minorSkills = mCreateClassDialog->getMinorSkills();
assert(majorSkills.size() >= klass.mData.mSkills.size()); assert(majorSkills.size() >= createdClass.mData.mSkills.size());
assert(minorSkills.size() >= klass.mData.mSkills.size()); assert(minorSkills.size() >= createdClass.mData.mSkills.size());
for (size_t i = 0; i < klass.mData.mSkills.size(); ++i) for (size_t i = 0; i < createdClass.mData.mSkills.size(); ++i)
{ {
klass.mData.mSkills[i][1] = ESM::Skill::refIdToIndex(majorSkills[i]); createdClass.mData.mSkills[i][1] = ESM::Skill::refIdToIndex(majorSkills[i]);
klass.mData.mSkills[i][0] = ESM::Skill::refIdToIndex(minorSkills[i]); createdClass.mData.mSkills[i][0] = ESM::Skill::refIdToIndex(minorSkills[i]);
} }
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); MWBase::Environment::get().getMechanicsManager()->setPlayerClass(createdClass);
mPlayerClass = klass; mPlayerClass = std::move(createdClass);
// Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later
mCreateClassDialog->setVisible(false); mCreateClassDialog->setVisible(false);
@ -666,9 +666,10 @@ namespace MWGui
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass);
const ESM::Class* klass = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(mGenerateClass); const ESM::Class* generatedClass
= MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(mGenerateClass);
mPlayerClass = *klass; mPlayerClass = *generatedClass;
} }
void CharacterCreation::onGenerateClassBack() void CharacterCreation::onGenerateClassBack()

View file

@ -248,27 +248,27 @@ namespace MWGui
if (mCurrentClassId.empty()) if (mCurrentClassId.empty())
return; return;
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore(); const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
const ESM::Class* klass = store.get<ESM::Class>().search(mCurrentClassId); const ESM::Class* currentClass = store.get<ESM::Class>().search(mCurrentClassId);
if (!klass) if (!currentClass)
return; return;
ESM::Class::Specialization specialization ESM::Class::Specialization specialization
= static_cast<ESM::Class::Specialization>(klass->mData.mSpecialization); = static_cast<ESM::Class::Specialization>(currentClass->mData.mSpecialization);
std::string specName{ MWBase::Environment::get().getWindowManager()->getGameSettingString( std::string specName{ MWBase::Environment::get().getWindowManager()->getGameSettingString(
ESM::Class::sGmstSpecializationIds[specialization], ESM::Class::sGmstSpecializationIds[specialization]) }; ESM::Class::sGmstSpecializationIds[specialization], ESM::Class::sGmstSpecializationIds[specialization]) };
mSpecializationName->setCaption(specName); mSpecializationName->setCaption(specName);
ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization);
mFavoriteAttribute[0]->setAttributeId(ESM::Attribute::indexToRefId(klass->mData.mAttribute[0])); mFavoriteAttribute[0]->setAttributeId(ESM::Attribute::indexToRefId(currentClass->mData.mAttribute[0]));
mFavoriteAttribute[1]->setAttributeId(ESM::Attribute::indexToRefId(klass->mData.mAttribute[1])); mFavoriteAttribute[1]->setAttributeId(ESM::Attribute::indexToRefId(currentClass->mData.mAttribute[1]));
ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId());
ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->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 minor = ESM::Skill::indexToRefId(currentClass->mData.mSkills[i][0]);
ESM::RefId major = ESM::Skill::indexToRefId(klass->mData.mSkills[i][1]); ESM::RefId major = ESM::Skill::indexToRefId(currentClass->mData.mSkills[i][1]);
mMinorSkill[i]->setSkillId(minor); mMinorSkill[i]->setSkillId(minor);
mMajorSkill[i]->setSkillId(major); mMajorSkill[i]->setSkillId(major);
ToolTips::createSkillToolTip(mMinorSkill[i], minor); ToolTips::createSkillToolTip(mMinorSkill[i], minor);

View file

@ -9,7 +9,6 @@
#include <fstream> #include <fstream>
#include <regex> #include <regex>
#include <apps/openmw/mwgui/textcolours.hpp>
#include <components/compiler/exception.hpp> #include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp> #include <components/compiler/extensions0.hpp>
#include <components/compiler/lineparser.hpp> #include <components/compiler/lineparser.hpp>
@ -20,6 +19,8 @@
#include <components/misc/utf8stream.hpp> #include <components/misc/utf8stream.hpp>
#include <components/settings/values.hpp> #include <components/settings/values.hpp>
#include "apps/openmw/mwgui/textcolours.hpp"
#include "../mwscript/extensions.hpp" #include "../mwscript/extensions.hpp"
#include "../mwscript/interpretercontext.hpp" #include "../mwscript/interpretercontext.hpp"
@ -439,7 +440,7 @@ namespace MWGui
// If new search term reset position, otherwise continue from current position // If new search term reset position, otherwise continue from current position
if (newSearchTerm != mCurrentSearchTerm) if (newSearchTerm != mCurrentSearchTerm)
{ {
mCurrentSearchTerm = newSearchTerm; mCurrentSearchTerm = std::move(newSearchTerm);
mCurrentOccurrenceIndex = std::string::npos; mCurrentOccurrenceIndex = std::string::npos;
} }

View file

@ -221,7 +221,7 @@ namespace MWGui::Formatting
} }
} }
mAttributes[key] = value; mAttributes[key] = std::move(value);
} }
} }

View file

@ -300,11 +300,9 @@ namespace MWGui
return MyGUI::IntCoord(position.left - halfMarkerSize, position.top - halfMarkerSize, markerSize, markerSize); return MyGUI::IntCoord(position.left - halfMarkerSize, position.top - halfMarkerSize, markerSize, markerSize);
} }
MyGUI::Widget* LocalMapBase::createDoorMarker( MyGUI::Widget* LocalMapBase::createDoorMarker(const std::string& name, float x, float y) const
const std::string& name, const MyGUI::VectorString& notes, float x, float y) const
{ {
MarkerUserData data(mLocalMapRender); MarkerUserData data(mLocalMapRender);
data.notes = notes;
data.caption = name; data.caption = name;
MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>( MarkerWidget* markerWidget = mLocalMap->createWidget<MarkerWidget>(
"MarkerButton", getMarkerCoordinates(x, y, data, 8), MyGUI::Align::Default); "MarkerButton", getMarkerCoordinates(x, y, data, 8), MyGUI::Align::Default);
@ -662,8 +660,9 @@ namespace MWGui
MarkerUserData* data; MarkerUserData* data;
if (mDoorMarkersToRecycle.empty()) if (mDoorMarkersToRecycle.empty())
{ {
markerWidget = createDoorMarker(marker.name, destNotes, marker.x, marker.y); markerWidget = createDoorMarker(marker.name, marker.x, marker.y);
data = markerWidget->getUserData<MarkerUserData>(); data = markerWidget->getUserData<MarkerUserData>();
data->notes = std::move(destNotes);
doorMarkerCreated(markerWidget); doorMarkerCreated(markerWidget);
} }
else else
@ -672,7 +671,7 @@ namespace MWGui
mDoorMarkersToRecycle.pop_back(); mDoorMarkersToRecycle.pop_back();
data = markerWidget->getUserData<MarkerUserData>(); data = markerWidget->getUserData<MarkerUserData>();
data->notes = destNotes; data->notes = std::move(destNotes);
data->caption = marker.name; data->caption = marker.name;
markerWidget->setCoord(getMarkerCoordinates(marker.x, marker.y, *data, 8)); markerWidget->setCoord(getMarkerCoordinates(marker.x, marker.y, *data, 8));
markerWidget->setVisible(true); markerWidget->setVisible(true);

View file

@ -170,8 +170,7 @@ namespace MWGui
MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const; MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const;
MyGUI::IntCoord getMarkerCoordinates( MyGUI::IntCoord getMarkerCoordinates(
float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const; float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const;
MyGUI::Widget* createDoorMarker( MyGUI::Widget* createDoorMarker(const std::string& name, float x, float y) const;
const std::string& name, const MyGUI::VectorString& notes, float x, float y) const;
MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const; MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const;
virtual void notifyPlayerUpdate() {} virtual void notifyPlayerUpdate() {}

View file

@ -148,11 +148,11 @@ namespace MWGui
mUpdateSkillArea = true; mUpdateSkillArea = true;
} }
void ReviewDialog::setClass(const ESM::Class& class_) void ReviewDialog::setClass(const ESM::Class& playerClass)
{ {
mKlass = class_; mClass = playerClass;
mClassWidget->setCaption(mKlass.mName); mClassWidget->setCaption(mClass.mName);
ToolTips::createClassToolTip(mClassWidget, mKlass); ToolTips::createClassToolTip(mClassWidget, mClass);
} }
void ReviewDialog::setBirthSign(const ESM::RefId& signId) void ReviewDialog::setBirthSign(const ESM::RefId& signId)

View file

@ -30,7 +30,7 @@ namespace MWGui
void setPlayerName(const std::string& name); void setPlayerName(const std::string& name);
void setRace(const ESM::RefId& raceId); 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 setBirthSign(const ESM::RefId& signId);
void setHealth(const MWMechanics::DynamicStat<float>& value); void setHealth(const MWMechanics::DynamicStat<float>& value);
@ -96,7 +96,7 @@ namespace MWGui
std::map<ESM::RefId, MyGUI::TextBox*> mSkillWidgetMap; std::map<ESM::RefId, MyGUI::TextBox*> mSkillWidgetMap;
ESM::RefId mRaceId, mBirthSignId; ESM::RefId mRaceId, mBirthSignId;
std::string mName; std::string mName;
ESM::Class mKlass; ESM::Class mClass;
std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information
bool mUpdateSkillArea; bool mUpdateSkillArea;

View file

@ -472,7 +472,7 @@ namespace MWGui
ESM::EffectList effectList; ESM::EffectList effectList;
effectList.mList = mEffects; effectList.mList = mEffects;
mSpell.mEffects = effectList; mSpell.mEffects = std::move(effectList);
mSpell.mData.mCost = int(y); mSpell.mData.mCost = int(y);
mSpell.mData.mType = ESM::Spell::ST_Spell; mSpell.mData.mType = ESM::Spell::ST_Spell;
mSpell.mData.mFlags = 0; mSpell.mData.mFlags = 0;

View file

@ -172,7 +172,7 @@ namespace MWGui
w += 16; w += 16;
ToolTipInfo* tooltipInfo = image->getUserData<ToolTipInfo>(); ToolTipInfo* tooltipInfo = image->getUserData<ToolTipInfo>();
tooltipInfo->text = sourcesDescription; tooltipInfo->text = std::move(sourcesDescription);
// Fade out // Fade out
if (totalDuration >= fadeTime && fadeTime > 0.f) if (totalDuration >= fadeTime && fadeTime > 0.f)

View file

@ -251,7 +251,7 @@ namespace MWGui
if (!cost.empty() && cost != "0") if (!cost.empty() && cost != "0")
info.text info.text
+= MWGui::ToolTips::getValueString(MWMechanics::calcSpellCost(*spell), "#{sCastCost}"); += MWGui::ToolTips::getValueString(MWMechanics::calcSpellCost(*spell), "#{sCastCost}");
info.effects = effects; info.effects = std::move(effects);
tooltipSize = createToolTip(info); tooltipSize = createToolTip(info);
} }
else if (type == "Layout") else if (type == "Layout")

View file

@ -43,6 +43,8 @@
#include <components/esm4/loadtree.hpp> #include <components/esm4/loadtree.hpp>
#include <components/esm4/loadweap.hpp> #include <components/esm4/loadweap.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/worldmodel.hpp" #include "../mwworld/worldmodel.hpp"

View file

@ -122,7 +122,8 @@ namespace MWLua
return "ESM3_FactionRank[" + rec.mFactionId.toDebugString() + ", " + std::to_string(rec.mRankIndex + 1) 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["primarySkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mPrimarySkill; });
rankT["favouredSkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFavouredSkill; }); rankT["favouredSkillValue"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFavouredSkill; });
rankT["factionReaction"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFactReaction; }); rankT["factionReaction"] = sol::readonly_property([](const FactionRank& rec) { return rec.mFactReaction; });

View file

@ -22,11 +22,13 @@
#include <components/lua_ui/util.hpp> #include <components/lua_ui/util.hpp>
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwrender/postprocessor.hpp" #include "../mwrender/postprocessor.hpp"
#include "../mwworld/datetimemanager.hpp" #include "../mwworld/datetimemanager.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/scene.hpp" #include "../mwworld/scene.hpp"
#include "../mwworld/worldmodel.hpp" #include "../mwworld/worldmodel.hpp"

View file

@ -769,8 +769,13 @@ namespace MWLua
sol::state_view lua(ts); sol::state_view lua(ts);
self.reset(); self.reset();
return sol::as_function([lua, self]() mutable -> std::pair<sol::object, sol::object> { return sol::as_function([lua, self]() mutable -> std::pair<sol::object, sol::object> {
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 }; ActiveEffect effect = ActiveEffect{ self.mIterator->first, self.mIterator->second };
auto result = sol::make_object(lua, effect); auto result = sol::make_object(lua, effect);
@ -778,10 +783,7 @@ namespace MWLua
self.advance(); self.advance();
return { key, result }; 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* store = effects.getStore())
if (auto effect = store->get(key)) if (auto effect = store->get(key))
return ActiveEffect{ key, effect.value() }; return ActiveEffect{ key, effect.value() };
return sol::nullopt; return ActiveEffect{ key, MWMechanics::EffectParam() };
}; };
// types.Actor.activeEffects(o):removeEffect(id, ?arg) // types.Actor.activeEffects(o):removeEffect(id, ?arg)

View file

@ -20,6 +20,9 @@
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "luaevents.hpp" #include "luaevents.hpp"
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include "types/types.hpp" #include "types/types.hpp"

View file

@ -5,10 +5,6 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {
template <> template <>

View file

@ -6,8 +6,10 @@
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/settings/values.hpp> #include <components/settings/values.hpp>
#include "apps/openmw/mwbase/environment.hpp"
#include "apps/openmw/mwbase/mechanicsmanager.hpp" #include "apps/openmw/mwbase/mechanicsmanager.hpp"
#include "apps/openmw/mwbase/windowmanager.hpp" #include "apps/openmw/mwbase/windowmanager.hpp"
#include "apps/openmw/mwbase/world.hpp"
#include "apps/openmw/mwmechanics/actorutil.hpp" #include "apps/openmw/mwmechanics/actorutil.hpp"
#include "apps/openmw/mwmechanics/creaturestats.hpp" #include "apps/openmw/mwmechanics/creaturestats.hpp"
#include "apps/openmw/mwmechanics/drawstate.hpp" #include "apps/openmw/mwmechanics/drawstate.hpp"

View file

@ -4,16 +4,15 @@
#include <sol/sol.hpp> #include <sol/sol.hpp>
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/lua/luastate.hpp>
#include "apps/openmw/mwworld/esmstore.hpp"
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwbase/world.hpp>
#include <components/esm3/loadclas.hpp> #include <components/esm3/loadclas.hpp>
#include <components/esm3/loadnpc.hpp> #include <components/esm3/loadnpc.hpp>
#include <components/lua/luastate.hpp>
#include "apps/openmw/mwbase/environment.hpp"
#include "apps/openmw/mwworld/esmstore.hpp"
#include "../context.hpp" #include "../context.hpp"
#include "../object.hpp"
namespace MWLua namespace MWLua
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -4,14 +4,12 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/esm3/loadbook.hpp> #include <components/esm3/loadbook.hpp>
#include <components/esm3/loadskil.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
#include <components/esm3/loadskil.hpp>
namespace sol namespace sol
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -5,7 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwworld/class.hpp> #include "apps/openmw/mwworld/class.hpp"
namespace sol namespace sol
{ {

View file

@ -6,10 +6,6 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {
template <> template <>

View file

@ -7,7 +7,6 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include "apps/openmw/mwworld/esmstore.hpp"
#include "apps/openmw/mwworld/worldmodel.hpp" #include "apps/openmw/mwworld/worldmodel.hpp"
namespace sol namespace sol

View file

@ -6,10 +6,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwworld/esmstore.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwbase/world.hpp>
namespace sol namespace sol
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -1,11 +1,11 @@
#include "types.hpp" #include "types.hpp"
#include <components/esm3/loadmisc.hpp> #include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadspel.hpp> #include <components/esm3/loadspel.hpp>
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwworld/esmstore.hpp> #include "apps/openmw/mwworld/esmstore.hpp"
namespace MWLua namespace MWLua
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -6,9 +6,8 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp> #include "apps/openmw/mwworld/esmstore.hpp"
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -5,12 +5,12 @@
#include <components/esm3/loadnpc.hpp> #include <components/esm3/loadnpc.hpp>
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/mechanicsmanager.hpp> #include "apps/openmw/mwbase/mechanicsmanager.hpp"
#include <apps/openmw/mwbase/world.hpp> #include "apps/openmw/mwbase/world.hpp"
#include <apps/openmw/mwmechanics/npcstats.hpp> #include "apps/openmw/mwmechanics/npcstats.hpp"
#include <apps/openmw/mwworld/class.hpp> #include "apps/openmw/mwworld/class.hpp"
#include <apps/openmw/mwworld/esmstore.hpp> #include "apps/openmw/mwworld/esmstore.hpp"
#include "../classbindings.hpp" #include "../classbindings.hpp"
#include "../localscripts.hpp" #include "../localscripts.hpp"

View file

@ -1,12 +1,13 @@
#include "types.hpp" #include "types.hpp"
#include "../luamanagerimp.hpp" #include "../luamanagerimp.hpp"
#include <apps/openmw/mwbase/inputmanager.hpp>
#include <apps/openmw/mwbase/journal.hpp> #include "apps/openmw/mwbase/inputmanager.hpp"
#include <apps/openmw/mwbase/world.hpp> #include "apps/openmw/mwbase/journal.hpp"
#include <apps/openmw/mwmechanics/npcstats.hpp> #include "apps/openmw/mwbase/world.hpp"
#include <apps/openmw/mwworld/class.hpp> #include "apps/openmw/mwmechanics/npcstats.hpp"
#include <apps/openmw/mwworld/globals.hpp> #include "apps/openmw/mwworld/class.hpp"
#include "apps/openmw/mwworld/globals.hpp"
namespace MWLua namespace MWLua
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {

View file

@ -5,7 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
namespace sol namespace sol
{ {

View file

@ -5,10 +5,6 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {
template <> template <>

View file

@ -7,7 +7,6 @@
#include <components/lua/luastate.hpp> #include <components/lua/luastate.hpp>
#include "apps/openmw/mwbase/environment.hpp" #include "apps/openmw/mwbase/environment.hpp"
#include "apps/openmw/mwbase/world.hpp"
#include "apps/openmw/mwworld/esmstore.hpp" #include "apps/openmw/mwworld/esmstore.hpp"
#include "apps/openmw/mwworld/store.hpp" #include "apps/openmw/mwworld/store.hpp"

View file

@ -5,9 +5,7 @@
#include <components/misc/resourcehelpers.hpp> #include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwworld/esmstore.hpp>
namespace sol namespace sol
{ {
@ -16,7 +14,6 @@ namespace sol
{ {
}; };
} }
#include <components/resource/resourcesystem.hpp>
namespace namespace
{ {

View file

@ -161,7 +161,8 @@ namespace MWLua
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS(); auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
sol::usertype<FileHandle> handle = context.mLua->sol().new_usertype<FileHandle>("FileHandle"); sol::usertype<FileHandle> handle = context.mLua->sol().new_usertype<FileHandle>("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) { handle[sol::meta_function::to_string] = [](const FileHandle& self) {
return "FileHandle{'" + self.mFileName + "'" + (!self.mFilePtr ? ", closed" : "") + "}"; return "FileHandle{'" + self.mFileName + "'" + (!self.mFilePtr ? ", closed" : "") + "}";
}; };

View file

@ -2,7 +2,7 @@
#include "luamanagerimp.hpp" #include "luamanagerimp.hpp"
#include <apps/openmw/profile.hpp> #include "apps/openmw/profile.hpp"
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/settings/values.hpp> #include <components/settings/values.hpp>

View file

@ -1,7 +1,7 @@
#ifndef OPENMW_MWRENDER_AGENTSPATHS_H #ifndef OPENMW_MWRENDER_AGENTSPATHS_H
#define OPENMW_MWRENDER_AGENTSPATHS_H #define OPENMW_MWRENDER_AGENTSPATHS_H
#include <apps/openmw/mwworld/ptr.hpp> #include "apps/openmw/mwworld/ptr.hpp"
#include <osg/ref_ptr> #include <osg/ref_ptr>

View file

@ -9,7 +9,7 @@
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/settings/values.hpp> #include <components/settings/values.hpp>
#include <apps/openmw/mwworld/cell.hpp> #include "apps/openmw/mwworld/cell.hpp"
namespace MWRender namespace MWRender
{ {

View file

@ -510,11 +510,15 @@ namespace MWRender
if (!isWerewolf) if (!isWerewolf)
addAnimSource(base, smodel); addAnimSource(base, smodel);
if (smodel != defaultSkeleton && base != defaultSkeleton)
addAnimSource(defaultSkeleton, smodel);
if (!isBase) if (!isBase)
{
addAnimSource(defaultSkeleton, smodel);
addAnimSource(smodel, smodel); addAnimSource(smodel, smodel);
}
else if (base != defaultSkeleton)
{
addAnimSource(defaultSkeleton, smodel);
}
if (!isWerewolf && isBeast && mNpc->mRace.contains("argonian")) if (!isWerewolf && isBeast && mNpc->mRace.contains("argonian"))
addAnimSource("meshes\\xargonian_swimkna.nif", smodel); addAnimSource("meshes\\xargonian_swimkna.nif", smodel);

View file

@ -65,6 +65,7 @@ namespace MWRender
bool mIsStorm; bool mIsStorm;
ESM::RefId mAmbientLoopSoundID; ESM::RefId mAmbientLoopSoundID;
ESM::RefId mRainLoopSoundID;
float mAmbientSoundVolume; float mAmbientSoundVolume;
std::string mParticleEffect; std::string mParticleEffect;

View file

@ -1034,65 +1034,6 @@ namespace MWSound
return ret; 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<ALCint> 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<Sound_Handle, size_t> OpenAL_Output::loadSound(const std::string& fname) std::pair<Sound_Handle, size_t> OpenAL_Output::loadSound(const std::string& fname)
{ {
getALError(); getALError();

View file

@ -84,7 +84,6 @@ namespace MWSound
void deinit() override; void deinit() override;
std::vector<std::string> enumerateHrtf() override; std::vector<std::string> enumerateHrtf() override;
void setHrtf(const std::string& hrtfname, HrtfMode hrtfmode) override;
std::pair<Sound_Handle, size_t> loadSound(const std::string& fname) override; std::pair<Sound_Handle, size_t> loadSound(const std::string& fname) override;
size_t unloadSound(Sound_Handle data) override; size_t unloadSound(Sound_Handle data) override;

View file

@ -38,7 +38,6 @@ namespace MWSound
virtual void deinit() = 0; virtual void deinit() = 0;
virtual std::vector<std::string> enumerateHrtf() = 0; virtual std::vector<std::string> enumerateHrtf() = 0;
virtual void setHrtf(const std::string& hrtfname, HrtfMode hrtfmode) = 0;
virtual std::pair<Sound_Handle, size_t> loadSound(const std::string& fname) = 0; virtual std::pair<Sound_Handle, size_t> loadSound(const std::string& fname) = 0;
virtual size_t unloadSound(Sound_Handle data) = 0; virtual size_t unloadSound(Sound_Handle data) = 0;

View file

@ -64,6 +64,7 @@ void MWState::StateManager::cleanup(bool force)
mState = State_NoGame; mState = State_NoGame;
mCharacterManager.setCurrentCharacter(nullptr); mCharacterManager.setCurrentCharacter(nullptr);
mTimePlayed = 0; mTimePlayed = 0;
mLastSavegame.clear();
MWMechanics::CreatureStats::cleanup(); MWMechanics::CreatureStats::cleanup();
} }
@ -119,14 +120,27 @@ void MWState::StateManager::askLoadRecent()
if (!mAskLoadRecent) if (!mAskLoadRecent)
{ {
const MWState::Character* character = getCurrentCharacter(); if (mLastSavegame.empty()) // no saves
if (!character || character->begin() == character->end()) // no saves
{ {
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu);
} }
else 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<std::string> buttons; std::vector<std::string> buttons;
buttons.emplace_back("#{Interface:Yes}"); buttons.emplace_back("#{Interface:Yes}");
buttons.emplace_back("#{Interface:No}"); buttons.emplace_back("#{Interface:No}");
@ -134,7 +148,7 @@ void MWState::StateManager::askLoadRecent()
= MWBase::Environment::get().getL10nManager()->getMessage("OMWEngine", "AskLoadLastSave"); = MWBase::Environment::get().getL10nManager()->getMessage("OMWEngine", "AskLoadLastSave");
std::string_view tag = "%s"; std::string_view tag = "%s";
size_t pos = message.find(tag); 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); MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons);
mAskLoadRecent = true; 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)"); throw std::runtime_error("Write operation failed (file stream)");
Settings::saves().mCharacter.set(Files::pathToUnicodeString(slot->mPath.parent_path().filename())); Settings::saves().mCharacter.set(Files::pathToUnicodeString(slot->mPath.parent_path().filename()));
mLastSavegame = slot->mPath;
const auto finish = std::chrono::steady_clock::now(); const auto finish = std::chrono::steady_clock::now();
@ -563,6 +578,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file
if (character) if (character)
Settings::saves().mCharacter.set(Files::pathToUnicodeString(character->getPath().filename())); Settings::saves().mCharacter.set(Files::pathToUnicodeString(character->getPath().filename()));
mLastSavegame = filepath;
MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWindowManager()->setNewGame(false);
MWBase::Environment::get().getWorld()->saveLoaded(); 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) void MWState::StateManager::deleteGame(const MWState::Character* character, const MWState::Slot* slot)
{ {
const std::filesystem::path savePath = slot->mPath;
mCharacterManager.deleteSlot(character, slot); mCharacterManager.deleteSlot(character, slot);
if (mLastSavegame == savePath)
{
if (character->begin() != character->end())
mLastSavegame = character->begin()->mPath;
else
mLastSavegame.clear();
}
} }
MWState::Character* MWState::StateManager::getCurrentCharacter() MWState::Character* MWState::StateManager::getCurrentCharacter()
@ -672,9 +696,9 @@ void MWState::StateManager::update(float duration)
{ {
mAskLoadRecent = false; mAskLoadRecent = false;
// Load last saved game for current character // Load last saved game for current character
// loadGame resets the game state along with mLastSavegame so we want to preserve it
MWState::Slot lastSave = *curCharacter->begin(); const std::filesystem::path filePath = std::move(mLastSavegame);
loadGame(curCharacter, lastSave.mPath); loadGame(curCharacter, filePath);
} }
else if (iButton == 1) else if (iButton == 1)
{ {

View file

@ -19,6 +19,7 @@ namespace MWState
State mState; State mState;
CharacterManager mCharacterManager; CharacterManager mCharacterManager;
double mTimePlayed; double mTimePlayed;
std::filesystem::path mLastSavegame;
private: private:
void cleanup(bool force = false); void cleanup(bool force = false);

View file

@ -8,10 +8,10 @@
#include <components/esm3/objectstate.hpp> #include <components/esm3/objectstate.hpp>
#include <components/esm4/loadrefr.hpp> #include <components/esm4/loadrefr.hpp>
#include <apps/openmw/mwbase/environment.hpp> #include "apps/openmw/mwbase/environment.hpp"
#include <apps/openmw/mwbase/world.hpp> #include "apps/openmw/mwbase/world.hpp"
#include <apps/openmw/mwmechanics/spellutil.hpp> #include "apps/openmw/mwmechanics/spellutil.hpp"
#include <apps/openmw/mwworld/esmstore.hpp> #include "apps/openmw/mwworld/esmstore.hpp"
namespace MWWorld namespace MWWorld
{ {

View file

@ -9,8 +9,6 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <apps/openmw/mwbase/environment.hpp>
#include "store.hpp" #include "store.hpp"
namespace MWWorld namespace MWWorld

View file

@ -111,11 +111,16 @@ namespace
std::string model = getModel(ptr); std::string model = getModel(ptr);
const auto rotation = makeDirectNodeRotation(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<SceneUtil::PositionAttitudeTransform> pagedNode(
new SceneUtil::PositionAttitudeTransform);
ESM::RefNum refnum = ptr.getCellRef().getRefNum(); ESM::RefNum refnum = ptr.getCellRef().getRefNum();
if (!refnum.hasContentFile() || !std::binary_search(pagedRefs.begin(), pagedRefs.end(), refnum)) if (!refnum.hasContentFile() || !std::binary_search(pagedRefs.begin(), pagedRefs.end(), refnum))
ptr.getClass().insertObjectRendering(ptr, model, rendering); ptr.getClass().insertObjectRendering(ptr, model, rendering);
else else
ptr.getRefData().setBaseNode(nullptr); ptr.getRefData().setBaseNode(pagedNode);
setNodeRotation(ptr, rendering, rotation); setNodeRotation(ptr, rendering, rotation);
if (ptr.getClass().useAnim()) if (ptr.getClass().useAnim())

View file

@ -195,21 +195,19 @@ namespace MWWorld
mThunderSoundID[3] mThunderSoundID[3]
= ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Thunder_Sound_ID_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 if (!mRainEffect.empty()) // NOTE: in vanilla, the weathers with rain seem to be hardcoded; changing
// Using_Precip has no effect // Using_Precip has no effect
{ {
mAmbientLoopSoundID mRainLoopSoundID
= ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Rain_Loop_Sound_ID")); = ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Rain_Loop_Sound_ID"));
if (mAmbientLoopSoundID.empty()) // default to "rain" if not set if (mRainLoopSoundID.empty()) // default to "rain" if not set
mAmbientLoopSoundID = ESM::RefId::stringRefId("rain"); mRainLoopSoundID = ESM::RefId::stringRefId("rain");
else if (mRainLoopSoundID == "None")
mRainLoopSoundID = ESM::RefId();
} }
else
mAmbientLoopSoundID mAmbientLoopSoundID
= ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Ambient_Loop_Sound_ID")); = ESM::RefId::stringRefId(Fallback::Map::getString("Weather_" + name + "_Ambient_Loop_Sound_ID"));
if (mAmbientLoopSoundID == "None") if (mAmbientLoopSoundID == "None")
mAmbientLoopSoundID = ESM::RefId(); mAmbientLoopSoundID = ESM::RefId();
} }
@ -552,8 +550,6 @@ namespace MWWorld
, mQueuedWeather(0) , mQueuedWeather(0)
, mRegions() , mRegions()
, mResult() , mResult()
, mAmbientSound(nullptr)
, mPlayingSoundID()
{ {
mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration;
mTimeSettings.mNightEnd = mSunriseTime; mTimeSettings.mNightEnd = mSunriseTime;
@ -794,24 +790,52 @@ namespace MWWorld
mRendering.getSkyManager()->setWeather(mResult); mRendering.getSkyManager()->setWeather(mResult);
// Play sounds // 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()) if (!mResult.mAmbientLoopSoundID.empty())
mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID,
mResult.mAmbientSoundVolume, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::Loop); mResult.mAmbientSoundVolume, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::Loop);
mPlayingSoundID = mResult.mAmbientLoopSoundID; mPlayingAmbientSoundID = mResult.mAmbientLoopSoundID;
} }
else if (mAmbientSound) else if (mAmbientSound)
mAmbientSound->setVolume(mResult.mAmbientSoundVolume); 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() void WeatherManager::stopSounds()
{ {
if (mAmbientSound) if (mAmbientSound)
{
MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound);
mAmbientSound = nullptr; mAmbientSound = nullptr;
mPlayingSoundID = ESM::RefId(); }
mPlayingAmbientSoundID = ESM::RefId();
if (mRainSound)
{
MWBase::Environment::get().getSoundManager()->stopSound(mRainSound);
mRainSound = nullptr;
}
mPlayingRainSoundID = ESM::RefId();
} }
float WeatherManager::getWindSpeed() const float WeatherManager::getWindSpeed() const
@ -1118,6 +1142,7 @@ namespace MWWorld
mResult.mCloudSpeed = current.mCloudSpeed; mResult.mCloudSpeed = current.mCloudSpeed;
mResult.mGlareView = current.mGlareView; mResult.mGlareView = current.mGlareView;
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
mResult.mRainLoopSoundID = current.mRainLoopSoundID;
mResult.mAmbientSoundVolume = 1.f; mResult.mAmbientSoundVolume = 1.f;
mResult.mPrecipitationAlpha = 1.f; mResult.mPrecipitationAlpha = 1.f;
@ -1237,6 +1262,7 @@ namespace MWWorld
mResult.mAmbientSoundVolume = 1.f - factor / threshold; mResult.mAmbientSoundVolume = 1.f - factor / threshold;
mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume; mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume;
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
mResult.mRainLoopSoundID = current.mRainLoopSoundID;
mResult.mRainDiameter = current.mRainDiameter; mResult.mRainDiameter = current.mRainDiameter;
mResult.mRainMinHeight = current.mRainMinHeight; mResult.mRainMinHeight = current.mRainMinHeight;
mResult.mRainMaxHeight = current.mRainMaxHeight; mResult.mRainMaxHeight = current.mRainMaxHeight;
@ -1252,6 +1278,7 @@ namespace MWWorld
mResult.mAmbientSoundVolume = (factor - threshold) / (1 - threshold); mResult.mAmbientSoundVolume = (factor - threshold) / (1 - threshold);
mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume; mResult.mPrecipitationAlpha = mResult.mAmbientSoundVolume;
mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID;
mResult.mRainLoopSoundID = other.mRainLoopSoundID;
mResult.mRainDiameter = other.mRainDiameter; mResult.mRainDiameter = other.mRainDiameter;
mResult.mRainMinHeight = other.mRainMinHeight; mResult.mRainMinHeight = other.mRainMinHeight;

View file

@ -156,9 +156,11 @@ namespace MWWorld
float FogOffset; float FogOffset;
} mDL; } mDL;
// Sound effect // Sound effects
// This is used for Blight, Ashstorm and Blizzard (Bloodmoon) // This is used for Blight, Ashstorm and Blizzard (Bloodmoon)
ESM::RefId mAmbientLoopSoundID; 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: // 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. // - The particles and clouds will be oriented so they appear to come from the Red Mountain.
@ -369,8 +371,10 @@ namespace MWWorld
std::map<ESM::RefId, RegionWeather> mRegions; std::map<ESM::RefId, RegionWeather> mRegions;
MWRender::WeatherResult mResult; MWRender::WeatherResult mResult;
MWBase::Sound* mAmbientSound; MWBase::Sound* mAmbientSound{ nullptr };
ESM::RefId mPlayingSoundID; ESM::RefId mPlayingAmbientSoundID;
MWBase::Sound* mRainSound{ nullptr };
ESM::RefId mPlayingRainSoundID;
void addWeather( void addWeather(
const std::string& name, float dlFactor, float dlOffset, const std::string& particleEffect = ""); const std::string& name, float dlFactor, float dlOffset, const std::string& particleEffect = "");

View file

@ -1,4 +1,5 @@
#include "apps/openmw/mwdialogue/keywordsearch.hpp" #include "apps/openmw/mwdialogue/keywordsearch.hpp"
#include <gtest/gtest.h> #include <gtest/gtest.h>
struct KeywordSearchTest : public ::testing::Test struct KeywordSearchTest : public ::testing::Test

View file

@ -1,4 +1,5 @@
#include <apps/openmw/options.hpp> #include "apps/openmw/options.hpp"
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp> #include <components/files/conversion.hpp>

View file

@ -2,12 +2,15 @@
#include "esmfile.hpp" #include "esmfile.hpp"
#include <fstream> #include <fstream>
#include <memory>
#include <stdexcept> #include <stdexcept>
#include <unordered_set> #include <unordered_set>
#include <QDataStream>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QFont> #include <QFont>
#include <QIODevice>
#include <components/esm/format.hpp> #include <components/esm/format.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
@ -127,7 +130,7 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex& index
continue; continue;
noGameFiles = false; noGameFiles = false;
if (isChecked(depFile->filePath())) if (mCheckedFiles.contains(depFile))
{ {
gamefileChecked = true; gamefileChecked = true;
break; break;
@ -214,7 +217,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
if (file == mGameFile) if (file == mGameFile)
return QVariant(); return QVariant();
return mCheckStates[file->filePath()]; return mCheckedFiles.contains(file) ? Qt::Checked : Qt::Unchecked;
} }
case Qt::UserRole: case Qt::UserRole:
@ -228,7 +231,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex& index, int
} }
case Qt::UserRole + 1: case Qt::UserRole + 1:
return isChecked(file->filePath()); return mCheckedFiles.contains(file);
} }
return QVariant(); return QVariant();
} }
@ -276,12 +279,12 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex& index, const
{ {
int checkValue = value.toInt(); int checkValue = value.toInt();
bool setState = false; bool setState = false;
if ((checkValue == Qt::Checked) && !isChecked(file->filePath())) if (checkValue == Qt::Checked && !mCheckedFiles.contains(file))
{ {
setState = true; setState = true;
success = true; success = true;
} }
else if ((checkValue == Qt::Checked) && isChecked(file->filePath())) else if (checkValue == Qt::Checked && mCheckedFiles.contains(file))
setState = true; setState = true;
else if (checkValue == Qt::Unchecked) else if (checkValue == Qt::Unchecked)
setState = true; 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) bool ContentSelectorModel::ContentModel::insertRows(int position, int rows, const QModelIndex& parent)
{ {
if (parent.isValid())
return false; return false;
beginInsertRows(parent, position, position + rows - 1);
{
for (int row = 0; row < rows; ++row)
mFiles.insert(position, new EsmFile);
}
endInsertRows();
return true;
} }
bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, const QModelIndex& parent) bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, const QModelIndex& parent)
{ {
if (parent.isValid())
return false; 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;
} }
Qt::DropActions ContentSelectorModel::ContentModel::supportedDropActions() const Qt::DropActions ContentSelectorModel::ContentModel::supportedDropActions() const
@ -357,13 +338,14 @@ QStringList ContentSelectorModel::ContentModel::mimeTypes() const
QMimeData* ContentSelectorModel::ContentModel::mimeData(const QModelIndexList& indexes) const QMimeData* ContentSelectorModel::ContentModel::mimeData(const QModelIndexList& indexes) const
{ {
QByteArray encodedData; QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const QModelIndex& index : indexes) for (const QModelIndex& index : indexes)
{ {
if (!index.isValid()) if (!index.isValid())
continue; continue;
encodedData.append(item(index.row())->encodedData()); stream << index.row();
} }
QMimeData* mimeData = new QMimeData(); QMimeData* mimeData = new QMimeData();
@ -395,26 +377,31 @@ bool ContentSelectorModel::ContentModel::dropMimeData(
QByteArray encodedData = data->data(mMimeType); QByteArray encodedData = data->data(mMimeType);
QDataStream stream(&encodedData, QIODevice::ReadOnly); QDataStream stream(&encodedData, QIODevice::ReadOnly);
std::vector<EsmFile*> toMove;
while (!stream.atEnd()) while (!stream.atEnd())
{ {
int sourceRow;
QString value; stream >> sourceRow;
QStringList values; toMove.emplace_back(mFiles.at(sourceRow));
QStringList gamefiles; }
int minRow = mFiles.size();
for (int i = 0; i < EsmFile::FileProperty_GameFile; ++i) int maxRow = 0;
for (EsmFile* file : toMove)
{ {
stream >> value; int from = mFiles.indexOf(file);
values << value; 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);
} }
stream >> gamefiles; dataChanged(index(minRow, 0), index(maxRow, 0));
// at this point we know that drag and drop has finished.
insertRows(beginRow, 1); checkForLoadOrderErrors();
QModelIndex idx = index(beginRow++, 0, QModelIndex());
setData(idx, QStringList() << values << gamefiles, Qt::EditRole);
}
return true; return true;
} }
@ -447,26 +434,37 @@ void ContentSelectorModel::ContentModel::addFiles(const QString& path, bool newf
{ {
QFileInfo info(dir.absoluteFilePath(path2)); QFileInfo info(dir.absoluteFilePath(path2));
if (item(info.fileName()))
continue;
// Enabled by default in system openmw.cfg; shouldn't be shown in content list. // Enabled by default in system openmw.cfg; shouldn't be shown in content list.
if (info.fileName().compare("builtin.omwscripts", Qt::CaseInsensitive) == 0) if (info.fileName().compare("builtin.omwscripts", Qt::CaseInsensitive) == 0)
continue; continue;
EsmFile* file = const_cast<EsmFile*>(item(info.fileName()));
bool add = file == nullptr;
std::unique_ptr<EsmFile> newFile;
if (add)
{
newFile = std::make_unique<EsmFile>(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)) if (info.fileName().endsWith(".omwscripts", Qt::CaseInsensitive))
{ {
EsmFile* file = new EsmFile(path2);
file->setDate(info.lastModified()); file->setDate(info.lastModified());
file->setFilePath(info.absoluteFilePath()); file->setFilePath(info.absoluteFilePath());
addFile(file); if (add)
addFile(newFile.release());
setNew(file->fileName(), newfiles); setNew(file->fileName(), newfiles);
continue; continue;
} }
try try
{ {
EsmFile* file = new EsmFile(path2);
file->setDate(info.lastModified()); file->setDate(info.lastModified());
file->setFilePath(info.absoluteFilePath()); file->setFilePath(info.absoluteFilePath());
std::filesystem::path filepath = Files::pathFromQString(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 // Put the file in the table
addFile(file); if (add)
addFile(newFile.release());
setNew(file->fileName(), newfiles); setNew(file->fileName(), newfiles);
} }
catch (std::runtime_error& e) catch (std::runtime_error& e)
{ {
// An error occurred while reading the .esp // An error occurred while reading the .esp
qWarning() << "Error reading addon file: " << e.what(); qWarning() << "Error reading addon file: " << e.what();
continue;
} }
} }
} }
@ -554,6 +552,7 @@ void ContentSelectorModel::ContentModel::clearFiles()
if (filesCount > 0) if (filesCount > 0)
{ {
beginRemoveRows(QModelIndex(), 0, filesCount - 1); beginRemoveRows(QModelIndex(), 0, filesCount - 1);
qDeleteAll(mFiles);
mFiles.clear(); mFiles.clear();
endRemoveRows(); endRemoveRows();
} }
@ -616,14 +615,6 @@ void ContentSelectorModel::ContentModel::sortFiles()
emit layoutChanged(); 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 bool ContentSelectorModel::ContentModel::isEnabled(const QModelIndex& index) const
{ {
return (flags(index) & Qt::ItemIsEnabled); return (flags(index) & Qt::ItemIsEnabled);
@ -684,7 +675,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors()
{ {
for (int row = 0; row < mFiles.count(); ++row) for (int row = 0; row < mFiles.count(); ++row)
{ {
EsmFile* file = item(row); EsmFile* file = mFiles.at(row);
bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0; bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0;
if (isRowInError) if (isRowInError)
{ {
@ -711,7 +702,7 @@ QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::
} }
else else
{ {
if (!isChecked(dependentFile->filePath())) if (!mCheckedFiles.contains(dependentFile))
{ {
errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName));
} }
@ -761,19 +752,18 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath,
if (!file) if (!file)
return false; return false;
Qt::CheckState state = Qt::Unchecked;
if (checkState) if (checkState)
state = Qt::Checked; mCheckedFiles.insert(file);
else
mCheckedFiles.erase(file);
mCheckStates[filepath] = state;
emit dataChanged(indexFromItem(item(filepath)), indexFromItem(item(filepath))); emit dataChanged(indexFromItem(item(filepath)), indexFromItem(item(filepath)));
if (file->isGameFile()) if (file->isGameFile())
refreshModel(); refreshModel();
// if we're checking an item, ensure all "upstream" files (dependencies) are checked as well. // 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()) for (const QString& upstreamName : file->gameFiles())
{ {
@ -782,14 +772,13 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath,
if (!upstreamFile) if (!upstreamFile)
continue; continue;
if (!isChecked(upstreamFile->filePath())) mCheckedFiles.insert(upstreamFile);
mCheckStates[upstreamFile->filePath()] = Qt::Checked;
emit dataChanged(indexFromItem(upstreamFile), indexFromItem(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. // 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) for (const EsmFile* downstreamFile : mFiles)
{ {
@ -798,8 +787,7 @@ bool ContentSelectorModel::ContentModel::setCheckState(const QString& filepath,
if (downstreamFile->gameFiles().contains(filename, Qt::CaseInsensitive)) if (downstreamFile->gameFiles().contains(filename, Qt::CaseInsensitive))
{ {
if (mCheckStates.contains(downstreamFile->filePath())) mCheckedFiles.erase(downstreamFile);
mCheckStates[downstreamFile->filePath()] = Qt::Unchecked;
emit dataChanged(indexFromItem(downstreamFile), indexFromItem(downstreamFile)); emit dataChanged(indexFromItem(downstreamFile), indexFromItem(downstreamFile));
} }
@ -817,7 +805,7 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke
// First search for game files and next addons, // First search for game files and next addons,
// so we get more or less correct game files vs addons order. // so we get more or less correct game files vs addons order.
for (EsmFile* file : mFiles) for (EsmFile* file : mFiles)
if (isChecked(file->filePath())) if (mCheckedFiles.contains(file))
list << file; list << file;
return list; return list;
@ -826,6 +814,6 @@ ContentSelectorModel::ContentFileList ContentSelectorModel::ContentModel::checke
void ContentSelectorModel::ContentModel::uncheckAll() void ContentSelectorModel::ContentModel::uncheckAll()
{ {
emit layoutAboutToBeChanged(); emit layoutAboutToBeChanged();
mCheckStates.clear(); mCheckedFiles.clear();
emit layoutChanged(); emit layoutChanged();
} }

View file

@ -7,6 +7,8 @@
#include <QSet> #include <QSet>
#include <QStringList> #include <QStringList>
#include <set>
namespace ContentSelectorModel namespace ContentSelectorModel
{ {
class EsmFile; class EsmFile;
@ -57,7 +59,6 @@ namespace ContentSelectorModel
void setCurrentGameFile(const EsmFile* file); void setCurrentGameFile(const EsmFile* file);
bool isEnabled(const QModelIndex& index) const; bool isEnabled(const QModelIndex& index) const;
bool isChecked(const QString& filepath) const;
bool setCheckState(const QString& filepath, bool isChecked); bool setCheckState(const QString& filepath, bool isChecked);
bool isNew(const QString& filepath) const; bool isNew(const QString& filepath) const;
void setNew(const QString& filepath, bool isChecked); void setNew(const QString& filepath, bool isChecked);
@ -85,7 +86,7 @@ namespace ContentSelectorModel
const EsmFile* mGameFile; const EsmFile* mGameFile;
ContentFileList mFiles; ContentFileList mFiles;
QStringList mArchives; QStringList mArchives;
QHash<QString, Qt::CheckState> mCheckStates; std::set<const EsmFile*> mCheckedFiles;
QHash<QString, bool> mNewFiles; QHash<QString, bool> mNewFiles;
QSet<QString> mPluginsWithLoadOrderError; QSet<QString> mPluginsWithLoadOrderError;
QString mEncoding; QString mEncoding;

View file

@ -1,10 +1,5 @@
#include "esmfile.hpp" #include "esmfile.hpp"
#include <QDataStream>
#include <QIODevice>
int ContentSelectorModel::EsmFile::sPropertyCount = 7;
ContentSelectorModel::EsmFile::EsmFile(const QString& fileName, ModelItem* parent) ContentSelectorModel::EsmFile::EsmFile(const QString& fileName, ModelItem* parent)
: ModelItem(parent) : ModelItem(parent)
, mFileName(fileName) , mFileName(fileName)
@ -46,17 +41,6 @@ void ContentSelectorModel::EsmFile::setDescription(const QString& description)
mDescription = 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 bool ContentSelectorModel::EsmFile::isGameFile() const
{ {
return (mGameFiles.size() == 0) return (mGameFiles.size() == 0)

View file

@ -30,15 +30,11 @@ namespace ContentSelectorModel
}; };
EsmFile(const QString& fileName = QString(), ModelItem* parent = nullptr); EsmFile(const QString& fileName = QString(), ModelItem* parent = nullptr);
// EsmFile(const EsmFile &);
~EsmFile() {}
void setFileProperty(const FileProperty prop, const QString& value); void setFileProperty(const FileProperty prop, const QString& value);
void setFileName(const QString& fileName); void setFileName(const QString& fileName);
void setAuthor(const QString& author); void setAuthor(const QString& author);
void setSize(const int size);
void setDate(const QDateTime& modified); void setDate(const QDateTime& modified);
void setFormat(const QString& format); void setFormat(const QString& format);
void setFilePath(const QString& path); void setFilePath(const QString& path);
@ -68,10 +64,6 @@ namespace ContentSelectorModel
} }
bool isGameFile() const; bool isGameFile() const;
QByteArray encodedData() const;
public:
static int sPropertyCount;
private: private:
QString mTooltipTemlate = tr( QString mTooltipTemlate = tr(

View file

@ -108,6 +108,7 @@ void ContentSelectorView::ContentSelector::buildAddonView()
connect(ui->addonView, &QTableView::activated, this, &ContentSelector::slotAddonTableItemActivated); connect(ui->addonView, &QTableView::activated, this, &ContentSelector::slotAddonTableItemActivated);
connect(mContentModel, &ContentSelectorModel::ContentModel::dataChanged, this, connect(mContentModel, &ContentSelectorModel::ContentModel::dataChanged, this,
&ContentSelector::signalAddonDataChanged); &ContentSelector::signalAddonDataChanged);
connect(mContentModel, &ContentSelectorModel::ContentModel::dataChanged, this, &ContentSelector::slotRowsMoved);
buildContextMenu(); buildContextMenu();
} }
@ -331,3 +332,8 @@ void ContentSelectorView::ContentSelector::slotSearchFilterTextChanged(const QSt
{ {
ui->addonView->setDragEnabled(newText.isEmpty()); ui->addonView->setDragEnabled(newText.isEmpty());
} }
void ContentSelectorView::ContentSelector::slotRowsMoved()
{
ui->addonView->selectionModel()->clearSelection();
}

View file

@ -85,6 +85,7 @@ namespace ContentSelectorView
void slotUncheckMultiSelectedItems(); void slotUncheckMultiSelectedItems();
void slotCopySelectedItemsPaths(); void slotCopySelectedItemsPaths();
void slotSearchFilterTextChanged(const QString& newText); void slotSearchFilterTextChanged(const QString& newText);
void slotRowsMoved();
}; };
} }

View file

@ -189,42 +189,18 @@ namespace DetourNavigator
void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType) void RecastMeshBuilder::addObject(const btBoxShape& shape, const btTransform& transform, const AreaType areaType)
{ {
constexpr std::array<int, 36> indices{ { constexpr std::array<int, 36> indices{ {
0, 0, 2, 3, // triangle 0
2, 3, 1, 0, // triangle 1
3, 0, 4, 6, // triangle 2
3, 6, 2, 0, // triangle 3
1, 0, 1, 5, // triangle 4
0, 5, 4, 0, // triangle 5
0, 7, 5, 1, // triangle 6
4, 1, 3, 7, // triangle 7
6, 7, 3, 2, // triangle 8
6, 2, 6, 7, // triangle 9
2, 7, 6, 4, // triangle 10
0, 4, 5, 7, // triangle 11
0,
1,
5,
5,
4,
0,
7,
5,
1,
1,
3,
7,
7,
3,
2,
2,
6,
7,
7,
6,
4,
4,
5,
7,
} }; } };
for (std::size_t i = 0; i < indices.size(); i += 3) for (std::size_t i = 0; i < indices.size(); i += 3)

View file

@ -47,6 +47,7 @@ namespace DetourNavigator
return position; return position;
} }
// Returns value in NavMesh coordinates
inline float getTileSize(const RecastSettings& settings) inline float getTileSize(const RecastSettings& settings)
{ {
return static_cast<float>(settings.mTileSize) * settings.mCellSize; return static_cast<float>(settings.mTileSize) * settings.mCellSize;
@ -62,16 +63,19 @@ namespace DetourNavigator
return static_cast<int>(v); return static_cast<int>(v);
} }
// Returns integer tile position for position in navmesh coordinates
inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec2f& position) inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec2f& position)
{ {
return TilePosition(getTilePosition(settings, position.x()), getTilePosition(settings, position.y())); 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) inline TilePosition getTilePosition(const RecastSettings& settings, const osg::Vec3f& position)
{ {
return getTilePosition(settings, osg::Vec2f(position.x(), position.z())); return getTilePosition(settings, osg::Vec2f(position.x(), position.z()));
} }
// Returns tile bounds in navmesh coordinates
inline TileBounds makeTileBounds(const RecastSettings& settings, const TilePosition& tilePosition) inline TileBounds makeTileBounds(const RecastSettings& settings, const TilePosition& tilePosition)
{ {
return TileBounds{ return TileBounds{
@ -80,6 +84,7 @@ namespace DetourNavigator
}; };
} }
// Returns border size relative to cell size
inline float getBorderSize(const RecastSettings& settings) inline float getBorderSize(const RecastSettings& settings)
{ {
return static_cast<float>(settings.mBorderSize) * settings.mCellSize; return static_cast<float>(settings.mBorderSize) * settings.mCellSize;
@ -95,6 +100,7 @@ namespace DetourNavigator
return std::floor(std::sqrt(settings.mMaxTilesNumber / osg::PI)) - 1; 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) inline TileBounds makeRealTileBoundsWithBorder(const RecastSettings& settings, const TilePosition& tilePosition)
{ {
TileBounds result = makeTileBounds(settings, tilePosition); TileBounds result = makeTileBounds(settings, tilePosition);

View file

@ -288,6 +288,7 @@ namespace LuaUi
auto children = parent->children(); auto children = parent->children();
auto it = std::find(children.begin(), children.end(), mRoot); auto it = std::find(children.begin(), children.end(), mRoot);
mRoot = createWidget(layout(), 0); mRoot = createWidget(layout(), 0);
assert(it != children.end());
*it = mRoot; *it = mRoot;
parent->setChildren(children); parent->setChildren(children);
mRoot->updateCoord(); mRoot->updateCoord();

View file

@ -315,8 +315,7 @@ namespace Stereo
else else
{ {
auto* ds = osg::DisplaySettings::instance().get(); auto* ds = osg::DisplaySettings::instance().get();
auto viewMatrix = mMainCamera->getViewMatrix(); const auto& projectionMatrix = mMainCamera->getProjectionMatrix();
auto projectionMatrix = mMainCamera->getProjectionMatrix();
auto s = ds->getEyeSeparation() * Constants::UnitsPerMeter; auto s = ds->getEyeSeparation() * Constants::UnitsPerMeter;
mViewOffsetMatrix[0] 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); = 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);

View file

@ -682,7 +682,6 @@
--- ---
-- @type ActiveEffect -- @type ActiveEffect
-- Magic effect that is currently active on an actor. -- 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 affectedSkill Optional skill ID
-- @field #string affectedAttribute Optional attribute ID -- @field #string affectedAttribute Optional attribute ID
-- @field #string id Effect id string -- @field #string id Effect id string

View file

@ -210,14 +210,14 @@
-- end -- end
-- @usage -- Check for a specific effect -- @usage -- Check for a specific effect
-- local effect = Actor.activeEffects(self):getEffect(core.magic.EFFECT_TYPE.Telekinesis) -- 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)) -- print(effect.id..', attribute='..tostring(effect.affectedAttribute)..', skill='..tostring(effect.affectedSkill)..', magnitude='..tostring(effect.magnitude))
-- else -- else
-- print('No Telekinesis effect') -- print('No Telekinesis effect')
-- end -- end
-- @usage -- Check for a specific effect targeting a specific attribute. -- @usage -- Check for a specific effect targeting a specific attribute.
-- local effect = Actor.activeEffects(self):getEffect(core.magic.EFFECT_TYPE.FortifyAttribute, core.ATTRIBUTE.Luck) -- 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)) -- print(effect.id..', attribute='..tostring(effect.affectedAttribute)..', skill='..tostring(effect.affectedSkill)..', magnitude='..tostring(effect.magnitude))
-- else -- else
-- print('No Fortify Luck effect') -- print('No Fortify Luck effect')
@ -229,7 +229,7 @@
-- @param self -- @param self
-- @param #string effectId effect ID -- @param #string effectId effect ID
-- @param #string extraParam Optional skill or attribute 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. -- Completely removes the active effect from the actor.