1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-04-01 11:06:41 +00:00

Merge branch 'master' of https://gitlab.com/madsbuvi/openmw.git into openxr_vr

# Conflicts:
#	apps/openmw/mwbase/world.hpp
#	apps/openmw/mwworld/worldimp.cpp
#	apps/openmw/mwworld/worldimp.hpp
This commit is contained in:
Mads Buvik Sandvei 2020-03-30 01:37:29 +02:00
commit 14bb0f0208
244 changed files with 2757 additions and 1224 deletions
.travis.ymlAUTHORS.mdCHANGELOG.mdCHANGELOG_PR.md
CI
apps

View file

@ -9,19 +9,15 @@ env:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key # via the "travis encrypt" command using the project repo's public key
- secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE=" - secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE="
cache: cache: ccache
ccache: true
directories:
- ${HOME}/.ccache
addons: addons:
apt: apt:
sources: sources:
- sourceline: 'ppa:openmw/openmw' - sourceline: 'ppa:openmw/openmw'
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-xenial-7
packages: [ packages: [
# Dev # Dev
cmake, clang-7, clang-tools-7, gcc-8, g++-8, ccache, cmake, clang-tools, gcc-9, g++-9, ccache,
# Boost # Boost
libboost-filesystem-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-system-dev, libboost-filesystem-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-system-dev,
# FFmpeg # FFmpeg
@ -45,50 +41,51 @@ matrix:
os: osx os: osx
osx_image: xcode10.2 osx_image: xcode10.2
if: branch != coverity_scan if: branch != coverity_scan
- name: OpenMW (all) on Ubuntu Xenial GCC-5 - name: OpenMW (all) on Ubuntu Bionic GCC-7
os: linux os: linux
dist: xenial dist: bionic
sudo: required sudo: required
if: branch != coverity_scan if: branch != coverity_scan
- name: OpenMW (all) on Ubuntu Xenial GCC-8 - name: OpenMW (all) on Ubuntu Bionic GCC-9
os: linux os: linux
dist: xenial dist: bionic
sudo: required sudo: required
env: env:
- MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9"
if: branch != coverity_scan if: branch != coverity_scan
- name: OpenMW (openmw) on Ubuntu Xenial Clang-7 with Static Analysis - name: OpenMW (openmw) on Ubuntu Bionic Clang-6 with Static Analysis
os: linux os: linux
dist: xenial dist: bionic
sudo: required sudo: required
env: env:
- MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" - MATRIX_EVAL="CC=clang && CXX=clang++"
- ANALYZE="scan-build-7 --force-analyze-debug-code --use-cc clang-7 --use-c++ clang++-7" - ANALYZE="scan-build --force-analyze-debug-code --use-cc clang --use-c++ clang++"
- BUILD_OPENMW_CS="OFF" - BUILD_OPENMW_CS="OFF"
if: branch != coverity_scan if: branch != coverity_scan
compiler: clang compiler: clang
- name: OpenMW (openmw-cs) on Ubuntu Xenial Clang-7 with Static Analysis - name: OpenMW (openmw-cs) on Ubuntu Bionic Clang-6 with Static Analysis
os: linux os: linux
dist: xenial dist: bionic
sudo: required sudo: required
env: env:
- MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" - MATRIX_EVAL="CC=clang && CXX=clang++"
- ANALYZE="scan-build-7 --force-analyze-debug-code --use-cc clang-7 --use-c++ clang++-7" - ANALYZE="scan-build --force-analyze-debug-code --use-cc clang --use-c++ clang++"
- BUILD_OPENMW="OFF" - BUILD_OPENMW="OFF"
if: branch != coverity_scan if: branch != coverity_scan
compiler: clang compiler: clang
- name: OpenMW Components Coverity Scan - name: OpenMW Components Coverity Scan
os: linux os: linux
dist: xenial dist: bionic
sudo: required sudo: required
if: branch = coverity_scan if: branch = coverity_scan
# allow_failures: # allow_failures:
# - name: OpenMW (openmw) on Ubuntu Xenial Clang-7 with Static Analysis # - name: OpenMW (openmw) on Ubuntu Bionic Clang-6 with Static Analysis
before_install: before_install:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then eval "${MATRIX_EVAL}"; fi - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then eval "${MATRIX_EVAL}"; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_install.${TRAVIS_OS_NAME}.sh; fi - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_install.${TRAVIS_OS_NAME}.sh; fi
before_script: before_script:
- ccache -z
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_script.${TRAVIS_OS_NAME}.sh; fi - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then ./CI/before_script.${TRAVIS_OS_NAME}.sh; fi
script: script:
- cd ./build - cd ./build
@ -98,6 +95,7 @@ script:
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
- if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi - if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
- cd "${TRAVIS_BUILD_DIR}" - cd "${TRAVIS_BUILD_DIR}"
- ccache -s
deploy: deploy:
provider: script provider: script
script: ./CI/deploy.osx.sh script: ./CI/deploy.osx.sh

View file

@ -74,6 +74,7 @@ Programmers
Fil Krynicki (filkry) Fil Krynicki (filkry)
Finbar Crago(finbar-crago) Finbar Crago(finbar-crago)
Florian Weber (Florianjw) Florian Weber (Florianjw)
Frédéric Chardon (fr3dz10)
Gaëtan Dezeiraud (Brouilles) Gaëtan Dezeiraud (Brouilles)
Gašper Sedej Gašper Sedej
Gijsbert ter Horst (Ghostbird) Gijsbert ter Horst (Ghostbird)
@ -87,6 +88,7 @@ Programmers
Jacob Essex (Yacoby) Jacob Essex (Yacoby)
Jake Westrip (16bitint) Jake Westrip (16bitint)
James Carty (MrTopCat) James Carty (MrTopCat)
James Moore (moore.work)
James Stephens (james-h-stephens) James Stephens (james-h-stephens)
Jan-Peter Nilsson (peppe) Jan-Peter Nilsson (peppe)
Jan Borsodi (am0s) Jan Borsodi (am0s)

View file

@ -23,6 +23,7 @@
Bug #3977: Non-ASCII characters in object ID's are not supported Bug #3977: Non-ASCII characters in object ID's are not supported
Bug #4009: Launcher does not show data files on the first run after installing Bug #4009: Launcher does not show data files on the first run after installing
Bug #4077: Enchanted items are not recharged if they are not in the player's inventory Bug #4077: Enchanted items are not recharged if they are not in the player's inventory
Bug #4141: PCSkipEquip isn't set to 1 when reading books/scrolls
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
Bug #4262: Rain settings are hardcoded Bug #4262: Rain settings are hardcoded
@ -36,10 +37,13 @@
Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4411: Reloading a saved game while falling prevents damage in some cases
Bug #4449: Value returned by GetWindSpeed is incorrect Bug #4449: Value returned by GetWindSpeed is incorrect
Bug #4456: AiActivate should not be cancelled after target activation Bug #4456: AiActivate should not be cancelled after target activation
Bug #4493: If the setup doesn't find what it is expecting, it fails silently and displays the requester again instead of letting the user know what wasn't found.
Bug #4523: "player->ModCurrentFatigue -0.001" in global script does not cause the running player to fall
Bug #4540: Rain delay when exiting water Bug #4540: Rain delay when exiting water
Bug #4594: Actors without AI packages don't use Hello dialogue Bug #4594: Actors without AI packages don't use Hello dialogue
Bug #4598: Script parser does not support non-ASCII characters Bug #4598: Script parser does not support non-ASCII characters
Bug #4600: Crash when no sound output is available or --no-sound is used. Bug #4600: Crash when no sound output is available or --no-sound is used.
Bug #4601: Filtering referenceables by gender is broken
Bug #4639: Black screen after completing first mages guild mission + training Bug #4639: Black screen after completing first mages guild mission + training
Bug #4650: Focus is lost after pressing ESC in confirmation dialog inside savegame dialog Bug #4650: Focus is lost after pressing ESC in confirmation dialog inside savegame dialog
Bug #4680: Heap corruption on faulty esp Bug #4680: Heap corruption on faulty esp
@ -192,9 +196,19 @@
Bug #5239: OpenMW-CS does not support non-ASCII characters in path names Bug #5239: OpenMW-CS does not support non-ASCII characters in path names
Bug #5241: On-self absorb spells cannot be detected Bug #5241: On-self absorb spells cannot be detected
Bug #5242: ExplodeSpell behavior differs from Cast behavior Bug #5242: ExplodeSpell behavior differs from Cast behavior
Bug #5246: Water ripples persist after cell change
Bug #5249: Wandering NPCs start walking too soon after they hello Bug #5249: Wandering NPCs start walking too soon after they hello
Bug #5250: Creatures display shield ground mesh instead of shield body part Bug #5250: Creatures display shield ground mesh instead of shield body part
Bug #5255: "GetTarget, player" doesn't return 1 during NPC hello Bug #5255: "GetTarget, player" doesn't return 1 during NPC hello
Bug #5261: Creatures can sometimes become stuck playing idles and never wander again
Bug #5264: "Damage Fatigue" Magic Effect Can Bring Fatigue below 0
Bug #5269: Editor: Cell lighting in resaved cleaned content files is corrupted
Bug #5278: Console command Show doesn't fall back to global variable after local var not found
Bug #5300: NPCs don't switch from torch to shield when starting combat
Bug #5308: World map copying makes save loading much slower
Bug #5313: Node properties of identical type are not applied in the correct order
Bug #5326: Formatting issues in the settings.cfg
Bug #5328: Skills aren't properly reset for dead actors
Feature #1774: Handle AvoidNode Feature #1774: Handle AvoidNode
Feature #2229: Improve pathfinding AI Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls Feature #3025: Analogue gamepad movement controls
@ -215,9 +229,11 @@
Feature #4544: Actors movement deceleration Feature #4544: Actors movement deceleration
Feature #4673: Weapon sheathing Feature #4673: Weapon sheathing
Feature #4675: Support for NiRollController Feature #4675: Support for NiRollController
Feature #4708: Radial fog support
Feature #4730: Native animated containers support Feature #4730: Native animated containers support
Feature #4784: Launcher: Duplicate Content Lists Feature #4784: Launcher: Duplicate Content Lists
Feature #4812: Support NiSwitchNode Feature #4812: Support NiSwitchNode
Feature #4831: Item search in the player's inventory
Feature #4836: Daytime node switch Feature #4836: Daytime node switch
Feature #4840: Editor: Transient terrain change support Feature #4840: Editor: Transient terrain change support
Feature #4859: Make water reflections more configurable Feature #4859: Make water reflections more configurable
@ -240,6 +256,7 @@
Feature #5091: Human-readable light source duration Feature #5091: Human-readable light source duration
Feature #5094: Unix like console hotkeys Feature #5094: Unix like console hotkeys
Feature #5098: Allow user controller bindings Feature #5098: Allow user controller bindings
Feature #5114: Refresh launcher mod list
Feature #5121: Handle NiTriStrips and NiTriStripsData Feature #5121: Handle NiTriStrips and NiTriStripsData
Feature #5122: Use magic glow for enchanted arrows Feature #5122: Use magic glow for enchanted arrows
Feature #5131: Custom skeleton bones Feature #5131: Custom skeleton bones
@ -247,9 +264,13 @@
Feature #5146: Safe Dispose corpse Feature #5146: Safe Dispose corpse
Feature #5147: Show spell magicka cost in spell buying window Feature #5147: Show spell magicka cost in spell buying window
Feature #5170: Editor: Land shape editing, land selection Feature #5170: Editor: Land shape editing, land selection
Feature #5172: Editor: Delete instances/references with keypress in scene window
Feature #5193: Weapon sheathing Feature #5193: Weapon sheathing
Feature #5219: Impelement TestCells console command Feature #5219: Impelement TestCells console command
Feature #5224: Handle NiKeyframeController for NiTriShape Feature #5224: Handle NiKeyframeController for NiTriShape
Feature #5274: Editor: Keyboard shortcut to drop objects to ground/obstacle in scene view
Feature #5304: Morrowind-style bump-mapping
Feature #5314: Ingredient filter in the alchemy window
Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption Task #4695: Optimize Distant Terrain memory consumption
Task #4789: Optimize cell transitions Task #4789: Optimize cell transitions

View file

@ -42,6 +42,8 @@ New Editor Features:
- "Faction Ranks" table for "Faction" records (#4209) - "Faction Ranks" table for "Faction" records (#4209)
- Changes to height editing can be cancelled without changes to data (press esc to cancel) (#4840) - Changes to height editing can be cancelled without changes to data (press esc to cancel) (#4840)
- Land heightmap/shape editing and vertex selection (#5170) - Land heightmap/shape editing and vertex selection (#5170)
- Deleting instances with a keypress (#5172)
- Dropping objects with keyboard shortcuts (#5274)
Bug Fixes: Bug Fixes:
- The Mouse Wheel can now be used for key bindings (#2679) - The Mouse Wheel can now be used for key bindings (#2679)

View file

@ -1,4 +1,4 @@
#!/bin/bash -ex #!/bin/bash -ex
sudo ln -sf /usr/bin/clang-7 /usr/local/bin/clang #sudo ln -sf /usr/bin/clang-6 /usr/local/bin/clang
sudo ln -sf /usr/bin/clang++-7 /usr/local/bin/clang++ #sudo ln -sf /usr/bin/clang++-6 /usr/local/bin/clang++

View file

@ -7,9 +7,7 @@ GOOGLETEST_DIR="$(pwd)/googletest/build"
mkdir build mkdir build
cd build cd build
export CODE_COVERAGE=1
if [[ "${CC}" =~ "clang" ]]; then export CODE_COVERAGE=0; fi
if [[ -z "${BUILD_OPENMW}" ]]; then export BUILD_OPENMW=ON; fi if [[ -z "${BUILD_OPENMW}" ]]; then export BUILD_OPENMW=ON; fi
if [[ -z "${BUILD_OPENMW_CS}" ]]; then export BUILD_OPENMW_CS=ON; fi if [[ -z "${BUILD_OPENMW_CS}" ]]; then export BUILD_OPENMW_CS=ON; fi
@ -28,7 +26,6 @@ ${ANALYZE} cmake \
-DBUILD_WIZARD=${BUILD_OPENMW_CS} \ -DBUILD_WIZARD=${BUILD_OPENMW_CS} \
-DBUILD_NIFTEST=${BUILD_OPENMW_CS} \ -DBUILD_NIFTEST=${BUILD_OPENMW_CS} \
-DBUILD_MYGUI_PLUGIN=${BUILD_OPENMW_CS} \ -DBUILD_MYGUI_PLUGIN=${BUILD_OPENMW_CS} \
-DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} \
-DBUILD_UNITTESTS=1 \ -DBUILD_UNITTESTS=1 \
-DUSE_SYSTEM_TINYXML=1 \ -DUSE_SYSTEM_TINYXML=1 \
-DDESIRED_QT_VERSION=5 \ -DDESIRED_QT_VERSION=5 \

View file

@ -421,16 +421,16 @@ if [ -z $SKIP_DOWNLOAD ]; then
fi fi
download "Qt 5.7.0" \ download "Qt 5.7.0" \
"https://download.qt.io/archive/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \ "https://download.qt.io/new_archive/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \
"qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \ "qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \
"https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \ "https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \
"qt-5-install.qs" "qt-5-install.qs"
fi fi
# SDL2 # SDL2
download "SDL 2.0.7" \ download "SDL 2.0.12" \
"https://www.libsdl.org/release/SDL2-devel-2.0.7-VC.zip" \ "https://www.libsdl.org/release/SDL2-devel-2.0.12-VC.zip" \
"SDL2-2.0.7.zip" "SDL2-2.0.12.zip"
# Google test and mock # Google test and mock
if [ ! -z $TEST_FRAMEWORK ]; then if [ ! -z $TEST_FRAMEWORK ]; then
@ -697,16 +697,16 @@ fi
cd $DEPS cd $DEPS
echo echo
# SDL2 # SDL2
printf "SDL 2.0.7... " printf "SDL 2.0.12... "
{ {
if [ -d SDL2-2.0.7 ]; then if [ -d SDL2-2.0.12 ]; then
printf "Exists. " printf "Exists. "
elif [ -z $SKIP_EXTRACT ]; then elif [ -z $SKIP_EXTRACT ]; then
rm -rf SDL2-2.0.7 rm -rf SDL2-2.0.12
eval 7z x -y SDL2-2.0.7.zip $STRIP eval 7z x -y SDL2-2.0.12.zip $STRIP
fi fi
export SDL2DIR="$(real_pwd)/SDL2-2.0.7" export SDL2DIR="$(real_pwd)/SDL2-2.0.12"
add_runtime_dlls "$(pwd)/SDL2-2.0.7/lib/x${ARCHSUFFIX}/SDL2.dll" add_runtime_dlls "$(pwd)/SDL2-2.0.12/lib/x${ARCHSUFFIX}/SDL2.dll"
echo Done. echo Done.
} }
cd $DEPS cd $DEPS

View file

@ -534,10 +534,18 @@ void Record<ESM::Cell>::print()
if (mData.mData.mFlags & ESM::Cell::Interior && if (mData.mData.mFlags & ESM::Cell::Interior &&
!(mData.mData.mFlags & ESM::Cell::QuasiEx)) !(mData.mData.mFlags & ESM::Cell::QuasiEx))
{ {
if (mData.hasAmbient())
{
// TODO: see if we can change the integer representation to something more sensible
std::cout << " Ambient Light Color: " << mData.mAmbi.mAmbient << std::endl; std::cout << " Ambient Light Color: " << mData.mAmbi.mAmbient << std::endl;
std::cout << " Sunlight Color: " << mData.mAmbi.mSunlight << std::endl; std::cout << " Sunlight Color: " << mData.mAmbi.mSunlight << std::endl;
std::cout << " Fog Color: " << mData.mAmbi.mFog << std::endl; std::cout << " Fog Color: " << mData.mAmbi.mFog << std::endl;
std::cout << " Fog Density: " << mData.mAmbi.mFogDensity << std::endl; std::cout << " Fog Density: " << mData.mAmbi.mFogDensity << std::endl;
}
else
{
std::cout << " No Ambient Information" << std::endl;
}
std::cout << " Water Level: " << mData.mWater << std::endl; std::cout << " Water Level: " << mData.mWater << std::endl;
} }
else else

View file

@ -89,6 +89,7 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game"); loadSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game"); loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
} }
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
// Input Settings // Input Settings
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input"); loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
@ -152,6 +153,7 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game"); saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game"); saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game"); saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
// Input Settings // Input Settings
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input"); saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");

View file

@ -62,10 +62,13 @@ void Launcher::DataFilesPage::buildView()
{ {
ui.verticalLayout->insertWidget (0, mSelector->uiWidget()); ui.verticalLayout->insertWidget (0, mSelector->uiWidget());
QToolButton * refreshButton = mSelector->refreshButton();
//tool buttons //tool buttons
ui.newProfileButton->setToolTip ("Create a new Content List"); ui.newProfileButton->setToolTip ("Create a new Content List");
ui.cloneProfileButton->setToolTip ("Clone the current Content List"); ui.cloneProfileButton->setToolTip ("Clone the current Content List");
ui.deleteProfileButton->setToolTip ("Delete an existing Content List"); ui.deleteProfileButton->setToolTip ("Delete an existing Content List");
refreshButton->setToolTip("Refresh Data Files");
//combo box //combo box
ui.profilesComboBox->addItem(mDefaultContentListName); ui.profilesComboBox->addItem(mDefaultContentListName);
@ -76,6 +79,7 @@ void Launcher::DataFilesPage::buildView()
ui.newProfileButton->setDefaultAction (ui.newProfileAction); ui.newProfileButton->setDefaultAction (ui.newProfileAction);
ui.cloneProfileButton->setDefaultAction (ui.cloneProfileAction); ui.cloneProfileButton->setDefaultAction (ui.cloneProfileAction);
ui.deleteProfileButton->setDefaultAction (ui.deleteProfileAction); ui.deleteProfileButton->setDefaultAction (ui.deleteProfileAction);
refreshButton->setDefaultAction(ui.refreshDataFilesAction);
//establish connections //establish connections
connect (ui.profilesComboBox, SIGNAL (currentIndexChanged(int)), connect (ui.profilesComboBox, SIGNAL (currentIndexChanged(int)),
@ -86,6 +90,8 @@ void Launcher::DataFilesPage::buildView()
connect (ui.profilesComboBox, SIGNAL (signalProfileChanged(QString, QString)), connect (ui.profilesComboBox, SIGNAL (signalProfileChanged(QString, QString)),
this, SLOT (slotProfileChangedByUser(QString, QString))); this, SLOT (slotProfileChangedByUser(QString, QString)));
connect(ui.refreshDataFilesAction, SIGNAL(triggered()),this, SLOT(slotRefreshButtonClicked()));
} }
bool Launcher::DataFilesPage::loadSettings() bool Launcher::DataFilesPage::loadSettings()
@ -114,6 +120,8 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
if (!mDataLocal.isEmpty()) if (!mDataLocal.isEmpty())
paths.insert(0, mDataLocal); paths.insert(0, mDataLocal);
mSelector->clearFiles();
for (const QString &path : paths) for (const QString &path : paths)
mSelector->addFiles(path); mSelector->addFiles(path);
@ -166,9 +174,18 @@ QStringList Launcher::DataFilesPage::selectedFilePaths()
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles(); ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
QStringList filePaths; QStringList filePaths;
for (const ContentSelectorModel::EsmFile *item : items) for (const ContentSelectorModel::EsmFile *item : items)
{
QFile file(item->filePath());
if(file.exists())
{ {
filePaths.append(item->filePath()); filePaths.append(item->filePath());
} }
else
{
slotRefreshButtonClicked();
}
}
return filePaths; return filePaths;
} }
@ -221,6 +238,18 @@ void Launcher::DataFilesPage::slotProfileDeleted (const QString &item)
removeProfile (item); removeProfile (item);
} }
void Launcher::DataFilesPage:: refreshDataFilesView ()
{
QString currentProfile = ui.profilesComboBox->currentText();
saveSettings(currentProfile);
populateFileViews(currentProfile);
}
void Launcher::DataFilesPage::slotRefreshButtonClicked ()
{
refreshDataFilesView();
}
void Launcher::DataFilesPage::slotProfileChangedByUser(const QString &previous, const QString &current) void Launcher::DataFilesPage::slotProfileChangedByUser(const QString &previous, const QString &current)
{ {
setProfile(previous, current, true); setProfile(previous, current, true);

View file

@ -61,6 +61,7 @@ namespace Launcher
void slotProfileRenamed(const QString &previous, const QString &current); void slotProfileRenamed(const QString &previous, const QString &current);
void slotProfileDeleted(const QString &item); void slotProfileDeleted(const QString &item);
void slotAddonDataChanged (); void slotAddonDataChanged ();
void slotRefreshButtonClicked ();
void updateNewProfileOkButton(const QString &text); void updateNewProfileOkButton(const QString &text);
void updateCloneProfileOkButton(const QString &text); void updateCloneProfileOkButton(const QString &text);
@ -100,6 +101,7 @@ namespace Launcher
void checkForDefaultProfile(); void checkForDefaultProfile();
void populateFileViews(const QString& contentModelName); void populateFileViews(const QString& contentModelName);
void reloadCells(QStringList selectedFiles); void reloadCells(QStringList selectedFiles);
void refreshDataFilesView ();
class PathIterator class PathIterator
{ {

View file

@ -97,10 +97,6 @@ opencs_units_noqt (view/render
cellarrow cellmarker cellborder pathgrid cellarrow cellmarker cellborder pathgrid
) )
opencs_hdrs_noqt (view/render
mask
)
opencs_units (view/tools opencs_units (view/tools
reportsubview reporttable searchsubview searchbox merge reportsubview reporttable searchsubview searchbox merge

View file

@ -355,6 +355,11 @@ void CSMPrefs::State::declare()
declareShortcut ("scene-select-secondary", "Secondary Select", declareShortcut ("scene-select-secondary", "Secondary Select",
QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift); declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift);
declareShortcut ("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete));
declareShortcut ("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G));
declareShortcut ("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H));
declareShortcut ("scene-instance-drop-terrain-separately", "Drop to terrain level separately", QKeySequence());
declareShortcut ("scene-instance-drop-collision-separately", "Drop to collision separately", QKeySequence());
declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5));
declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6));
declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8));

View file

@ -76,53 +76,6 @@ namespace CSMWorld
return false; return false;
} }
/* LandMapLodColumn */
LandMapLodColumn::LandMapLodColumn()
: Column<Land>(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0)
{
}
QVariant LandMapLodColumn::get(const Record<Land>& record) const
{
const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE;
const Land& land = record.get();
DataType values(Size, 0);
if (land.mDataTypes & Land::DATA_WNAM)
{
for (int i = 0; i < Size; ++i)
values[i] = land.mWnam[i];
}
QVariant variant;
variant.setValue(values);
return variant;
}
void LandMapLodColumn::set(Record<Land>& record, const QVariant& data)
{
DataType values = data.value<DataType>();
if (values.size() != Land::LAND_GLOBAL_MAP_LOD_SIZE)
throw std::runtime_error("invalid land map LOD data");
Land copy = record.get();
copy.add(Land::DATA_WNAM);
for (int i = 0; i < values.size(); ++i)
{
copy.mWnam[i] = values[i];
}
record.setModified(copy);
}
bool LandMapLodColumn::isEditable() const
{
return true;
}
/* LandNormalsColumn */ /* LandNormalsColumn */
LandNormalsColumn::LandNormalsColumn() LandNormalsColumn::LandNormalsColumn()
: Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) : Column<Land>(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0)

View file

@ -1770,7 +1770,7 @@ namespace CSMWorld
struct GenderNpcColumn : public Column<ESXRecordT> struct GenderNpcColumn : public Column<ESXRecordT>
{ {
GenderNpcColumn() GenderNpcColumn()
: Column<ESXRecordT>(Columns::ColumnId_GenderNpc, ColumnBase::Display_GenderNpc) : Column<ESXRecordT>(Columns::ColumnId_Gender, ColumnBase::Display_GenderNpc)
{} {}
virtual QVariant get(const Record<ESXRecordT>& record) const virtual QVariant get(const Record<ESXRecordT>& record) const
@ -2461,17 +2461,6 @@ namespace CSMWorld
bool isEditable() const override; bool isEditable() const override;
}; };
struct LandMapLodColumn : public Column<Land>
{
using DataType = QVector<signed char>;
LandMapLodColumn();
QVariant get(const Record<Land>& record) const override;
void set(Record<Land>& record, const QVariant& data) override;
bool isEditable() const override;
};
struct LandNormalsColumn : public Column<Land> struct LandNormalsColumn : public Column<Land>
{ {
using DataType = QVector<signed char>; using DataType = QVector<signed char>;
@ -2529,8 +2518,7 @@ namespace CSMWorld
} }
// This is required to access the type as a QVariant. // This is required to access the type as a QVariant.
Q_DECLARE_METATYPE(CSMWorld::LandMapLodColumn::DataType) Q_DECLARE_METATYPE(CSMWorld::LandNormalsColumn::DataType)
//Q_DECLARE_METATYPE(CSMWorld::LandNormalsColumn::DataType) // Same as LandMapLodColumn::DataType
Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType) Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType)
Q_DECLARE_METATYPE(CSMWorld::LandColoursColumn::DataType) Q_DECLARE_METATYPE(CSMWorld::LandColoursColumn::DataType)
Q_DECLARE_METATYPE(CSMWorld::LandTexturesColumn::DataType) Q_DECLARE_METATYPE(CSMWorld::LandTexturesColumn::DataType)

View file

@ -288,7 +288,6 @@ namespace CSMWorld
{ ColumnId_UChar, "Value [0..255]" }, { ColumnId_UChar, "Value [0..255]" },
{ ColumnId_NpcMisc, "NPC Misc" }, { ColumnId_NpcMisc, "NPC Misc" },
{ ColumnId_Level, "Level" }, { ColumnId_Level, "Level" },
{ ColumnId_GenderNpc, "Gender"},
{ ColumnId_Mana, "Mana" }, { ColumnId_Mana, "Mana" },
{ ColumnId_Fatigue, "Fatigue" }, { ColumnId_Fatigue, "Fatigue" },
{ ColumnId_NpcDisposition, "NPC Disposition" }, { ColumnId_NpcDisposition, "NPC Disposition" },

View file

@ -273,7 +273,7 @@ namespace CSMWorld
ColumnId_UChar = 250, ColumnId_UChar = 250,
ColumnId_NpcMisc = 251, ColumnId_NpcMisc = 251,
ColumnId_Level = 252, ColumnId_Level = 252,
ColumnId_GenderNpc = 254, // unused
ColumnId_Mana = 255, ColumnId_Mana = 255,
ColumnId_Fatigue = 256, ColumnId_Fatigue = 256,
ColumnId_NpcDisposition = 257, ColumnId_NpcDisposition = 257,

View file

@ -79,8 +79,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
Shader::ShaderManager::DefineMap defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); Shader::ShaderManager::DefineMap defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines();
Shader::ShaderManager::DefineMap shadowDefines = SceneUtil::ShadowManager::getShadowsDisabledDefines(); Shader::ShaderManager::DefineMap shadowDefines = SceneUtil::ShadowManager::getShadowsDisabledDefines();
defines["forcePPL"] = "0"; defines["forcePPL"] = "0"; // Don't force per-pixel lighting
defines["clamp"] = "1"; defines["clamp"] = "1"; // Clamp lighting
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
defines["radialFog"] = "0";
for (const auto& define : shadowDefines) for (const auto& define : shadowDefines)
defines[define.first] = define.second; defines[define.first] = define.second;
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
@ -443,7 +445,6 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
mLand.addColumn (new RecordStateColumn<Land>); mLand.addColumn (new RecordStateColumn<Land>);
mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land)); mLand.addColumn (new FixedRecordTypeColumn<Land>(UniversalId::Type_Land));
mLand.addColumn (new LandPluginIndexColumn); mLand.addColumn (new LandPluginIndexColumn);
mLand.addColumn (new LandMapLodColumn);
mLand.addColumn (new LandNormalsColumn); mLand.addColumn (new LandNormalsColumn);
mLand.addColumn (new LandHeightsColumn); mLand.addColumn (new LandHeightsColumn);
mLand.addColumn (new LandColoursColumn); mLand.addColumn (new LandColoursColumn);

View file

@ -867,6 +867,8 @@ namespace CSMWorld
switch (subColIndex) switch (subColIndex)
{ {
case 0: return isInterior; case 0: return isInterior;
// While the ambient information is not necessarily valid if the subrecord wasn't loaded,
// the user should still be allowed to edit it
case 1: return (isInterior && !behaveLikeExterior) ? case 1: return (isInterior && !behaveLikeExterior) ?
cell.mAmbi.mAmbient : QVariant(QVariant::UserType); cell.mAmbi.mAmbient : QVariant(QVariant::UserType);
case 2: return (isInterior && !behaveLikeExterior) ? case 2: return (isInterior && !behaveLikeExterior) ?
@ -912,7 +914,10 @@ namespace CSMWorld
case 1: case 1:
{ {
if (isInterior && !behaveLikeExterior) if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mAmbient = static_cast<int32_t>(value.toInt()); cell.mAmbi.mAmbient = static_cast<int32_t>(value.toInt());
cell.setHasAmbient(true);
}
else else
return; // return without saving return; // return without saving
break; break;
@ -920,7 +925,10 @@ namespace CSMWorld
case 2: case 2:
{ {
if (isInterior && !behaveLikeExterior) if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mSunlight = static_cast<int32_t>(value.toInt()); cell.mAmbi.mSunlight = static_cast<int32_t>(value.toInt());
cell.setHasAmbient(true);
}
else else
return; // return without saving return; // return without saving
break; break;
@ -928,7 +936,10 @@ namespace CSMWorld
case 3: case 3:
{ {
if (isInterior && !behaveLikeExterior) if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mFog = static_cast<int32_t>(value.toInt()); cell.mAmbi.mFog = static_cast<int32_t>(value.toInt());
cell.setHasAmbient(true);
}
else else
return; // return without saving return; // return without saving
break; break;
@ -936,7 +947,10 @@ namespace CSMWorld
case 4: case 4:
{ {
if (isInterior && !behaveLikeExterior) if (isInterior && !behaveLikeExterior)
{
cell.mAmbi.mFogDensity = value.toFloat(); cell.mAmbi.mFogDensity = value.toFloat();
cell.setHasAmbient(true);
}
else else
return; // return without saving return; // return without saving
break; break;

View file

@ -486,7 +486,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart));
npcColumns.mHead = &mColumns.back(); npcColumns.mHead = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_GenderNpc, ColumnBase::Display_GenderNpc)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Gender, ColumnBase::Display_GenderNpc));
npcColumns.mGender = &mColumns.back(); npcColumns.mGender = &mColumns.back();
npcColumns.mFlags.insert (std::make_pair (essential, ESM::NPC::Essential)); npcColumns.mFlags.insert (std::make_pair (essential, ESM::NPC::Essential));

View file

@ -9,6 +9,7 @@
#include <components/esm/loadcell.hpp> #include <components/esm/loadcell.hpp>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/sceneutil/pathgridutil.hpp> #include <components/sceneutil/pathgridutil.hpp>
#include <components/sceneutil/vismask.hpp>
#include <components/terrain/terraingrid.hpp> #include <components/terrain/terraingrid.hpp>
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
@ -21,7 +22,6 @@
#include "cellborder.hpp" #include "cellborder.hpp"
#include "cellarrow.hpp" #include "cellarrow.hpp"
#include "cellmarker.hpp" #include "cellmarker.hpp"
#include "mask.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "terrainstorage.hpp" #include "terrainstorage.hpp"
#include "object.hpp" #include "object.hpp"
@ -92,7 +92,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
std::unique_ptr<Object> object (new Object (mData, mCellNode, id, false)); std::unique_ptr<Object> object (new Object (mData, mCellNode, id, false));
if (mSubModeElementMask & Mask_Reference) if (mSubModeElementMask & SceneUtil::Mask_EditorReference)
object->setSubMode (mSubMode); object->setSubMode (mSubMode);
mObjects.insert (std::make_pair (id, object.release())); mObjects.insert (std::make_pair (id, object.release()));
@ -134,7 +134,7 @@ void CSVRender::Cell::updateLand()
else else
{ {
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode,
mData.getResourceSystem().get(), mTerrainStorage, Mask_Terrain)); mData.getResourceSystem().get(), mTerrainStorage));
} }
mTerrain->loadCell(esmLand.mX, esmLand.mY); mTerrain->loadCell(esmLand.mX, esmLand.mY);
@ -434,7 +434,7 @@ void CSVRender::Cell::reloadAssets()
void CSVRender::Cell::setSelection (int elementMask, Selection mode) void CSVRender::Cell::setSelection (int elementMask, Selection mode)
{ {
if (elementMask & Mask_Reference) if (elementMask & SceneUtil::Mask_EditorReference)
{ {
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin()); for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter) iter!=mObjects.end(); ++iter)
@ -451,7 +451,7 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode)
iter->second->setSelected (selected); iter->second->setSelected (selected);
} }
} }
if (mPathgrid && elementMask & Mask_Pathgrid) if (mPathgrid && elementMask & SceneUtil::Mask_Pathgrid)
{ {
// Only one pathgrid may be selected, so some operations will only have an effect // Only one pathgrid may be selected, so some operations will only have an effect
// if the pathgrid is already focused // if the pathgrid is already focused
@ -546,12 +546,12 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getSelection (un
{ {
std::vector<osg::ref_ptr<TagBase> > result; std::vector<osg::ref_ptr<TagBase> > result;
if (elementMask & Mask_Reference) if (elementMask & SceneUtil::Mask_EditorReference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin()); for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter) iter!=mObjects.end(); ++iter)
if (iter->second->getSelected()) if (iter->second->getSelected())
result.push_back (iter->second->getTag()); result.push_back (iter->second->getTag());
if (mPathgrid && elementMask & Mask_Pathgrid) if (mPathgrid && elementMask & SceneUtil::Mask_Pathgrid)
if (mPathgrid->isSelected()) if (mPathgrid->isSelected())
result.push_back(mPathgrid->getTag()); result.push_back(mPathgrid->getTag());
@ -562,7 +562,7 @@ std::vector<osg::ref_ptr<CSVRender::TagBase> > CSVRender::Cell::getEdited (unsig
{ {
std::vector<osg::ref_ptr<TagBase> > result; std::vector<osg::ref_ptr<TagBase> > result;
if (elementMask & Mask_Reference) if (elementMask & SceneUtil::Mask_EditorReference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin()); for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter) iter!=mObjects.end(); ++iter)
if (iter->second->isEdited()) if (iter->second->isEdited())
@ -576,7 +576,7 @@ void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask)
mSubMode = subMode; mSubMode = subMode;
mSubModeElementMask = elementMask; mSubModeElementMask = elementMask;
if (elementMask & Mask_Reference) if (elementMask & SceneUtil::Mask_EditorReference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin()); for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter) iter!=mObjects.end(); ++iter)
iter->second->setSubMode (subMode); iter->second->setSubMode (subMode);
@ -584,10 +584,10 @@ void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask)
void CSVRender::Cell::reset (unsigned int elementMask) void CSVRender::Cell::reset (unsigned int elementMask)
{ {
if (elementMask & Mask_Reference) if (elementMask & SceneUtil::Mask_EditorReference)
for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin()); for (std::map<std::string, Object *>::const_iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter) iter!=mObjects.end(); ++iter)
iter->second->reset(); iter->second->reset();
if (mPathgrid && elementMask & Mask_Pathgrid) if (mPathgrid && elementMask & SceneUtil::Mask_Pathgrid)
mPathgrid->resetIndicators(); mPathgrid->resetIndicators();
} }

View file

@ -11,11 +11,10 @@
#include "../../model/prefs/shortcutmanager.hpp" #include "../../model/prefs/shortcutmanager.hpp"
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <components/sceneutil/vismask.hpp>
#include "mask.hpp"
CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow) CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow)
: TagBase (Mask_CellArrow), mArrow (arrow) : TagBase (SceneUtil::Mask_EditorCellArrow), mArrow (arrow)
{} {}
CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const CSVRender::CellArrow *CSVRender::CellArrowTag::getCellArrow() const
@ -175,7 +174,7 @@ CSVRender::CellArrow::CellArrow (osg::Group *cellNode, Direction direction,
mParentNode->addChild (mBaseNode); mParentNode->addChild (mBaseNode);
mBaseNode->setNodeMask (Mask_CellArrow); mBaseNode->setNodeMask (SceneUtil::Mask_EditorCellArrow);
adjustTransform(); adjustTransform();
buildShape(); buildShape();

View file

@ -7,8 +7,7 @@
#include <osg/PrimitiveSet> #include <osg/PrimitiveSet>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/sceneutil/vismask.hpp>
#include "mask.hpp"
#include "../../model/world/cellcoordinates.hpp" #include "../../model/world/cellcoordinates.hpp"
@ -20,7 +19,7 @@ CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoor
: mParentNode(cellNode) : mParentNode(cellNode)
{ {
mBaseNode = new osg::PositionAttitudeTransform(); mBaseNode = new osg::PositionAttitudeTransform();
mBaseNode->setNodeMask(Mask_CellBorder); mBaseNode->setNodeMask(SceneUtil::Mask_EditorCellBorder);
mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10)); mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10));
mParentNode->addChild(mBaseNode); mParentNode->addChild(mBaseNode);

View file

@ -8,7 +8,7 @@
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
CSVRender::CellMarkerTag::CellMarkerTag(CellMarker *marker) CSVRender::CellMarkerTag::CellMarkerTag(CellMarker *marker)
: TagBase(Mask_CellMarker), mMarker(marker) : TagBase(SceneUtil::Mask_EditorCellMarker), mMarker(marker)
{} {}
CSVRender::CellMarker *CSVRender::CellMarkerTag::getCellMarker() const CSVRender::CellMarker *CSVRender::CellMarkerTag::getCellMarker() const
@ -79,7 +79,7 @@ CSVRender::CellMarker::CellMarker(
mMarkerNode->getOrCreateStateSet()->setAttribute(mat); mMarkerNode->getOrCreateStateSet()->setAttribute(mat);
mMarkerNode->setUserData(new CellMarkerTag(this)); mMarkerNode->setUserData(new CellMarkerTag(this));
mMarkerNode->setNodeMask(Mask_CellMarker); mMarkerNode->setNodeMask(SceneUtil::Mask_EditorCellMarker);
mCellNode->addChild(mMarkerNode); mCellNode->addChild(mMarkerNode);

View file

@ -11,12 +11,12 @@
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/waterutil.hpp> #include <components/sceneutil/waterutil.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../../model/world/cell.hpp" #include "../../model/world/cell.hpp"
#include "../../model/world/cellcoordinates.hpp" #include "../../model/world/cellcoordinates.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "mask.hpp"
namespace CSVRender namespace CSVRender
{ {
@ -38,7 +38,7 @@ namespace CSVRender
mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize + CellSize / 2.f, mWaterTransform->setPosition(osg::Vec3f(cellCoords.getX() * CellSize + CellSize / 2.f,
cellCoords.getY() * CellSize + CellSize / 2.f, 0)); cellCoords.getY() * CellSize + CellSize / 2.f, 0));
mWaterTransform->setNodeMask(Mask_Water); mWaterTransform->setNodeMask(SceneUtil::Mask_Water);
mParentNode->addChild(mWaterTransform); mParentNode->addChild(mWaterTransform);
mWaterNode = new osg::Geode(); mWaterNode = new osg::Geode();

View file

@ -3,18 +3,25 @@
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QPoint> #include <QPoint>
#include <QString>
#include "../../model/prefs/state.hpp" #include "../../model/prefs/state.hpp"
#include <osg/ComputeBoundsVisitor>
#include <osg/Group>
#include <osg/Vec3d>
#include <osgUtil/LineSegmentIntersector>
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp" #include "../../model/world/idtree.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/commandmacro.hpp" #include "../../model/world/commandmacro.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolbar.hpp"
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
#include "mask.hpp" #include <components/sceneutil/vismask.hpp>
#include "object.hpp" #include "object.hpp"
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
@ -89,13 +96,26 @@ osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos)
return pos * combined; return pos * combined;
} }
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, osg::ref_ptr<osg::Group> parentNode, QWidget *parent)
: EditMode (worldspaceWidget, QIcon (":scenetoolbar/editing-instance"), Mask_Reference | Mask_Terrain, "Instance editing", : EditMode (worldspaceWidget, QIcon (":scenetoolbar/editing-instance"), SceneUtil::Mask_EditorReference | SceneUtil::Mask_Terrain, "Instance editing",
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None), parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
mDragAxis (-1), mLocked (false), mUnitScaleDist(1) mDragAxis (-1), mLocked (false), mUnitScaleDist(1), mParentNode (parentNode)
{ {
connect(this, SIGNAL(requestFocus(const std::string&)), connect(this, SIGNAL(requestFocus(const std::string&)),
worldspaceWidget, SIGNAL(requestFocus(const std::string&))); worldspaceWidget, SIGNAL(requestFocus(const std::string&)));
CSMPrefs::Shortcut* deleteShortcut = new CSMPrefs::Shortcut("scene-delete", worldspaceWidget);
connect(deleteShortcut, SIGNAL(activated(bool)), this, SLOT(deleteSelectedInstances(bool)));
// Following classes could be simplified by using QSignalMapper, which is obsolete in Qt5.10, but not in Qt4.8 and Qt5.14
CSMPrefs::Shortcut* dropToCollisionShortcut = new CSMPrefs::Shortcut("scene-instance-drop-collision", worldspaceWidget);
connect(dropToCollisionShortcut, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToCollision()));
CSMPrefs::Shortcut* dropToTerrainLevelShortcut = new CSMPrefs::Shortcut("scene-instance-drop-terrain", worldspaceWidget);
connect(dropToTerrainLevelShortcut, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToTerrain()));
CSMPrefs::Shortcut* dropToCollisionShortcut2 = new CSMPrefs::Shortcut("scene-instance-drop-collision-separately", worldspaceWidget);
connect(dropToCollisionShortcut2, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToCollisionSeparately()));
CSMPrefs::Shortcut* dropToTerrainLevelShortcut2 = new CSMPrefs::Shortcut("scene-instance-drop-terrain-separately", worldspaceWidget);
connect(dropToTerrainLevelShortcut2, SIGNAL(activated()), this, SLOT(dropSelectedInstancesToTerrainSeparately()));
} }
void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
@ -137,13 +157,13 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
std::string subMode = mSubMode->getCurrentId(); std::string subMode = mSubMode->getCurrentId();
getWorldspaceWidget().setSubMode (getSubModeFromId (subMode), Mask_Reference); getWorldspaceWidget().setSubMode (getSubModeFromId (subMode), SceneUtil::Mask_EditorReference);
} }
void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar) void CSVRender::InstanceMode::deactivate (CSVWidget::SceneToolbar *toolbar)
{ {
mDragMode = DragMode_None; mDragMode = DragMode_None;
getWorldspaceWidget().reset (Mask_Reference); getWorldspaceWidget().reset (SceneUtil::Mask_EditorReference);
if (mSelectionMode) if (mSelectionMode)
{ {
@ -196,7 +216,7 @@ void CSVRender::InstanceMode::secondaryEditPressed (const WorldspaceHitResult& h
void CSVRender::InstanceMode::primarySelectPressed (const WorldspaceHitResult& hit) void CSVRender::InstanceMode::primarySelectPressed (const WorldspaceHitResult& hit)
{ {
getWorldspaceWidget().clearSelection (Mask_Reference); getWorldspaceWidget().clearSelection (SceneUtil::Mask_EditorReference);
if (hit.tag) if (hit.tag)
{ {
@ -231,13 +251,13 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Reference); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference);
if (selection.empty()) if (selection.empty())
{ {
// Only change selection at the start of drag if no object is already selected // Only change selection at the start of drag if no object is already selected
if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) if (hit.tag && CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
{ {
getWorldspaceWidget().clearSelection (Mask_Reference); getWorldspaceWidget().clearSelection (SceneUtil::Mask_EditorReference);
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get())) if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get()))
{ {
CSVRender::Object* object = objectTag->mObject; CSVRender::Object* object = objectTag->mObject;
@ -245,7 +265,7 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
} }
} }
selection = getWorldspaceWidget().getSelection (Mask_Reference); selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference);
if (selection.empty()) if (selection.empty())
return false; return false;
} }
@ -271,7 +291,7 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
mDragMode = DragMode_Scale; mDragMode = DragMode_Scale;
// Calculate scale factor // Calculate scale factor
std::vector<osg::ref_ptr<TagBase> > editedSelection = getWorldspaceWidget().getEdited (Mask_Reference); std::vector<osg::ref_ptr<TagBase> > editedSelection = getWorldspaceWidget().getEdited (SceneUtil::Mask_EditorReference);
osg::Vec3f center = getScreenCoords(getSelectionCenter(editedSelection)); osg::Vec3f center = getScreenCoords(getSelectionCenter(editedSelection));
int widgetHeight = getWorldspaceWidget().height(); int widgetHeight = getWorldspaceWidget().height();
@ -307,7 +327,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
osg::Vec3f offset; osg::Vec3f offset;
osg::Quat rotation; osg::Quat rotation;
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (SceneUtil::Mask_EditorReference);
if (mDragMode == DragMode_Move) if (mDragMode == DragMode_Move)
{ {
@ -464,7 +484,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
void CSVRender::InstanceMode::dragCompleted(const QPoint& pos) void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
{ {
std::vector<osg::ref_ptr<TagBase> > selection = std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference); getWorldspaceWidget().getEdited (SceneUtil::Mask_EditorReference);
QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack();
@ -496,7 +516,7 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
void CSVRender::InstanceMode::dragAborted() void CSVRender::InstanceMode::dragAborted()
{ {
getWorldspaceWidget().reset (Mask_Reference); getWorldspaceWidget().reset (SceneUtil::Mask_EditorReference);
mDragMode = DragMode_None; mDragMode = DragMode_None;
} }
@ -515,7 +535,7 @@ void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor)
offset *= diff * speedFactor; offset *= diff * speedFactor;
std::vector<osg::ref_ptr<TagBase> > selection = std::vector<osg::ref_ptr<TagBase> > selection =
getWorldspaceWidget().getEdited (Mask_Reference); getWorldspaceWidget().getEdited (SceneUtil::Mask_EditorReference);
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin()); for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
iter!=selection.end(); ++iter) iter!=selection.end(); ++iter)
@ -657,5 +677,207 @@ void CSVRender::InstanceMode::subModeChanged (const std::string& id)
{ {
mSubModeId = id; mSubModeId = id;
getWorldspaceWidget().abortDrag(); getWorldspaceWidget().abortDrag();
getWorldspaceWidget().setSubMode (getSubModeFromId (id), Mask_Reference); getWorldspaceWidget().setSubMode (getSubModeFromId (id), SceneUtil::Mask_EditorReference);
}
void CSVRender::InstanceMode::deleteSelectedInstances(bool active)
{
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference);
if (selection.empty()) return;
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
CSMWorld::IdTable& referencesTable = dynamic_cast<CSMWorld::IdTable&> (
*document.getData().getTableModel (CSMWorld::UniversalId::Type_References));
QUndoStack& undoStack = document.getUndoStack();
CSMWorld::CommandMacro macro (undoStack, "Delete Instances");
for(osg::ref_ptr<TagBase> tag: selection)
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
macro.push(new CSMWorld::DeleteCommand(referencesTable, objectTag->mObject->getReferenceId()));
getWorldspaceWidget().clearSelection (SceneUtil::Mask_EditorReference);
}
void CSVRender::InstanceMode::dropInstance(DropMode dropMode, CSVRender::Object* object, float objectHeight)
{
osg::Vec3d point = object->getPosition().asVec3();
osg::Vec3d start = point;
start.z() += objectHeight;
osg::Vec3d end = point;
end.z() = std::numeric_limits<float>::lowest();
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(
osgUtil::Intersector::MODEL, start, end) );
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
osgUtil::IntersectionVisitor visitor(intersector);
if (dropMode == TerrainSep)
visitor.setTraversalMask(SceneUtil::Mask_Terrain);
if (dropMode == CollisionSep)
visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference);
mParentNode->accept(visitor);
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
it != intersector->getIntersections().end(); ++it)
{
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
ESM::Position position = object->getPosition();
object->setEdited (Object::Override_Position);
position.pos[2] = intersection.getWorldIntersectPoint().z() + objectHeight;
object->setPosition(position.pos);
return;
}
}
float CSVRender::InstanceMode::getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight)
{
osg::Vec3d point = object->getPosition().asVec3();
osg::Vec3d start = point;
start.z() += objectHeight;
osg::Vec3d end = point;
end.z() = std::numeric_limits<float>::lowest();
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(
osgUtil::Intersector::MODEL, start, end) );
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::NO_LIMIT);
osgUtil::IntersectionVisitor visitor(intersector);
if (dropMode == Terrain)
visitor.setTraversalMask(SceneUtil::Mask_Terrain);
if (dropMode == Collision)
visitor.setTraversalMask(SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference);
mParentNode->accept(visitor);
for (osgUtil::LineSegmentIntersector::Intersections::iterator it = intersector->getIntersections().begin();
it != intersector->getIntersections().end(); ++it)
{
osgUtil::LineSegmentIntersector::Intersection intersection = *it;
float collisionLevel = intersection.getWorldIntersectPoint().z();
return point.z() - collisionLevel + objectHeight;
}
return 0.0f;
}
void CSVRender::InstanceMode::dropSelectedInstancesToCollision()
{
handleDropMethod(Collision, "Drop instances to next collision");
}
void CSVRender::InstanceMode::dropSelectedInstancesToTerrain()
{
handleDropMethod(Terrain, "Drop instances to terrain level");
}
void CSVRender::InstanceMode::dropSelectedInstancesToCollisionSeparately()
{
handleDropMethod(TerrainSep, "Drop instances to next collision level separately");
}
void CSVRender::InstanceMode::dropSelectedInstancesToTerrainSeparately()
{
handleDropMethod(CollisionSep, "Drop instances to terrain level separately");
}
void CSVRender::InstanceMode::handleDropMethod(DropMode dropMode, QString commandMsg)
{
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_EditorReference);
if (selection.empty())
return;
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
QUndoStack& undoStack = document.getUndoStack();
CSMWorld::CommandMacro macro (undoStack, commandMsg);
DropObjectDataHandler dropObjectDataHandler(&getWorldspaceWidget());
switch (dropMode)
{
case Terrain:
case Collision:
{
float smallestDropHeight = std::numeric_limits<float>::max();
int counter = 0;
for(osg::ref_ptr<TagBase> tag: selection)
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
float thisDrop = getDropHeight(dropMode, objectTag->mObject, dropObjectDataHandler.mObjectHeights[counter]);
if (thisDrop < smallestDropHeight)
smallestDropHeight = thisDrop;
counter++;
}
for(osg::ref_ptr<TagBase> tag: selection)
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
objectTag->mObject->setEdited (Object::Override_Position);
ESM::Position position = objectTag->mObject->getPosition();
position.pos[2] -= smallestDropHeight;
objectTag->mObject->setPosition(position.pos);
objectTag->mObject->apply (macro);
}
}
break;
case TerrainSep:
case CollisionSep:
{
int counter = 0;
for(osg::ref_ptr<TagBase> tag: selection)
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
dropInstance(dropMode, objectTag->mObject, dropObjectDataHandler.mObjectHeights[counter]);
objectTag->mObject->apply (macro);
counter++;
}
}
break;
}
}
CSVRender::DropObjectDataHandler::DropObjectDataHandler(WorldspaceWidget* worldspacewidget)
: mWorldspaceWidget(worldspacewidget)
{
std::vector<osg::ref_ptr<TagBase> > selection = mWorldspaceWidget->getSelection (SceneUtil::Mask_EditorReference);
for(osg::ref_ptr<TagBase> tag: selection)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
osg::ref_ptr<osg::Group> objectNodeWithGUI = objectTag->mObject->getRootNode();
osg::ref_ptr<osg::Group> objectNodeWithoutGUI = objectTag->mObject->getBaseNode();
osg::ComputeBoundsVisitor computeBounds;
computeBounds.setTraversalMask(SceneUtil::Mask_EditorReference);
objectNodeWithoutGUI->accept(computeBounds);
osg::BoundingBox bounds = computeBounds.getBoundingBox();
float boundingBoxOffset = 0.0f;
if (bounds.valid())
boundingBoxOffset = bounds.zMin();
mObjectHeights.emplace_back(boundingBoxOffset);
mOldMasks.emplace_back(objectNodeWithGUI->getNodeMask());
objectNodeWithGUI->setNodeMask(SceneUtil::Mask_Disabled);
}
}
}
CSVRender::DropObjectDataHandler::~DropObjectDataHandler()
{
std::vector<osg::ref_ptr<TagBase> > selection = mWorldspaceWidget->getSelection (SceneUtil::Mask_EditorReference);
int counter = 0;
for(osg::ref_ptr<TagBase> tag: selection)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (tag.get()))
{
osg::ref_ptr<osg::Group> objectNodeWithGUI = objectTag->mObject->getRootNode();
objectNodeWithGUI->setNodeMask(mOldMasks[counter]);
counter++;
}
}
} }

View file

@ -1,7 +1,10 @@
#ifndef CSV_RENDER_INSTANCEMODE_H #ifndef CSV_RENDER_INSTANCEMODE_H
#define CSV_RENDER_INSTANCEMODE_H #define CSV_RENDER_INSTANCEMODE_H
#include <QString>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Group>
#include <osg/Quat> #include <osg/Quat>
#include <osg/Vec3f> #include <osg/Vec3f>
@ -16,6 +19,7 @@ namespace CSVRender
{ {
class TagBase; class TagBase;
class InstanceSelectionMode; class InstanceSelectionMode;
class Object;
class InstanceMode : public EditMode class InstanceMode : public EditMode
{ {
@ -29,6 +33,14 @@ namespace CSVRender
DragMode_Scale DragMode_Scale
}; };
enum DropMode
{
Collision,
Terrain,
CollisionSep,
TerrainSep
};
CSVWidget::SceneToolMode *mSubMode; CSVWidget::SceneToolMode *mSubMode;
std::string mSubModeId; std::string mSubModeId;
InstanceSelectionMode *mSelectionMode; InstanceSelectionMode *mSelectionMode;
@ -36,6 +48,7 @@ namespace CSVRender
int mDragAxis; int mDragAxis;
bool mLocked; bool mLocked;
float mUnitScaleDist; float mUnitScaleDist;
osg::ref_ptr<osg::Group> mParentNode;
int getSubModeFromId (const std::string& id) const; int getSubModeFromId (const std::string& id) const;
@ -44,10 +57,12 @@ namespace CSVRender
osg::Vec3f getSelectionCenter(const std::vector<osg::ref_ptr<TagBase> >& selection) const; osg::Vec3f getSelectionCenter(const std::vector<osg::ref_ptr<TagBase> >& selection) const;
osg::Vec3f getScreenCoords(const osg::Vec3f& pos); osg::Vec3f getScreenCoords(const osg::Vec3f& pos);
void dropInstance(DropMode dropMode, CSVRender::Object* object, float objectHeight);
float getDropHeight(DropMode dropMode, CSVRender::Object* object, float objectHeight);
public: public:
InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent = 0); InstanceMode (WorldspaceWidget *worldspaceWidget, osg::ref_ptr<osg::Group> parentNode, QWidget *parent = 0);
virtual void activate (CSVWidget::SceneToolbar *toolbar); virtual void activate (CSVWidget::SceneToolbar *toolbar);
@ -92,6 +107,25 @@ namespace CSVRender
private slots: private slots:
void subModeChanged (const std::string& id); void subModeChanged (const std::string& id);
void deleteSelectedInstances(bool active);
void dropSelectedInstancesToCollision();
void dropSelectedInstancesToTerrain();
void dropSelectedInstancesToCollisionSeparately();
void dropSelectedInstancesToTerrainSeparately();
void handleDropMethod(DropMode dropMode, QString commandMsg);
};
/// \brief Helper class to handle object mask data in safe way
class DropObjectDataHandler
{
public:
DropObjectDataHandler(WorldspaceWidget* worldspacewidget);
~DropObjectDataHandler();
std::vector<float> mObjectHeights;
private:
WorldspaceWidget* mWorldspaceWidget;
std::vector<osg::Node::NodeMask> mOldMasks;
}; };
} }

View file

@ -6,13 +6,15 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include <components/sceneutil/vismask.hpp>
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
#include "object.hpp" #include "object.hpp"
namespace CSVRender namespace CSVRender
{ {
InstanceSelectionMode::InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget) InstanceSelectionMode::InstanceSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget)
: SelectionMode(parent, worldspaceWidget, Mask_Reference) : SelectionMode(parent, worldspaceWidget, SceneUtil::Mask_EditorReference)
{ {
mSelectSame = new QAction("Extend selection to instances with same object ID", this); mSelectSame = new QAction("Extend selection to instances with same object ID", this);
mDeleteSelection = new QAction("Delete selected instances", this); mDeleteSelection = new QAction("Delete selected instances", this);
@ -36,12 +38,12 @@ namespace CSVRender
void InstanceSelectionMode::selectSame() void InstanceSelectionMode::selectSame()
{ {
getWorldspaceWidget().selectAllWithSameParentId(Mask_Reference); getWorldspaceWidget().selectAllWithSameParentId(SceneUtil::Mask_EditorReference);
} }
void InstanceSelectionMode::deleteSelection() void InstanceSelectionMode::deleteSelection()
{ {
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection(Mask_Reference); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection(SceneUtil::Mask_EditorReference);
CSMWorld::IdTable& referencesTable = dynamic_cast<CSMWorld::IdTable&>( CSMWorld::IdTable& referencesTable = dynamic_cast<CSMWorld::IdTable&>(
*getWorldspaceWidget().getDocument().getData().getTableModel(CSMWorld::UniversalId::Type_References)); *getWorldspaceWidget().getDocument().getData().getTableModel(CSMWorld::UniversalId::Type_References));

View file

@ -1,35 +0,0 @@
#ifndef CSV_RENDER_ELEMENTS_H
#define CSV_RENDER_ELEMENTS_H
namespace CSVRender
{
/// Node masks used on the OSG scene graph in OpenMW-CS.
/// @note See the respective file in OpenMW (apps/openmw/mwrender/vismask.hpp)
/// for general usage hints about node masks.
/// @copydoc MWRender::VisMask
enum Mask
{
// internal use within NifLoader, do not change
Mask_UpdateVisitor = 0x1,
// elements that are part of the actual scene
Mask_Reference = 0x2,
Mask_Pathgrid = 0x4,
Mask_Water = 0x8,
Mask_Fog = 0x10,
Mask_Terrain = 0x20,
// used within models
Mask_ParticleSystem = 0x100,
Mask_Lighting = 0x200,
// control elements
Mask_CellMarker = 0x10000,
Mask_CellArrow = 0x20000,
Mask_CellBorder = 0x40000
};
}
#endif

View file

@ -29,9 +29,9 @@
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/lightutil.hpp> #include <components/sceneutil/lightutil.hpp>
#include <components/sceneutil/lightmanager.hpp> #include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/vismask.hpp>
#include "actor.hpp" #include "actor.hpp"
#include "mask.hpp"
const float CSVRender::Object::MarkerShaftWidth = 30; const float CSVRender::Object::MarkerShaftWidth = 30;
@ -58,7 +58,7 @@ namespace
CSVRender::ObjectTag::ObjectTag (Object* object) CSVRender::ObjectTag::ObjectTag (Object* object)
: TagBase (Mask_Reference), mObject (object) : TagBase (SceneUtil::Mask_EditorReference), mObject (object)
{} {}
QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const QString CSVRender::ObjectTag::getToolTip (bool hideBasics) const
@ -140,7 +140,7 @@ void CSVRender::Object::update()
if (light) if (light)
{ {
bool isExterior = false; // FIXME bool isExterior = false; // FIXME
SceneUtil::addLight(mBaseNode, light, Mask_ParticleSystem, Mask_Lighting, isExterior); SceneUtil::addLight(mBaseNode, light, isExterior);
} }
} }
@ -429,7 +429,7 @@ CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
parentNode->addChild (mRootNode); parentNode->addChild (mRootNode);
mRootNode->setNodeMask(Mask_Reference); mRootNode->setNodeMask(SceneUtil::Mask_EditorReference);
if (referenceable) if (referenceable)
{ {
@ -477,6 +477,16 @@ bool CSVRender::Object::getSelected() const
return mSelected; return mSelected;
} }
osg::ref_ptr<osg::Group> CSVRender::Object::getRootNode()
{
return mRootNode;
}
osg::ref_ptr<osg::Group> CSVRender::Object::getBaseNode()
{
return mBaseNode;
}
bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft, bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight) const QModelIndex& bottomRight)
{ {
@ -705,7 +715,7 @@ void CSVRender::Object::apply (CSMWorld::CommandMacro& commands)
CSMWorld::Columns::ColumnId_PositionXRot+i)); CSMWorld::Columns::ColumnId_PositionXRot+i));
commands.push (new CSMWorld::ModifyCommand (*model, commands.push (new CSMWorld::ModifyCommand (*model,
model->index (recordIndex, column), mPositionOverride.rot[i])); model->index (recordIndex, column), osg::RadiansToDegrees(mPositionOverride.rot[i])));
} }
} }

View file

@ -146,6 +146,12 @@ namespace CSVRender
bool getSelected() const; bool getSelected() const;
/// Get object node with GUI graphics
osg::ref_ptr<osg::Group> getRootNode();
/// Get object node without GUI graphics
osg::ref_ptr<osg::Group> getBaseNode();
/// \return Did this call result in a modification of the visual representation of /// \return Did this call result in a modification of the visual representation of
/// this object? /// this object?
bool referenceableDataChanged (const QModelIndex& topLeft, bool referenceableDataChanged (const QModelIndex& topLeft,

View file

@ -21,7 +21,6 @@
#include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetooltoggle2.hpp"
#include "editmode.hpp" #include "editmode.hpp"
#include "mask.hpp"
#include "cameracontroller.hpp" #include "cameracontroller.hpp"
#include "cellarrow.hpp" #include "cellarrow.hpp"
#include "terraintexturemode.hpp" #include "terraintexturemode.hpp"
@ -127,8 +126,8 @@ void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle2 *tool) CSVWidget::SceneToolToggle2 *tool)
{ {
WorldspaceWidget::addVisibilitySelectorButtons (tool); WorldspaceWidget::addVisibilitySelectorButtons (tool);
tool->addButton (Button_Terrain, Mask_Terrain, "Terrain"); tool->addButton (Button_Terrain, SceneUtil::Mask_Terrain, "Terrain");
tool->addButton (Button_Fog, Mask_Fog, "Fog", "", true); //tool->addButton (Button_Fog, Mask_Fog, "Fog", "", true);
} }
void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
@ -142,16 +141,16 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
tool->addButton ( tool->addButton (
new TerrainTextureMode (this, mRootNode, tool), "terrain-texture"); new TerrainTextureMode (this, mRootNode, tool), "terrain-texture");
tool->addButton ( tool->addButton (
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain vertex paint editing"), new EditMode (this, QIcon (":placeholder"), SceneUtil::Mask_EditorReference, "Terrain vertex paint editing"),
"terrain-vertex"); "terrain-vertex");
tool->addButton ( tool->addButton (
new EditMode (this, QIcon (":placeholder"), Mask_Reference, "Terrain movement"), new EditMode (this, QIcon (":placeholder"), SceneUtil::Mask_EditorReference, "Terrain movement"),
"terrain-move"); "terrain-move");
} }
void CSVRender::PagedWorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type) void CSVRender::PagedWorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type)
{ {
if (hit.tag && hit.tag->getMask()==Mask_CellArrow) if (hit.tag && hit.tag->getMask()==SceneUtil::Mask_EditorCellArrow)
{ {
if (CellArrowTag *cellArrowTag = dynamic_cast<CSVRender::CellArrowTag *> (hit.tag.get())) if (CellArrowTag *cellArrowTag = dynamic_cast<CSVRender::CellArrowTag *> (hit.tag.get()))
{ {
@ -874,9 +873,9 @@ CSVWidget::SceneToolToggle2 *CSVRender::PagedWorldspaceWidget::makeControlVisibi
mControlElements = new CSVWidget::SceneToolToggle2 (parent, mControlElements = new CSVWidget::SceneToolToggle2 (parent,
"Controls & Guides Visibility", ":scenetoolbar/scene-view-marker-c", ":scenetoolbar/scene-view-marker-"); "Controls & Guides Visibility", ":scenetoolbar/scene-view-marker-c", ":scenetoolbar/scene-view-marker-");
mControlElements->addButton (1, Mask_CellMarker, "Cell Marker"); mControlElements->addButton (1, SceneUtil::Mask_EditorCellMarker, "Cell Marker");
mControlElements->addButton (2, Mask_CellArrow, "Cell Arrows"); mControlElements->addButton (2, SceneUtil::Mask_EditorCellArrow, "Cell Arrows");
mControlElements->addButton (4, Mask_CellBorder, "Cell Border"); mControlElements->addButton (4, SceneUtil::Mask_EditorCellBorder, "Cell Border");
mControlElements->setSelectionMask (0xffffffff); mControlElements->setSelectionMask (0xffffffff);

View file

@ -10,6 +10,7 @@
#include <osg/Vec3> #include <osg/Vec3>
#include <components/sceneutil/pathgridutil.hpp> #include <components/sceneutil/pathgridutil.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../../model/world/cell.hpp" #include "../../model/world/cell.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
@ -31,7 +32,7 @@ namespace CSVRender
}; };
PathgridTag::PathgridTag(Pathgrid* pathgrid) PathgridTag::PathgridTag(Pathgrid* pathgrid)
: TagBase(Mask_Pathgrid), mPathgrid(pathgrid) : TagBase(SceneUtil::Mask_Pathgrid), mPathgrid(pathgrid)
{ {
} }
@ -70,7 +71,7 @@ namespace CSVRender
mBaseNode->setPosition(osg::Vec3f(mCoords.getX() * CoordScalar, mCoords.getY() * CoordScalar, 0.f)); mBaseNode->setPosition(osg::Vec3f(mCoords.getX() * CoordScalar, mCoords.getY() * CoordScalar, 0.f));
mBaseNode->setUserData(mTag); mBaseNode->setUserData(mTag);
mBaseNode->setUpdateCallback(new PathgridNodeCallback()); mBaseNode->setUpdateCallback(new PathgridNodeCallback());
mBaseNode->setNodeMask(Mask_Pathgrid); mBaseNode->setNodeMask(SceneUtil::Mask_Pathgrid);
mParent->addChild(mBaseNode); mParent->addChild(mBaseNode);
mPathgridGeode = new osg::Geode(); mPathgridGeode = new osg::Geode();

View file

@ -4,6 +4,7 @@
#include <QPoint> #include <QPoint>
#include <components/sceneutil/pathgridutil.hpp> #include <components/sceneutil/pathgridutil.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../../model/prefs/state.hpp" #include "../../model/prefs/state.hpp"
@ -15,7 +16,6 @@
#include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolbar.hpp"
#include "cell.hpp" #include "cell.hpp"
#include "mask.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "pathgridselectionmode.hpp" #include "pathgridselectionmode.hpp"
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
@ -23,7 +23,7 @@
namespace CSVRender namespace CSVRender
{ {
PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent) PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent)
: EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid | Mask_Terrain | Mask_Reference, : EditMode(worldspaceWidget, QIcon(":placeholder"), SceneUtil::Mask_Pathgrid | SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference,
getTooltip(), parent) getTooltip(), parent)
, mDragMode(DragMode_None) , mDragMode(DragMode_None)
, mFromNode(0) , mFromNode(0)
@ -110,7 +110,7 @@ namespace CSVRender
void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit) void PathgridMode::primarySelectPressed(const WorldspaceHitResult& hit)
{ {
getWorldspaceWidget().clearSelection(Mask_Pathgrid); getWorldspaceWidget().clearSelection(SceneUtil::Mask_Pathgrid);
if (hit.tag) if (hit.tag)
{ {
@ -131,7 +131,7 @@ namespace CSVRender
{ {
if (tag->getPathgrid()->getId() != mLastId) if (tag->getPathgrid()->getId() != mLastId)
{ {
getWorldspaceWidget().clearSelection(Mask_Pathgrid); getWorldspaceWidget().clearSelection(SceneUtil::Mask_Pathgrid);
mLastId = tag->getPathgrid()->getId(); mLastId = tag->getPathgrid()->getId();
} }
@ -142,12 +142,12 @@ namespace CSVRender
} }
} }
getWorldspaceWidget().clearSelection(Mask_Pathgrid); getWorldspaceWidget().clearSelection(SceneUtil::Mask_Pathgrid);
} }
bool PathgridMode::primaryEditStartDrag(const QPoint& pos) bool PathgridMode::primaryEditStartDrag(const QPoint& pos)
{ {
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_Pathgrid);
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue()) if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())
{ {
@ -156,7 +156,7 @@ namespace CSVRender
if (dynamic_cast<PathgridTag*>(hit.tag.get())) if (dynamic_cast<PathgridTag*>(hit.tag.get()))
{ {
primarySelectPressed(hit); primarySelectPressed(hit);
selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_Pathgrid);
} }
} }
@ -192,7 +192,7 @@ namespace CSVRender
{ {
if (mDragMode == DragMode_Move) if (mDragMode == DragMode_Move)
{ {
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection(Mask_Pathgrid); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection(SceneUtil::Mask_Pathgrid);
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it) for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
{ {
@ -233,7 +233,7 @@ namespace CSVRender
{ {
if (mDragMode == DragMode_Move) if (mDragMode == DragMode_Move)
{ {
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_Pathgrid);
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it) for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
{ {
if (PathgridTag* tag = dynamic_cast<PathgridTag*>(it->get())) if (PathgridTag* tag = dynamic_cast<PathgridTag*>(it->get()))
@ -272,11 +272,11 @@ namespace CSVRender
} }
mDragMode = DragMode_None; mDragMode = DragMode_None;
getWorldspaceWidget().reset(Mask_Pathgrid); getWorldspaceWidget().reset(SceneUtil::Mask_Pathgrid);
} }
void PathgridMode::dragAborted() void PathgridMode::dragAborted()
{ {
getWorldspaceWidget().reset(Mask_Pathgrid); getWorldspaceWidget().reset(SceneUtil::Mask_Pathgrid);
} }
} }

View file

@ -13,7 +13,7 @@
namespace CSVRender namespace CSVRender
{ {
PathgridSelectionMode::PathgridSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget) PathgridSelectionMode::PathgridSelectionMode(CSVWidget::SceneToolbar* parent, WorldspaceWidget& worldspaceWidget)
: SelectionMode(parent, worldspaceWidget, Mask_Pathgrid) : SelectionMode(parent, worldspaceWidget, SceneUtil::Mask_Pathgrid)
{ {
mRemoveSelectedNodes = new QAction("Remove selected nodes", this); mRemoveSelectedNodes = new QAction("Remove selected nodes", this);
mRemoveSelectedEdges = new QAction("Remove edges between selected nodes", this); mRemoveSelectedEdges = new QAction("Remove edges between selected nodes", this);
@ -37,7 +37,7 @@ namespace CSVRender
void PathgridSelectionMode::removeSelectedNodes() void PathgridSelectionMode::removeSelectedNodes()
{ {
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_Pathgrid);
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it) for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
{ {
@ -54,7 +54,7 @@ namespace CSVRender
void PathgridSelectionMode::removeSelectedEdges() void PathgridSelectionMode::removeSelectedEdges()
{ {
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (Mask_Pathgrid); std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getSelection (SceneUtil::Mask_Pathgrid);
for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it) for (std::vector<osg::ref_ptr<TagBase> >::iterator it = selection.begin(); it != selection.end(); ++it)
{ {

View file

@ -17,6 +17,7 @@
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/lightmanager.hpp> #include <components/sceneutil/lightmanager.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
@ -25,7 +26,6 @@
#include "../../model/prefs/shortcuteventhandler.hpp" #include "../../model/prefs/shortcuteventhandler.hpp"
#include "lighting.hpp" #include "lighting.hpp"
#include "mask.hpp"
#include "cameracontroller.hpp" #include "cameracontroller.hpp"
namespace CSVRender namespace CSVRender
@ -71,7 +71,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager;
lightMgr->setStartLight(1); lightMgr->setStartLight(1);
lightMgr->setLightingMask(Mask_Lighting); lightMgr->setLightingMask(SceneUtil::Mask_Lighting);
mRootNode = lightMgr; mRootNode = lightMgr;
mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); mView->getCamera()->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
@ -88,7 +88,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
// Add ability to signal osg to show its statistics for debugging purposes // Add ability to signal osg to show its statistics for debugging purposes
mView->addEventHandler(new osgViewer::StatsHandler); mView->addEventHandler(new osgViewer::StatsHandler);
mView->getCamera()->setCullMask(~(Mask_UpdateVisitor)); mView->getCamera()->setCullMask(~(SceneUtil::Mask_UpdateVisitor));
viewer.addView(mView); viewer.addView(mView);
viewer.setDone(false); viewer.setDone(false);
@ -100,6 +100,14 @@ RenderWidget::~RenderWidget()
try try
{ {
CompositeViewer::get().removeView(mView); CompositeViewer::get().removeView(mView);
#if OSG_VERSION_LESS_THAN(3,6,5)
// before OSG 3.6.4, the default font was a static object, and if it wasn't attached to the scene when a graphics context was destroyed, it's program wouldn't be released.
// 3.6.4 moved it into the object cache, which meant it usually got released, but not here.
// 3.6.5 improved cleanup with osgViewer::CompositeViewer::removeView so it more reliably released associated state for objects in the object cache.
osg::ref_ptr<osg::GraphicsContext> graphicsContext = mView->getCamera()->getGraphicsContext();
osgText::Font::getDefaultFont()->releaseGLObjects(graphicsContext->getState());
#endif
} }
catch(const std::exception& e) catch(const std::exception& e)
{ {
@ -114,7 +122,7 @@ void RenderWidget::flagAsModified()
void RenderWidget::setVisibilityMask(int mask) void RenderWidget::setVisibilityMask(int mask)
{ {
mView->getCamera()->setCullMask(mask | Mask_ParticleSystem | Mask_Lighting); mView->getCamera()->setCullMask(mask | SceneUtil::Mask_ParticleSystem | SceneUtil::Mask_Lighting);
} }
osg::Camera *RenderWidget::getCamera() osg::Camera *RenderWidget::getCamera()
@ -204,7 +212,7 @@ SceneWidget::SceneWidget(std::shared_ptr<Resource::ResourceSystem> resourceSyste
mOrbitCamControl = new OrbitCameraController(this); mOrbitCamControl = new OrbitCameraController(this);
mCurrentCamControl = mFreeCamControl; mCurrentCamControl = mFreeCamControl;
mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); mOrbitCamControl->setPickingMask(SceneUtil::Mask_EditorReference | SceneUtil::Mask_Terrain);
mOrbitCamControl->setConstRoll( CSMPrefs::get()["3D Scene Input"]["navi-orbit-const-roll"].isTrue() ); mOrbitCamControl->setConstRoll( CSMPrefs::get()["3D Scene Input"]["navi-orbit-const-roll"].isTrue() );
@ -213,7 +221,7 @@ SceneWidget::SceneWidget(std::shared_ptr<Resource::ResourceSystem> resourceSyste
setLighting(&mLightingDay); setLighting(&mLightingDay);
mResourceSystem->getSceneManager()->setParticleSystemMask(Mask_ParticleSystem); mResourceSystem->getSceneManager()->setParticleSystemMask(SceneUtil::Mask_ParticleSystem);
// Recieve mouse move event even if mouse button is not pressed // Recieve mouse move event even if mouse button is not pressed
setMouseTracking(true); setMouseTracking(true);
@ -342,7 +350,7 @@ void SceneWidget::update(double dt)
} }
else else
{ {
mCurrentCamControl->setup(mRootNode, Mask_Reference | Mask_Terrain, CameraController::WorldUp); mCurrentCamControl->setup(mRootNode, SceneUtil::Mask_EditorReference | SceneUtil::Mask_Terrain, CameraController::WorldUp);
mCamPositionSet = true; mCamPositionSet = true;
} }
} }

View file

@ -3,8 +3,6 @@
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
#include "mask.hpp"
class QAction; class QAction;
namespace CSVRender namespace CSVRender

View file

@ -1,9 +1,9 @@
#include "tagbase.hpp" #include "tagbase.hpp"
CSVRender::TagBase::TagBase (Mask mask) : mMask (mask) {} CSVRender::TagBase::TagBase (SceneUtil::VisMask mask) : mMask (mask) {}
CSVRender::Mask CSVRender::TagBase::getMask() const SceneUtil::VisMask CSVRender::TagBase::getMask() const
{ {
return mMask; return mMask;
} }

View file

@ -5,19 +5,19 @@
#include <QString> #include <QString>
#include "mask.hpp" #include <components/sceneutil/vismask.hpp>
namespace CSVRender namespace CSVRender
{ {
class TagBase : public osg::Referenced class TagBase : public osg::Referenced
{ {
Mask mMask; SceneUtil::VisMask mMask;
public: public:
TagBase (Mask mask); TagBase (SceneUtil::VisMask mask);
Mask getMask() const; SceneUtil::VisMask getMask() const;
virtual QString getToolTip (bool hideBasics) const; virtual QString getToolTip (bool hideBasics) const;

View file

@ -17,6 +17,7 @@
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../widget/brushshapes.hpp" #include "../widget/brushshapes.hpp"
#include "../widget/modebutton.hpp" #include "../widget/modebutton.hpp"
@ -38,13 +39,12 @@
#include "editmode.hpp" #include "editmode.hpp"
#include "pagedworldspacewidget.hpp" #include "pagedworldspacewidget.hpp"
#include "mask.hpp"
#include "tagbase.hpp" #include "tagbase.hpp"
#include "terrainselection.hpp" #include "terrainselection.hpp"
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
CSVRender::TerrainShapeMode::TerrainShapeMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent) CSVRender::TerrainShapeMode::TerrainShapeMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-shape"}, Mask_Terrain | Mask_Reference, "Terrain land editing", parent), : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-shape"}, SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference, "Terrain land editing", parent),
mParentNode(parentNode) mParentNode(parentNode)
{ {
} }
@ -273,7 +273,6 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
*document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures)); *document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures));
int landshapeColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandHeightsIndex); int landshapeColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandHeightsIndex);
int landMapLodColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandMapLodIndex);
int landnormalsColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandNormalsIndex); int landnormalsColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandNormalsIndex);
QUndoStack& undoStack = document.getUndoStack(); QUndoStack& undoStack = document.getUndoStack();
@ -287,9 +286,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoordinates.getX(), cellCoordinates.getY()); std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoordinates.getX(), cellCoordinates.getY());
undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId)); undoStack.push (new CSMWorld::TouchLandCommand(landTable, ltexTable, cellId));
const CSMWorld::LandHeightsColumn::DataType landShapePointer = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>(); const CSMWorld::LandHeightsColumn::DataType landShapePointer = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
const CSMWorld::LandMapLodColumn::DataType landMapLodPointer = landTable.data(landTable.getModelIndex(cellId, landMapLodColumn)).value<CSMWorld::LandMapLodColumn::DataType>();
CSMWorld::LandHeightsColumn::DataType landShapeNew(landShapePointer); CSMWorld::LandHeightsColumn::DataType landShapeNew(landShapePointer);
CSMWorld::LandMapLodColumn::DataType mapLodShapeNew(landMapLodPointer);
CSVRender::PagedWorldspaceWidget *paged = dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()); CSVRender::PagedWorldspaceWidget *paged = dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget());
// Generate land height record // Generate land height record
@ -304,26 +301,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
} }
} }
// Generate WNAM record
int sqrtLandGlobalMapLodSize = sqrt(ESM::Land::LAND_GLOBAL_MAP_LOD_SIZE);
for(int i = 0; i < sqrtLandGlobalMapLodSize; ++i)
{
for(int j = 0; j < sqrtLandGlobalMapLodSize; ++j)
{
int col = (static_cast<float>(j) / sqrtLandGlobalMapLodSize) * (ESM::Land::LAND_SIZE - 1);
int row = (static_cast<float>(i) / sqrtLandGlobalMapLodSize) * (ESM::Land::LAND_SIZE - 1);
signed char lodHeight = 0;
float floatLodHeight = 0;
if (landShapeNew[col * ESM::Land::LAND_SIZE + row] > 0) floatLodHeight = landShapeNew[col * ESM::Land::LAND_SIZE + row] / 128;
if (landShapeNew[col * ESM::Land::LAND_SIZE + row] <= 0) floatLodHeight = landShapeNew[col * ESM::Land::LAND_SIZE + row] / 16;
if (floatLodHeight > std::numeric_limits<signed char>::max()) lodHeight = std::numeric_limits<signed char>::max();
else if (floatLodHeight < std::numeric_limits<signed char>::min()) lodHeight = std::numeric_limits<signed char>::min();
else lodHeight = static_cast<signed char>(floatLodHeight);
mapLodShapeNew[j * sqrtLandGlobalMapLodSize + i] = lodHeight;
}
}
pushEditToCommand(landShapeNew, document, landTable, cellId); pushEditToCommand(landShapeNew, document, landTable, cellId);
pushLodToCommand(mapLodShapeNew, document, landTable, cellId);
} }
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells) for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
@ -1136,18 +1114,6 @@ void CSVRender::TerrainShapeMode::pushNormalsEditToCommand(const CSMWorld::LandN
undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand)); undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLand));
} }
void CSVRender::TerrainShapeMode::pushLodToCommand(const CSMWorld::LandMapLodColumn::DataType& newLandMapLod, CSMDoc::Document& document,
CSMWorld::IdTable& landTable, const std::string& cellId)
{
QVariant changedLod;
changedLod.setValue(newLandMapLod);
QModelIndex index(landTable.getModelIndex (cellId, landTable.findColumnIndex (CSMWorld::Columns::ColumnId_LandMapLodIndex)));
QUndoStack& undoStack = document.getUndoStack();
undoStack.push (new CSMWorld::ModifyCommand(landTable, index, changedLod));
}
bool CSVRender::TerrainShapeMode::noCell(const std::string& cellId) bool CSVRender::TerrainShapeMode::noCell(const std::string& cellId)
{ {
CSMDoc::Document& document = getWorldspaceWidget().getDocument(); CSMDoc::Document& document = getWorldspaceWidget().getDocument();

View file

@ -148,10 +148,6 @@ namespace CSVRender
void pushNormalsEditToCommand(const CSMWorld::LandNormalsColumn::DataType& newLandGrid, CSMDoc::Document& document, void pushNormalsEditToCommand(const CSMWorld::LandNormalsColumn::DataType& newLandGrid, CSMDoc::Document& document,
CSMWorld::IdTable& landTable, const std::string& cellId); CSMWorld::IdTable& landTable, const std::string& cellId);
/// Generate new land map LOD
void pushLodToCommand(const CSMWorld::LandMapLodColumn::DataType& newLandMapLod, CSMDoc::Document& document,
CSMWorld::IdTable& landTable, const std::string& cellId);
bool noCell(const std::string& cellId); bool noCell(const std::string& cellId);
bool noLand(const std::string& cellId); bool noLand(const std::string& cellId);

View file

@ -13,6 +13,7 @@
#include <osg/Group> #include <osg/Group>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../widget/modebutton.hpp" #include "../widget/modebutton.hpp"
#include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolbar.hpp"
@ -34,12 +35,11 @@
#include "editmode.hpp" #include "editmode.hpp"
#include "pagedworldspacewidget.hpp" #include "pagedworldspacewidget.hpp"
#include "mask.hpp"
#include "object.hpp" // Something small needed regarding pointers from here () #include "object.hpp" // Something small needed regarding pointers from here ()
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent) CSVRender::TerrainTextureMode::TerrainTextureMode (WorldspaceWidget *worldspaceWidget, osg::Group* parentNode, QWidget *parent)
: EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, Mask_Terrain | Mask_Reference, "Terrain texture editing", parent), : EditMode (worldspaceWidget, QIcon {":scenetoolbar/editing-terrain-texture"}, SceneUtil::Mask_Terrain | SceneUtil::Mask_EditorReference, "Terrain texture editing", parent),
mBrushTexture("L0#0"), mBrushTexture("L0#0"),
mBrushSize(1), mBrushSize(1),
mBrushShape(0), mBrushShape(0),

View file

@ -16,7 +16,6 @@
#include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetooltoggle2.hpp"
#include "cameracontroller.hpp" #include "cameracontroller.hpp"
#include "mask.hpp"
#include "tagbase.hpp" #include "tagbase.hpp"
void CSVRender::UnpagedWorldspaceWidget::update() void CSVRender::UnpagedWorldspaceWidget::update()
@ -304,8 +303,8 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle2 *tool) CSVWidget::SceneToolToggle2 *tool)
{ {
WorldspaceWidget::addVisibilitySelectorButtons (tool); WorldspaceWidget::addVisibilitySelectorButtons (tool);
tool->addButton (Button_Terrain, Mask_Terrain, "Terrain", "", true); tool->addButton (Button_Terrain, SceneUtil::Mask_Terrain, "Terrain", "", true);
tool->addButton (Button_Fog, Mask_Fog, "Fog"); //tool->addButton (Button_Fog, Mask_Fog, "Fog");
} }
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()

View file

@ -26,8 +26,9 @@
#include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetooltoggle2.hpp"
#include "../widget/scenetoolrun.hpp" #include "../widget/scenetoolrun.hpp"
#include <components/sceneutil/vismask.hpp>
#include "object.hpp" #include "object.hpp"
#include "mask.hpp"
#include "instancemode.hpp" #include "instancemode.hpp"
#include "pathgridmode.hpp" #include "pathgridmode.hpp"
#include "cameracontroller.hpp" #include "cameracontroller.hpp"
@ -138,7 +139,7 @@ void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setti
{ {
float alpha = setting->toDouble(); float alpha = setting->toDouble();
// getSelection is virtual, thus this can not be called from the constructor // getSelection is virtual, thus this can not be called from the constructor
auto selection = getSelection(Mask_Reference); auto selection = getSelection(SceneUtil::Mask_EditorReference);
for (osg::ref_ptr<TagBase> tag : selection) for (osg::ref_ptr<TagBase> tag : selection)
{ {
if (auto objTag = dynamic_cast<ObjectTag*>(tag.get())) if (auto objTag = dynamic_cast<ObjectTag*>(tag.get()))
@ -345,7 +346,7 @@ unsigned int CSVRender::WorldspaceWidget::getVisibilityMask() const
void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask) void CSVRender::WorldspaceWidget::setInteractionMask (unsigned int mask)
{ {
mInteractionMask = mask | Mask_CellMarker | Mask_CellArrow; mInteractionMask = mask | SceneUtil::Mask_EditorCellMarker | SceneUtil::Mask_EditorCellArrow;
} }
unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const
@ -361,15 +362,15 @@ void CSVRender::WorldspaceWidget::setEditLock (bool locked)
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle2 *tool) CSVWidget::SceneToolToggle2 *tool)
{ {
tool->addButton (Button_Reference, Mask_Reference, "Instances"); tool->addButton (Button_Reference, SceneUtil::Mask_EditorReference, "Instances");
tool->addButton (Button_Water, Mask_Water, "Water"); tool->addButton (Button_Water, SceneUtil::Mask_Water, "Water");
tool->addButton (Button_Pathgrid, Mask_Pathgrid, "Pathgrid"); tool->addButton (Button_Pathgrid, SceneUtil::Mask_Pathgrid, "Pathgrid");
} }
void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool)
{ {
/// \todo replace EditMode with suitable subclasses /// \todo replace EditMode with suitable subclasses
tool->addButton (new InstanceMode (this, tool), "object"); tool->addButton (new InstanceMode (this, mRootNode, tool), "object");
tool->addButton (new PathgridMode (this, tool), "pathgrid"); tool->addButton (new PathgridMode (this, tool), "pathgrid");
} }

View file

@ -8,7 +8,6 @@
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "scenewidget.hpp" #include "scenewidget.hpp"
#include "mask.hpp"
namespace CSMPrefs namespace CSMPrefs
{ {

View file

@ -18,10 +18,10 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER}) source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths renderbin actoranimation landmanager navmesh actorspaths recastmesh
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput

View file

@ -26,6 +26,7 @@
#include <components/compiler/extensions0.hpp> #include <components/compiler/extensions0.hpp>
#include <components/sceneutil/vismask.hpp>
#include <components/sceneutil/workqueue.hpp> #include <components/sceneutil/workqueue.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
@ -47,8 +48,6 @@
#include "mwworld/player.hpp" #include "mwworld/player.hpp"
#include "mwworld/worldimp.hpp" #include "mwworld/worldimp.hpp"
#include "mwrender/vismask.hpp"
#include "mwclass/classes.hpp" #include "mwclass/classes.hpp"
#include "mwdialogue/dialoguemanagerimp.hpp" #include "mwdialogue/dialoguemanagerimp.hpp"
@ -558,7 +557,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
std::string myguiResources = (mResDir / "mygui").string(); std::string myguiResources = (mResDir / "mygui").string();
osg::ref_ptr<osg::Group> guiRoot = new osg::Group; osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
guiRoot->setName("GUI Root"); guiRoot->setName("GUI Root");
guiRoot->setNodeMask(MWRender::Mask_GUI); guiRoot->setNodeMask(SceneUtil::Mask_GUI);
rootNode->addChild(guiRoot); rootNode->addChild(guiRoot);
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(), MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(),
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources, mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,

View file

@ -325,6 +325,8 @@ namespace MWBase
virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0;
virtual bool castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask, const MWWorld::ConstPtr& ignore) = 0;
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0; virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0; virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0;
@ -653,6 +655,8 @@ namespace MWBase
virtual MWPhysics::PhysicsSystem* getPhysicsSystem(void) = 0; virtual MWPhysics::PhysicsSystem* getPhysicsSystem(void) = 0;
virtual void toggleWaterRTT(bool enable) = 0; virtual void toggleWaterRTT(bool enable) = 0;
virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const = 0;
}; };
} }

View file

@ -3,6 +3,7 @@
#include <components/esm/loadacti.hpp> #include <components/esm/loadacti.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
@ -19,7 +20,6 @@
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwrender/vismask.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -34,7 +34,7 @@ namespace MWClass
if (!model.empty()) if (!model.empty())
{ {
renderingInterface.getObjects().insertModel(ptr, model, true); renderingInterface.getObjects().insertModel(ptr, model, true);
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); ptr.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Static);
} }
} }

View file

@ -317,7 +317,6 @@ namespace MWClass
{ {
if (!state.mHasCustomState) if (!state.mHasCustomState)
return; return;
const ESM::ContainerState& state2 = dynamic_cast<const ESM::ContainerState&> (state);
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
@ -326,21 +325,21 @@ namespace MWClass
ptr.getRefData().setCustomData (data.release()); ptr.getRefData().setCustomData (data.release());
} }
dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore. ContainerCustomData& customData = ptr.getRefData().getCustomData()->asContainerCustomData();
readState (state2.mInventory); const ESM::ContainerState& containerState = state.asContainerState();
customData.mContainerStore.readState (containerState.mInventory);
} }
void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const void Container::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
{ {
ESM::ContainerState& state2 = dynamic_cast<ESM::ContainerState&> (state);
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
state.mHasCustomState = false; state.mHasCustomState = false;
return; return;
} }
dynamic_cast<const ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore. const ContainerCustomData& customData = ptr.getRefData().getCustomData()->asContainerCustomData();
writeState (state2.mInventory); ESM::ContainerState& containerState = state.asContainerState();
customData.mContainerStore.writeState (containerState.mInventory);
} }
} }

View file

@ -777,8 +777,6 @@ namespace MWClass
if (!state.mHasCustomState) if (!state.mHasCustomState)
return; return;
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
if (state.mVersion > 0) if (state.mVersion > 0)
{ {
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
@ -798,16 +796,14 @@ namespace MWClass
ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData();
const ESM::CreatureState& creatureState = state.asCreatureState();
customData.mContainerStore->readState (state2.mInventory); customData.mContainerStore->readState (creatureState.mInventory);
customData.mCreatureStats.readState (state2.mCreatureStats); customData.mCreatureStats.readState (creatureState.mCreatureStats);
} }
void Creature::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) void Creature::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state)
const const
{ {
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
state.mHasCustomState = false; state.mHasCustomState = false;
@ -815,9 +811,9 @@ namespace MWClass
} }
const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData();
ESM::CreatureState& creatureState = state.asCreatureState();
customData.mContainerStore->writeState (state2.mInventory); customData.mContainerStore->writeState (creatureState.mInventory);
customData.mCreatureStats.writeState (state2.mCreatureStats); customData.mCreatureStats.writeState (creatureState.mCreatureStats);
} }
int Creature::getBaseGold(const MWWorld::ConstPtr& ptr) const int Creature::getBaseGold(const MWWorld::ConstPtr& ptr) const

View file

@ -151,19 +151,16 @@ namespace MWClass
if (!state.mHasCustomState) if (!state.mHasCustomState)
return; return;
const ESM::CreatureLevListState& state2 = dynamic_cast<const ESM::CreatureLevListState&> (state);
ensureCustomData(ptr); ensureCustomData(ptr);
CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData();
customData.mSpawnActorId = state2.mSpawnActorId; const ESM::CreatureLevListState& levListState = state.asCreatureLevListState();
customData.mSpawn = state2.mSpawn; customData.mSpawnActorId = levListState.mSpawnActorId;
customData.mSpawn = levListState.mSpawn;
} }
void CreatureLevList::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) void CreatureLevList::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state)
const const
{ {
ESM::CreatureLevListState& state2 = dynamic_cast<ESM::CreatureLevListState&> (state);
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
state.mHasCustomState = false; state.mHasCustomState = false;
@ -171,7 +168,8 @@ namespace MWClass
} }
const CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData(); const CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData();
state2.mSpawnActorId = customData.mSpawnActorId; ESM::CreatureLevListState& levListState = state.asCreatureLevListState();
state2.mSpawn = customData.mSpawn; levListState.mSpawnActorId = customData.mSpawnActorId;
levListState.mSpawn = customData.mSpawn;
} }
} }

View file

@ -3,6 +3,7 @@
#include <components/esm/loaddoor.hpp> #include <components/esm/loaddoor.hpp>
#include <components/esm/doorstate.hpp> #include <components/esm/doorstate.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -25,7 +26,6 @@
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwrender/animation.hpp" #include "../mwrender/animation.hpp"
#include "../mwrender/vismask.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
@ -58,7 +58,7 @@ namespace MWClass
if (!model.empty()) if (!model.empty())
{ {
renderingInterface.getObjects().insertModel(ptr, model, true); renderingInterface.getObjects().insertModel(ptr, model, true);
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); ptr.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Static);
} }
} }
@ -370,11 +370,11 @@ namespace MWClass
{ {
if (!state.mHasCustomState) if (!state.mHasCustomState)
return; return;
ensureCustomData(ptr); ensureCustomData(ptr);
DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
const ESM::DoorState& doorState = state.asDoorState();
const ESM::DoorState& state2 = dynamic_cast<const ESM::DoorState&>(state); customData.mDoorState = MWWorld::DoorState(doorState.mDoorState);
customData.mDoorState = static_cast<MWWorld::DoorState>(state2.mDoorState);
} }
void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
@ -384,10 +384,10 @@ namespace MWClass
state.mHasCustomState = false; state.mHasCustomState = false;
return; return;
} }
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
ESM::DoorState& doorState = state.asDoorState();
ESM::DoorState& state2 = dynamic_cast<ESM::DoorState&>(state); doorState.mDoorState = int(customData.mDoorState);
state2.mDoorState = static_cast<int>(customData.mDoorState);
} }
} }

View file

@ -1307,8 +1307,6 @@ namespace MWClass
if (!state.mHasCustomState) if (!state.mHasCustomState)
return; return;
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
if (state.mVersion > 0) if (state.mVersion > 0)
{ {
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
@ -1322,17 +1320,15 @@ namespace MWClass
ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless. ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
const ESM::NpcState& npcState = state.asNpcState();
customData.mInventoryStore.readState (state2.mInventory); customData.mInventoryStore.readState (npcState.mInventory);
customData.mNpcStats.readState (state2.mNpcStats); customData.mNpcStats.readState (npcState.mNpcStats);
static_cast<MWMechanics::CreatureStats&> (customData.mNpcStats).readState (state2.mCreatureStats); customData.mNpcStats.readState (npcState.mCreatureStats);
} }
void Npc::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) void Npc::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state)
const const
{ {
ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state);
if (!ptr.getRefData().getCustomData()) if (!ptr.getRefData().getCustomData())
{ {
state.mHasCustomState = false; state.mHasCustomState = false;
@ -1340,10 +1336,10 @@ namespace MWClass
} }
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
ESM::NpcState& npcState = state.asNpcState();
customData.mInventoryStore.writeState (state2.mInventory); customData.mInventoryStore.writeState (npcState.mInventory);
customData.mNpcStats.writeState (state2.mNpcStats); customData.mNpcStats.writeState (npcState.mNpcStats);
static_cast<const MWMechanics::CreatureStats&> (customData.mNpcStats).writeState (state2.mCreatureStats); customData.mNpcStats.writeState (npcState.mCreatureStats);
} }
int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const

View file

@ -2,6 +2,7 @@
#include <components/esm/loadstat.hpp> #include <components/esm/loadstat.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwphysics/physicssystem.hpp" #include "../mwphysics/physicssystem.hpp"
@ -9,7 +10,6 @@
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwrender/vismask.hpp"
namespace MWClass namespace MWClass
{ {
@ -19,7 +19,7 @@ namespace MWClass
if (!model.empty()) if (!model.empty())
{ {
renderingInterface.getObjects().insertModel(ptr, model); renderingInterface.getObjects().insertModel(ptr, model);
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); ptr.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Static);
} }
} }

View file

@ -3,6 +3,7 @@
#include <MyGUI_Gui.h> #include <MyGUI_Gui.h>
#include <MyGUI_Button.h> #include <MyGUI_Button.h>
#include <MyGUI_EditBox.h> #include <MyGUI_EditBox.h>
#include <MyGUI_ComboBox.h>
#include <MyGUI_ControllerManager.h> #include <MyGUI_ControllerManager.h>
#include <MyGUI_ControllerRepeatClick.h> #include <MyGUI_ControllerRepeatClick.h>
@ -17,6 +18,7 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include <MyGUI_Macros.h>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include "inventoryitemmodel.hpp" #include "inventoryitemmodel.hpp"
@ -29,6 +31,7 @@ namespace MWGui
{ {
AlchemyWindow::AlchemyWindow() AlchemyWindow::AlchemyWindow()
: WindowBase("openmw_alchemy_window.layout") : WindowBase("openmw_alchemy_window.layout")
, mModel(nullptr)
, mSortModel(nullptr) , mSortModel(nullptr)
, mAlchemy(new MWMechanics::Alchemy()) , mAlchemy(new MWMechanics::Alchemy())
, mApparatus (4) , mApparatus (4)
@ -50,6 +53,8 @@ namespace MWGui
getWidget(mDecreaseButton, "DecreaseButton"); getWidget(mDecreaseButton, "DecreaseButton");
getWidget(mNameEdit, "NameEdit"); getWidget(mNameEdit, "NameEdit");
getWidget(mItemView, "ItemView"); getWidget(mItemView, "ItemView");
getWidget(mFilterValue, "FilterValue");
getWidget(mFilterType, "FilterType");
mBrewCountEdit->eventValueChanged += MyGUI::newDelegate(this, &AlchemyWindow::onCountValueChanged); mBrewCountEdit->eventValueChanged += MyGUI::newDelegate(this, &AlchemyWindow::onCountValueChanged);
mBrewCountEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept); mBrewCountEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept);
@ -72,6 +77,9 @@ namespace MWGui
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept); mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept);
mFilterValue->eventComboChangePosition += MyGUI::newDelegate(this, &AlchemyWindow::onFilterChanged);
mFilterValue->eventEditTextChange += MyGUI::newDelegate(this, &AlchemyWindow::onFilterEdited);
mFilterType->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::switchFilterType);
center(); center();
} }
@ -136,16 +144,110 @@ namespace MWGui
removeIngredient(mIngredients[i]); removeIngredient(mIngredients[i]);
} }
updateFilters();
update(); update();
} }
void AlchemyWindow::initFilter()
{
auto const& wm = MWBase::Environment::get().getWindowManager();
auto const ingredient = wm->getGameSettingString("sIngredients", "Ingredients");
auto const effect = wm->getGameSettingString("sMagicEffects", "Magic Effects");
if (mFilterType->getCaption() == ingredient)
mCurrentFilter = FilterType::ByName;
else
mCurrentFilter = FilterType::ByEffect;
updateFilters();
mFilterValue->clearIndexSelected();
updateFilters();
}
void AlchemyWindow::switchFilterType(MyGUI::Widget* _sender)
{
auto const& wm = MWBase::Environment::get().getWindowManager();
auto const ingredient = wm->getGameSettingString("sIngredients", "Ingredients");
auto const effect = wm->getGameSettingString("sMagicEffects", "Magic Effects");
auto *button = _sender->castType<MyGUI::Button>();
if (button->getCaption() == ingredient)
{
button->setCaption(effect);
mCurrentFilter = FilterType::ByEffect;
}
else
{
button->setCaption(ingredient);
mCurrentFilter = FilterType::ByName;
}
mSortModel->setNameFilter({});
mSortModel->setEffectFilter({});
mFilterValue->clearIndexSelected();
updateFilters();
mItemView->update();
}
void AlchemyWindow::updateFilters()
{
std::set<std::string> itemNames, itemEffects;
for (size_t i = 0; i < mModel->getItemCount(); ++i)
{
auto const& base = mModel->getItem(i).mBase;
if (base.getTypeName() != typeid(ESM::Ingredient).name())
continue;
itemNames.insert(base.getClass().getName(base));
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
auto const alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
auto const effects = MWMechanics::Alchemy::effectsDescription(base, alchemySkill);
itemEffects.insert(effects.begin(), effects.end());
}
mFilterValue->removeAllItems();
auto const addItems = [&](auto const& container)
{
for (auto const& item : container)
mFilterValue->addItem(item);
};
switch (mCurrentFilter)
{
case FilterType::ByName: addItems(itemNames); break;
case FilterType::ByEffect: addItems(itemEffects); break;
}
}
void AlchemyWindow::applyFilter(const std::string& filter)
{
switch (mCurrentFilter)
{
case FilterType::ByName: mSortModel->setNameFilter(filter); break;
case FilterType::ByEffect: mSortModel->setEffectFilter(filter); break;
}
mItemView->update();
}
void AlchemyWindow::onFilterChanged(MyGUI::ComboBox* _sender, size_t _index)
{
// ignore spurious event fired when one edit the content after selection.
// onFilterEdited will handle it.
if (_index != MyGUI::ITEM_NONE)
applyFilter(_sender->getItemNameAt(_index));
}
void AlchemyWindow::onFilterEdited(MyGUI::EditBox* _sender)
{
applyFilter(_sender->getCaption());
}
void AlchemyWindow::onOpen() void AlchemyWindow::onOpen()
{ {
mAlchemy->clear(); mAlchemy->clear();
mAlchemy->setAlchemist (MWMechanics::getPlayer()); mAlchemy->setAlchemist (MWMechanics::getPlayer());
InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); mModel = new InventoryItemModel(MWMechanics::getPlayer());
mSortModel = new SortFilterItemModel(model); mSortModel = new SortFilterItemModel(mModel);
mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients);
mItemView->setModel (mSortModel); mItemView->setModel (mSortModel);
mItemView->resetScrollBars(); mItemView->resetScrollBars();
@ -167,6 +269,7 @@ namespace MWGui
} }
update(); update();
initFilter();
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
} }

View file

@ -5,7 +5,9 @@
#include <vector> #include <vector>
#include <MyGUI_ControllerItem.h> #include <MyGUI_ControllerItem.h>
#include <MyGUI_ComboBox.h>
#include <components/widgets/box.hpp>
#include <components/widgets/numericeditbox.hpp> #include <components/widgets/numericeditbox.hpp>
#include "windowbase.hpp" #include "windowbase.hpp"
@ -19,6 +21,7 @@ namespace MWGui
{ {
class ItemView; class ItemView;
class ItemWidget; class ItemWidget;
class InventoryItemModel;
class SortFilterItemModel; class SortFilterItemModel;
class AlchemyWindow : public WindowBase class AlchemyWindow : public WindowBase
@ -36,8 +39,11 @@ namespace MWGui
static const float sCountChangeInterval; // in seconds static const float sCountChangeInterval; // in seconds
std::string mSuggestedPotionName; std::string mSuggestedPotionName;
enum class FilterType { ByName, ByEffect };
FilterType mCurrentFilter;
ItemView* mItemView; ItemView* mItemView;
InventoryItemModel* mModel;
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
MyGUI::Button* mCreateButton; MyGUI::Button* mCreateButton;
@ -47,6 +53,8 @@ namespace MWGui
MyGUI::Button* mIncreaseButton; MyGUI::Button* mIncreaseButton;
MyGUI::Button* mDecreaseButton; MyGUI::Button* mDecreaseButton;
Gui::AutoSizedButton* mFilterType;
MyGUI::ComboBox* mFilterValue;
MyGUI::EditBox* mNameEdit; MyGUI::EditBox* mNameEdit;
Gui::NumericEditBox* mBrewCountEdit; Gui::NumericEditBox* mBrewCountEdit;
@ -60,6 +68,13 @@ namespace MWGui
void onCountValueChanged(int value); void onCountValueChanged(int value);
void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller); void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller);
void applyFilter(const std::string& filter);
void initFilter();
void onFilterChanged(MyGUI::ComboBox* _sender, size_t _index);
void onFilterEdited(MyGUI::EditBox* _sender);
void switchFilterType(MyGUI::Widget* _sender);
void updateFilters();
void addRepeatController(MyGUI::Widget* widget); void addRepeatController(MyGUI::Widget* widget);
void onIncreaseButtonTriggered(); void onIncreaseButtonTriggered();

View file

@ -9,7 +9,7 @@ namespace MWGui
/** /**
* @brief A variant of MyGUI::ImageBox with aspect ratio correction using black bars * @brief A variant of MyGUI::ImageBox with aspect ratio correction using black bars
*/ */
class BackgroundImage : public MyGUI::ImageBox class BackgroundImage final : public MyGUI::ImageBox
{ {
MYGUI_RTTI_DERIVED(BackgroundImage) MYGUI_RTTI_DERIVED(BackgroundImage)
@ -22,8 +22,8 @@ namespace MWGui
*/ */
void setBackgroundImage (const std::string& image, bool fixedRatio=true, bool stretch=true); void setBackgroundImage (const std::string& image, bool fixedRatio=true, bool stretch=true);
virtual void setSize (const MyGUI::IntSize &_value); void setSize (const MyGUI::IntSize &_value) final;
virtual void setCoord (const MyGUI::IntCoord &_value); void setCoord (const MyGUI::IntCoord &_value) final;
private: private:
MyGUI::ImageBox* mChild; MyGUI::ImageBox* mChild;

View file

@ -817,7 +817,7 @@ namespace
}; };
} }
class PageDisplay : public MyGUI::ISubWidgetText class PageDisplay final : public MyGUI::ISubWidgetText
{ {
MYGUI_RTTI_DERIVED(PageDisplay) MYGUI_RTTI_DERIVED(PageDisplay)
protected: protected:
@ -1140,7 +1140,7 @@ public:
i->second->createDrawItem (mNode); i->second->createDrawItem (mNode);
} }
void setVisible (bool newVisible) void setVisible (bool newVisible) final
{ {
if (mVisible == newVisible) if (mVisible == newVisible)
return; return;
@ -1162,7 +1162,7 @@ public:
} }
} }
void createDrawItem(MyGUI::ITexture* texture, MyGUI::ILayerNode* node) void createDrawItem(MyGUI::ITexture* texture, MyGUI::ILayerNode* node) final
{ {
mNode = node; mNode = node;
@ -1230,9 +1230,9 @@ public:
// ISubWidget should not necessarily be a drawitem // ISubWidget should not necessarily be a drawitem
// in this case, it is not... // in this case, it is not...
void doRender() { } void doRender() final { }
void _updateView () void _updateView () final
{ {
_checkMargin(); _checkMargin();
@ -1241,7 +1241,7 @@ public:
mNode->outOfDate (i->second->mRenderItem); mNode->outOfDate (i->second->mRenderItem);
} }
void _correctView() void _correctView() final
{ {
_checkMargin (); _checkMargin ();
@ -1251,7 +1251,7 @@ public:
} }
void destroyDrawItem() void destroyDrawItem() final
{ {
for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i) for (ActiveTextFormats::iterator i = mActiveTextFormats.begin (); i != mActiveTextFormats.end (); ++i)
i->second->destroyDrawItem (mNode); i->second->destroyDrawItem (mNode);
@ -1261,7 +1261,7 @@ public:
}; };
class BookPageImpl : public BookPage class BookPageImpl final : public BookPage
{ {
MYGUI_RTTI_DERIVED(BookPage) MYGUI_RTTI_DERIVED(BookPage)
public: public:
@ -1271,24 +1271,24 @@ public:
{ {
} }
void showPage (TypesetBook::Ptr book, size_t page) void showPage (TypesetBook::Ptr book, size_t page) final
{ {
mPageDisplay->showPage (book, page); mPageDisplay->showPage (book, page);
} }
void adviseLinkClicked (std::function <void (InteractiveId)> linkClicked) void adviseLinkClicked (std::function <void (InteractiveId)> linkClicked) final
{ {
mPageDisplay->mLinkClicked = linkClicked; mPageDisplay->mLinkClicked = linkClicked;
} }
void unadviseLinkClicked () void unadviseLinkClicked () final
{ {
mPageDisplay->mLinkClicked = std::function <void (InteractiveId)> (); mPageDisplay->mLinkClicked = std::function <void (InteractiveId)> ();
} }
protected: protected:
virtual void initialiseOverride() void initialiseOverride() final
{ {
Base::initialiseOverride(); Base::initialiseOverride();
@ -1302,24 +1302,24 @@ protected:
} }
} }
void onMouseLostFocus(Widget* _new) void onMouseLostFocus(Widget* _new) final
{ {
// NOTE: MyGUI also fires eventMouseLostFocus for widgets that are about to be destroyed (if they had focus). // NOTE: MyGUI also fires eventMouseLostFocus for widgets that are about to be destroyed (if they had focus).
// Child widgets may already be destroyed! So be careful. // Child widgets may already be destroyed! So be careful.
mPageDisplay->onMouseLostFocus (); mPageDisplay->onMouseLostFocus ();
} }
void onMouseMove(int left, int top) void onMouseMove(int left, int top) final
{ {
mPageDisplay->onMouseMove (left, top); mPageDisplay->onMouseMove (left, top);
} }
void onMouseButtonPressed (int left, int top, MyGUI::MouseButton id) void onMouseButtonPressed (int left, int top, MyGUI::MouseButton id) final
{ {
mPageDisplay->onMouseButtonPressed (left, top, id); mPageDisplay->onMouseButtonPressed (left, top, id);
} }
void onMouseButtonReleased(int left, int top, MyGUI::MouseButton id) void onMouseButtonReleased(int left, int top, MyGUI::MouseButton id) final
{ {
mPageDisplay->onMouseButtonReleased (left, top, id); mPageDisplay->onMouseButtonReleased (left, top, id);
} }

View file

@ -46,9 +46,11 @@ CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* ma
getWidget(mCloseButton, "CloseButton"); getWidget(mCloseButton, "CloseButton");
getWidget(mProfitLabel, "ProfitLabel"); getWidget(mProfitLabel, "ProfitLabel");
getWidget(mEncumbranceBar, "EncumbranceBar"); getWidget(mEncumbranceBar, "EncumbranceBar");
getWidget(mFilterEdit, "FilterEdit");
getWidget(mItemView, "ItemView"); getWidget(mItemView, "ItemView");
mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &CompanionWindow::onBackgroundSelected); mItemView->eventBackgroundClicked += MyGUI::newDelegate(this, &CompanionWindow::onBackgroundSelected);
mItemView->eventItemClicked += MyGUI::newDelegate(this, &CompanionWindow::onItemSelected); mItemView->eventItemClicked += MyGUI::newDelegate(this, &CompanionWindow::onItemSelected);
mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &CompanionWindow::onNameFilterChanged);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked);
@ -92,6 +94,12 @@ void CompanionWindow::onItemSelected(int index)
dragItem (nullptr, count); dragItem (nullptr, count);
} }
void CompanionWindow::onNameFilterChanged(MyGUI::EditBox* _sender)
{
mSortModel->setNameFilter(_sender->getCaption());
mItemView->update();
}
void CompanionWindow::dragItem(MyGUI::Widget* sender, int count) void CompanionWindow::dragItem(MyGUI::Widget* sender, int count)
{ {
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count);
@ -113,6 +121,7 @@ void CompanionWindow::setPtr(const MWWorld::Ptr& npc)
mModel = new CompanionItemModel(npc); mModel = new CompanionItemModel(npc);
mSortModel = new SortFilterItemModel(mModel); mSortModel = new SortFilterItemModel(mModel);
mFilterEdit->setCaption(std::string());
mItemView->setModel(mSortModel); mItemView->setModel(mSortModel);
mItemView->resetScrollBars(); mItemView->resetScrollBars();

View file

@ -39,11 +39,13 @@ namespace MWGui
DragAndDrop* mDragAndDrop; DragAndDrop* mDragAndDrop;
MyGUI::Button* mCloseButton; MyGUI::Button* mCloseButton;
MyGUI::EditBox* mFilterEdit;
MyGUI::TextBox* mProfitLabel; MyGUI::TextBox* mProfitLabel;
Widgets::MWDynamicStat* mEncumbranceBar; Widgets::MWDynamicStat* mEncumbranceBar;
MessageBoxManager* mMessageBoxManager; MessageBoxManager* mMessageBoxManager;
void onItemSelected(int index); void onItemSelected(int index);
void onNameFilterChanged(MyGUI::EditBox* _sender);
void onBackgroundSelected(); void onBackgroundSelected();
void dragItem(MyGUI::Widget* sender, int count); void dragItem(MyGUI::Widget* sender, int count);

View file

@ -14,14 +14,14 @@ namespace MWGui
namespace Controllers namespace Controllers
{ {
/// Automatically positions a widget below the mouse cursor. /// Automatically positions a widget below the mouse cursor.
class ControllerFollowMouse : class ControllerFollowMouse final :
public MyGUI::ControllerItem public MyGUI::ControllerItem
{ {
MYGUI_RTTI_DERIVED( ControllerFollowMouse ) MYGUI_RTTI_DERIVED( ControllerFollowMouse )
private: private:
bool addTime(MyGUI::Widget* _widget, float _time); bool addTime(MyGUI::Widget* _widget, float _time) final;
void prepareItem(MyGUI::Widget* _widget); void prepareItem(MyGUI::Widget* _widget) final;
}; };
} }
} }

View file

@ -11,7 +11,7 @@ namespace MWGui
/// ResourceImageSetPointer that we need. /// ResourceImageSetPointer that we need.
/// \example MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer"); /// \example MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
/// MyGUI::ResourceManager::getInstance().load("core.xml"); /// MyGUI::ResourceManager::getInstance().load("core.xml");
class ResourceImageSetPointerFix : class ResourceImageSetPointerFix final :
public MyGUI::IPointer public MyGUI::IPointer
{ {
MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix ) MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix )
@ -20,17 +20,17 @@ namespace MWGui
ResourceImageSetPointerFix(); ResourceImageSetPointerFix();
virtual ~ResourceImageSetPointerFix(); virtual ~ResourceImageSetPointerFix();
virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) final;
virtual void setImage(MyGUI::ImageBox* _image); void setImage(MyGUI::ImageBox* _image) final;
virtual void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point); void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) final;
//and now for the whole point of this class, allow us to get //and now for the whole point of this class, allow us to get
//the hot spot, the image and the size of the cursor. //the hot spot, the image and the size of the cursor.
virtual MyGUI::ResourceImageSetPtr getImageSet(); MyGUI::ResourceImageSetPtr getImageSet();
virtual MyGUI::IntPoint getHotSpot(); MyGUI::IntPoint getHotSpot();
virtual MyGUI::IntSize getSize(); MyGUI::IntSize getSize();
virtual int getRotation(); int getRotation();
private: private:
MyGUI::IntPoint mPoint; MyGUI::IntPoint mPoint;

View file

@ -8,6 +8,7 @@
#include <MyGUI_RenderManager.h> #include <MyGUI_RenderManager.h>
#include <MyGUI_InputManager.h> #include <MyGUI_InputManager.h>
#include <MyGUI_Button.h> #include <MyGUI_Button.h>
#include <MyGUI_EditBox.h>
#include <osg/Texture2D> #include <osg/Texture2D>
@ -21,12 +22,10 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/actionequip.hpp" #include "../mwworld/actionequip.hpp"
#include "../mwscript/interpretercontext.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
@ -90,6 +89,7 @@ namespace MWGui
getWidget(mLeftPane, "LeftPane"); getWidget(mLeftPane, "LeftPane");
getWidget(mRightPane, "RightPane"); getWidget(mRightPane, "RightPane");
getWidget(mArmorRating, "ArmorRating"); getWidget(mArmorRating, "ArmorRating");
getWidget(mFilterEdit, "FilterEdit");
mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); mAvatarImage->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked);
mAvatarImage->setRenderItemTexture(mPreviewTexture.get()); mAvatarImage->setRenderItemTexture(mPreviewTexture.get());
@ -104,6 +104,7 @@ namespace MWGui
mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged);
mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &InventoryWindow::onNameFilterChanged);
mFilterAll->setStateSelected(true); mFilterAll->setStateSelected(true);
@ -133,6 +134,8 @@ namespace MWGui
else else
mSortModel = new SortFilterItemModel(mTradeModel); mSortModel = new SortFilterItemModel(mTradeModel);
mSortModel->setNameFilter(mFilterEdit->getCaption());
mItemView->setModel(mSortModel); mItemView->setModel(mSortModel);
mFilterAll->setStateSelected(true); mFilterAll->setStateSelected(true);
@ -388,6 +391,11 @@ namespace MWGui
void InventoryWindow::onOpen() void InventoryWindow::onOpen()
{ {
// Reset the filter focus when opening the window
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (focus == mFilterEdit)
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nullptr);
if (!mPtr.isEmpty()) if (!mPtr.isEmpty())
{ {
updateEncumbranceBar(); updateEncumbranceBar();
@ -465,6 +473,12 @@ namespace MWGui
width*mScaleFactor/float(mPreview->getTextureWidth()), height*mScaleFactor/float(mPreview->getTextureHeight()))); width*mScaleFactor/float(mPreview->getTextureWidth()), height*mScaleFactor/float(mPreview->getTextureHeight())));
} }
void InventoryWindow::onNameFilterChanged(MyGUI::EditBox* _sender)
{
mSortModel->setNameFilter(_sender->getCaption());
mItemView->update();
}
void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender)
{ {
if (_sender == mFilterAll) if (_sender == mFilterAll)
@ -477,7 +491,6 @@ namespace MWGui
mSortModel->setCategory(SortFilterItemModel::Category_Magic); mSortModel->setCategory(SortFilterItemModel::Category_Magic);
else if (_sender == mFilterMisc) else if (_sender == mFilterMisc)
mSortModel->setCategory(SortFilterItemModel::Category_Misc); mSortModel->setCategory(SortFilterItemModel::Category_Misc);
mFilterAll->setStateSelected(false); mFilterAll->setStateSelected(false);
mFilterWeapon->setStateSelected(false); mFilterWeapon->setStateSelected(false);
mFilterApparel->setStateSelected(false); mFilterApparel->setStateSelected(false);
@ -507,6 +520,16 @@ namespace MWGui
void InventoryWindow::useItem(const MWWorld::Ptr &ptr, bool force) void InventoryWindow::useItem(const MWWorld::Ptr &ptr, bool force)
{ {
const std::string& script = ptr.getClass().getScript(ptr); const std::string& script = ptr.getClass().getScript(ptr);
if (!script.empty())
{
// Don't try to equip the item if PCSkipEquip is set to 1
if (ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 1)
{
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
return;
}
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 0);
}
MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::Ptr player = MWMechanics::getPlayer();
@ -526,10 +549,6 @@ namespace MWGui
if (canEquip.first == 0) if (canEquip.first == 0)
{ {
/// If PCSkipEquip is set, set OnPCEquip to 1 and don't message anything
if (!script.empty() && ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 1)
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
else
MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second);
updateItemView(); updateItemView();
return; return;
@ -537,32 +556,21 @@ namespace MWGui
} }
} }
// If the item has a script, set its OnPcEquip to 1 // If the item has a script, set OnPCEquip or PCSkipEquip to 1
if (!script.empty() if (!script.empty())
// Another morrowind oddity: when an item has skipped equipping and pcskipequip is reset to 0 afterwards,
// the next time it is equipped will work normally, but will not set onpcequip
&& (ptr != mSkippedToEquip || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 1))
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
// Give the script a chance to run once before we do anything else
// this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this)
if (!force && !script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
{ {
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); // Ingredients, books and repair hammers must not have OnPCEquip set to 1 here
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); const std::string& type = ptr.getTypeName();
bool isBook = type == typeid(ESM::Book).name();
if (!isBook && type != typeid(ESM::Ingredient).name() && type != typeid(ESM::Repair).name())
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
// Books must have PCSkipEquip set to 1 instead
else if (isBook)
ptr.getRefData().getLocals().setVarByInt(script, "pcskipequip", 1);
} }
mSkippedToEquip = MWWorld::Ptr();
if (ptr.getRefData().getCount()) // make sure the item is still there, the script might have removed it
{
if (script.empty() || ptr.getRefData().getLocals().getIntVar(script, "pcskipequip") == 0)
{
std::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr, force); std::shared_ptr<MWWorld::Action> action = ptr.getClass().use(ptr, force);
action->execute(player); action->execute(player);
}
else
mSkippedToEquip = ptr;
}
if (isVisible()) if (isVisible())
{ {

View file

@ -93,7 +93,7 @@ namespace MWGui
MyGUI::Button* mFilterMagic; MyGUI::Button* mFilterMagic;
MyGUI::Button* mFilterMisc; MyGUI::Button* mFilterMisc;
MWWorld::Ptr mSkippedToEquip; MyGUI::EditBox* mFilterEdit;
GuiMode mGuiMode; GuiMode mGuiMode;
@ -121,6 +121,7 @@ namespace MWGui
void onWindowResize(MyGUI::Window* _sender); void onWindowResize(MyGUI::Window* _sender);
void onFilterChanged(MyGUI::Widget* _sender); void onFilterChanged(MyGUI::Widget* _sender);
void onNameFilterChanged(MyGUI::EditBox* _sender);
void onAvatarClicked(MyGUI::Widget* _sender); void onAvatarClicked(MyGUI::Widget* _sender);
void onPinToggled(); void onPinToggled();

View file

@ -21,7 +21,7 @@ namespace MWGui
class ItemModel; class ItemModel;
class ItemWidget; class ItemWidget;
class ItemChargeView : public MyGUI::Widget class ItemChargeView final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED(ItemChargeView) MYGUI_RTTI_DERIVED(ItemChargeView)
public: public:
@ -36,7 +36,7 @@ namespace MWGui
/// Register needed components with MyGUI's factory manager /// Register needed components with MyGUI's factory manager
static void registerComponents(); static void registerComponents();
virtual void initialiseOverride(); void initialiseOverride() final;
/// Takes ownership of \a model /// Takes ownership of \a model
void setModel(ItemModel* model); void setModel(ItemModel* model);
@ -47,8 +47,8 @@ namespace MWGui
void layoutWidgets(); void layoutWidgets();
void resetScrollbars(); void resetScrollbars();
virtual void setSize(const MyGUI::IntSize& value); void setSize(const MyGUI::IntSize& value) final;
virtual void setCoord(const MyGUI::IntCoord& value); void setCoord(const MyGUI::IntCoord& value) final;
MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked; MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked;

View file

@ -8,7 +8,7 @@
namespace MWGui namespace MWGui
{ {
class ItemView : public MyGUI::Widget class ItemView final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED(ItemView) MYGUI_RTTI_DERIVED(ItemView)
public: public:
@ -33,12 +33,12 @@ namespace MWGui
void resetScrollBars(); void resetScrollBars();
private: private:
virtual void initialiseOverride(); void initialiseOverride() final;
void layoutWidgets(); void layoutWidgets();
virtual void setSize(const MyGUI::IntSize& _value); void setSize(const MyGUI::IntSize& _value) final;
virtual void setCoord(const MyGUI::IntCoord& _value); void setCoord(const MyGUI::IntCoord& _value) final;
void onSelectedItem (MyGUI::Widget* sender); void onSelectedItem (MyGUI::Widget* sender);
void onSelectedBackground (MyGUI::Widget* sender); void onSelectedBackground (MyGUI::Widget* sender);

View file

@ -41,7 +41,7 @@ namespace MWGui
void setFrame (const std::string& frame, const MyGUI::IntCoord& coord); void setFrame (const std::string& frame, const MyGUI::IntCoord& coord);
protected: protected:
virtual void initialiseOverride(); void initialiseOverride() final;
MyGUI::ImageBox* mItem; MyGUI::ImageBox* mItem;
MyGUI::ImageBox* mItemShadow; MyGUI::ImageBox* mItemShadow;

View file

@ -16,9 +16,6 @@ namespace MWGui
bool shouldAcceptKeyFocus(MyGUI::Widget* w) bool shouldAcceptKeyFocus(MyGUI::Widget* w)
{ {
if (w && w->getUserString("IgnoreTabKey") == "y")
return false;
return w && !w->castType<MyGUI::Window>(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); return w && !w->castType<MyGUI::Window>(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled();
} }

View file

@ -14,14 +14,13 @@
#include <components/myguiplatform/myguitexture.hpp> #include <components/myguiplatform/myguitexture.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/sceneutil/vismask.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/statemanager.hpp" #include "../mwbase/statemanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
#include "../mwrender/vismask.hpp"
#include "backgroundimage.hpp" #include "backgroundimage.hpp"
namespace MWGui namespace MWGui
@ -335,8 +334,8 @@ namespace MWGui
// Turn off rendering except the GUI // Turn off rendering except the GUI
int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
int oldCullMask = mViewer->getCamera()->getCullMask(); int oldCullMask = mViewer->getCamera()->getCullMask();
mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI|MWRender::Mask_PreCompile); mViewer->getUpdateVisitor()->setTraversalMask(SceneUtil::Mask_GUI|SceneUtil::Mask_PreCompile);
mViewer->getCamera()->setCullMask(MWRender::Mask_GUI|MWRender::Mask_PreCompile); mViewer->getCamera()->setCullMask(SceneUtil::Mask_GUI|SceneUtil::Mask_PreCompile);
MWBase::Environment::get().getInputManager()->update(0, true, true); MWBase::Environment::get().getInputManager()->update(0, true, true);

View file

@ -54,7 +54,7 @@ namespace
/// @brief A widget that changes its color when hovered. /// @brief A widget that changes its color when hovered.
class MarkerWidget: public MyGUI::Widget class MarkerWidget final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED(MarkerWidget) MYGUI_RTTI_DERIVED(MarkerWidget)
@ -74,12 +74,12 @@ namespace
MyGUI::Colour mNormalColour; MyGUI::Colour mNormalColour;
MyGUI::Colour mHoverColour; MyGUI::Colour mHoverColour;
void onMouseLostFocus(MyGUI::Widget* _new) void onMouseLostFocus(MyGUI::Widget* _new) final
{ {
setColour(mNormalColour); setColour(mNormalColour);
} }
void onMouseSetFocus(MyGUI::Widget* _old) void onMouseSetFocus(MyGUI::Widget* _old) final
{ {
setColour(mHoverColour); setColour(mHoverColour);
} }

View file

@ -5,12 +5,12 @@
namespace MWGui namespace MWGui
{ {
class AutoSizedResourceSkin : public MyGUI::ResourceSkin class AutoSizedResourceSkin final : public MyGUI::ResourceSkin
{ {
MYGUI_RTTI_DERIVED( AutoSizedResourceSkin ) MYGUI_RTTI_DERIVED( AutoSizedResourceSkin )
public: public:
virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) final;
}; };
} }

View file

@ -23,6 +23,8 @@
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwmechanics/alchemy.hpp"
namespace namespace
{ {
bool compareType(const std::string& type1, const std::string& type2) bool compareType(const std::string& type1, const std::string& type2)
@ -151,6 +153,8 @@ namespace MWGui
: mCategory(Category_All) : mCategory(Category_All)
, mFilter(0) , mFilter(0)
, mSortByType(true) , mSortByType(true)
, mNameFilter("")
, mEffectFilter("")
{ {
mSourceModel = sourceModel; mSourceModel = sourceModel;
} }
@ -199,8 +203,39 @@ namespace MWGui
if (!(category & mCategory)) if (!(category & mCategory))
return false; return false;
if ((mFilter & Filter_OnlyIngredients) && base.getTypeName() != typeid(ESM::Ingredient).name()) if (mFilter & Filter_OnlyIngredients)
{
if (base.getTypeName() != typeid(ESM::Ingredient).name())
return false; return false;
if (!mNameFilter.empty() && !mEffectFilter.empty())
throw std::logic_error("name and magic effect filter are mutually exclusive");
if (!mNameFilter.empty())
{
const auto itemName = Misc::StringUtils::lowerCase(base.getClass().getName(base));
return itemName.find(mNameFilter) != std::string::npos;
}
if (!mEffectFilter.empty())
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
const auto alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
const auto effects = MWMechanics::Alchemy::effectsDescription(base, alchemySkill);
for (const auto& effect : effects)
{
const auto ciEffect = Misc::StringUtils::lowerCase(effect);
if (ciEffect.find(mEffectFilter) != std::string::npos)
return true;
}
return false;
}
return true;
}
if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted)) if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted))
return false; return false;
if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name() if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name()
@ -250,6 +285,10 @@ namespace MWGui
return false; return false;
} }
std::string compare = Misc::StringUtils::lowerCase(item.mBase.getClass().getName(item.mBase));
if(compare.find(mNameFilter) == std::string::npos)
return false;
return true; return true;
} }
@ -277,6 +316,16 @@ namespace MWGui
mFilter = filter; mFilter = filter;
} }
void SortFilterItemModel::setNameFilter (const std::string& filter)
{
mNameFilter = Misc::StringUtils::lowerCase(filter);
}
void SortFilterItemModel::setEffectFilter (const std::string& filter)
{
mEffectFilter = Misc::StringUtils::lowerCase(filter);
}
void SortFilterItemModel::update() void SortFilterItemModel::update()
{ {
mSourceModel->update(); mSourceModel->update();

View file

@ -25,6 +25,8 @@ namespace MWGui
void setCategory (int category); void setCategory (int category);
void setFilter (int filter); void setFilter (int filter);
void setNameFilter (const std::string& filter);
void setEffectFilter (const std::string& filter);
/// Use ItemStack::Type for sorting? /// Use ItemStack::Type for sorting?
void setSortByType(bool sort) { mSortByType = sort; } void setSortByType(bool sort) { mSortByType = sort; }
@ -57,6 +59,9 @@ namespace MWGui
int mCategory; int mCategory;
int mFilter; int mFilter;
bool mSortByType; bool mSortByType;
std::string mNameFilter; // filter by item name
std::string mEffectFilter; // filter by magic effect
}; };
} }

View file

@ -19,7 +19,7 @@ namespace MWGui
class SpellModel; class SpellModel;
///@brief Displays a SpellModel in a list widget ///@brief Displays a SpellModel in a list widget
class SpellView : public MyGUI::Widget class SpellView final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED(SpellView) MYGUI_RTTI_DERIVED(SpellView)
public: public:
@ -47,10 +47,10 @@ namespace MWGui
/// Fired when a spell was clicked /// Fired when a spell was clicked
EventHandle_ModelIndex eventSpellClicked; EventHandle_ModelIndex eventSpellClicked;
virtual void initialiseOverride(); void initialiseOverride() final;
virtual void setSize(const MyGUI::IntSize& _value); void setSize(const MyGUI::IntSize& _value) final;
virtual void setCoord(const MyGUI::IntCoord& _value); void setCoord(const MyGUI::IntCoord& _value) final;
void resetScrollbars(); void resetScrollbars();

View file

@ -45,8 +45,6 @@ namespace MWGui
getWidget(mEffectBox, "EffectsBox"); getWidget(mEffectBox, "EffectsBox");
getWidget(mFilterEdit, "FilterEdit"); getWidget(mFilterEdit, "FilterEdit");
mFilterEdit->setUserString("IgnoreTabKey", "y");
mSpellView->eventSpellClicked += MyGUI::newDelegate(this, &SpellWindow::onModelIndexSelected); mSpellView->eventSpellClicked += MyGUI::newDelegate(this, &SpellWindow::onModelIndexSelected);
mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &SpellWindow::onFilterChanged); mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &SpellWindow::onFilterChanged);
deleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onDeleteClicked); deleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onDeleteClicked);

View file

@ -69,6 +69,7 @@ namespace MWGui
getWidget(mTotalBalance, "TotalBalance"); getWidget(mTotalBalance, "TotalBalance");
getWidget(mTotalBalanceLabel, "TotalBalanceLabel"); getWidget(mTotalBalanceLabel, "TotalBalanceLabel");
getWidget(mBottomPane, "BottomPane"); getWidget(mBottomPane, "BottomPane");
getWidget(mFilterEdit, "FilterEdit");
getWidget(mItemView, "ItemView"); getWidget(mItemView, "ItemView");
mItemView->eventItemClicked += MyGUI::newDelegate(this, &TradeWindow::onItemSelected); mItemView->eventItemClicked += MyGUI::newDelegate(this, &TradeWindow::onItemSelected);
@ -80,6 +81,7 @@ namespace MWGui
mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged);
mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged);
mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged);
mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &TradeWindow::onNameFilterChanged);
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked);
mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked);
@ -135,8 +137,7 @@ namespace MWGui
setTitle(actor.getClass().getName(actor)); setTitle(actor.getClass().getName(actor));
onFilterChanged(mFilterAll); onFilterChanged(mFilterAll);
mFilterEdit->setCaption("");
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTotalBalance);
} }
void TradeWindow::onFrame(float dt) void TradeWindow::onFrame(float dt)
@ -144,6 +145,12 @@ namespace MWGui
checkReferenceAvailable(); checkReferenceAvailable();
} }
void TradeWindow::onNameFilterChanged(MyGUI::EditBox* _sender)
{
mSortModel->setNameFilter(_sender->getCaption());
mItemView->update();
}
void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) void TradeWindow::onFilterChanged(MyGUI::Widget* _sender)
{ {
if (_sender == mFilterAll) if (_sender == mFilterAll)

View file

@ -59,6 +59,8 @@ namespace MWGui
MyGUI::Button* mFilterMagic; MyGUI::Button* mFilterMagic;
MyGUI::Button* mFilterMisc; MyGUI::Button* mFilterMisc;
MyGUI::EditBox* mFilterEdit;
MyGUI::Button* mIncreaseButton; MyGUI::Button* mIncreaseButton;
MyGUI::Button* mDecreaseButton; MyGUI::Button* mDecreaseButton;
MyGUI::TextBox* mTotalBalanceLabel; MyGUI::TextBox* mTotalBalanceLabel;
@ -86,6 +88,7 @@ namespace MWGui
void sellItem (MyGUI::Widget* sender, int count); void sellItem (MyGUI::Widget* sender, int count);
void onFilterChanged(MyGUI::Widget* _sender); void onFilterChanged(MyGUI::Widget* _sender);
void onNameFilterChanged(MyGUI::EditBox* _sender);
void onOfferButtonClicked(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender);
void onAccept(MyGUI::EditBox* sender); void onAccept(MyGUI::EditBox* sender);
void onCancelButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender);

View file

@ -227,9 +227,9 @@ namespace MWGui
void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character)
{ {
if (key == MyGUI::KeyCode::ArrowDown) if (key == MyGUI::KeyCode::ArrowUp)
mHourSlider->setScrollPosition(std::min(mHourSlider->getScrollPosition()+1, mHourSlider->getScrollRange()-1)); mHourSlider->setScrollPosition(std::min(mHourSlider->getScrollPosition()+1, mHourSlider->getScrollRange()-1));
else if (key == MyGUI::KeyCode::ArrowUp) else if (key == MyGUI::KeyCode::ArrowDown)
mHourSlider->setScrollPosition(std::max(static_cast<int>(mHourSlider->getScrollPosition())-1, 0)); mHourSlider->setScrollPosition(std::max(static_cast<int>(mHourSlider->getScrollPosition())-1, 0));
else else
return; return;

View file

@ -90,7 +90,7 @@ namespace MWGui
typedef std::vector<SpellEffectParams> SpellEffectList; typedef std::vector<SpellEffectParams> SpellEffectList;
class MWSkill : public MyGUI::Widget class MWSkill final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED( MWSkill ) MYGUI_RTTI_DERIVED( MWSkill )
public: public:
@ -116,7 +116,7 @@ namespace MWGui
protected: protected:
virtual ~MWSkill(); virtual ~MWSkill();
virtual void initialiseOverride(); void initialiseOverride() final;
void onClicked(MyGUI::Widget* _sender); void onClicked(MyGUI::Widget* _sender);
@ -131,7 +131,7 @@ namespace MWGui
}; };
typedef MWSkill* MWSkillPtr; typedef MWSkill* MWSkillPtr;
class MWAttribute : public MyGUI::Widget class MWAttribute final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED( MWAttribute ) MYGUI_RTTI_DERIVED( MWAttribute )
public: public:
@ -156,7 +156,7 @@ namespace MWGui
protected: protected:
virtual ~MWAttribute(); virtual ~MWAttribute();
virtual void initialiseOverride(); void initialiseOverride() final;
void onClicked(MyGUI::Widget* _sender); void onClicked(MyGUI::Widget* _sender);
@ -175,7 +175,7 @@ namespace MWGui
* @todo remove this class and use MWEffectList instead * @todo remove this class and use MWEffectList instead
*/ */
class MWSpellEffect; class MWSpellEffect;
class MWSpell : public MyGUI::Widget class MWSpell final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED( MWSpell ) MYGUI_RTTI_DERIVED( MWSpell )
public: public:
@ -199,7 +199,7 @@ namespace MWGui
protected: protected:
virtual ~MWSpell(); virtual ~MWSpell();
virtual void initialiseOverride(); void initialiseOverride() final;
private: private:
void updateWidgets(); void updateWidgets();
@ -209,7 +209,7 @@ namespace MWGui
}; };
typedef MWSpell* MWSpellPtr; typedef MWSpell* MWSpellPtr;
class MWEffectList : public MyGUI::Widget class MWEffectList final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED( MWEffectList ) MYGUI_RTTI_DERIVED( MWEffectList )
public: public:
@ -241,7 +241,7 @@ namespace MWGui
protected: protected:
virtual ~MWEffectList(); virtual ~MWEffectList();
virtual void initialiseOverride(); void initialiseOverride() final;
private: private:
void updateWidgets(); void updateWidgets();
@ -250,7 +250,7 @@ namespace MWGui
}; };
typedef MWEffectList* MWEffectListPtr; typedef MWEffectList* MWEffectListPtr;
class MWSpellEffect : public MyGUI::Widget class MWSpellEffect final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED( MWSpellEffect ) MYGUI_RTTI_DERIVED( MWSpellEffect )
public: public:
@ -265,7 +265,7 @@ namespace MWGui
protected: protected:
virtual ~MWSpellEffect(); virtual ~MWSpellEffect();
virtual void initialiseOverride(); void initialiseOverride() final;
private: private:
static const int sIconOffset = 24; static const int sIconOffset = 24;
@ -279,7 +279,7 @@ namespace MWGui
}; };
typedef MWSpellEffect* MWSpellEffectPtr; typedef MWSpellEffect* MWSpellEffectPtr;
class MWDynamicStat : public MyGUI::Widget class MWDynamicStat final : public MyGUI::Widget
{ {
MYGUI_RTTI_DERIVED( MWDynamicStat ) MYGUI_RTTI_DERIVED( MWDynamicStat )
public: public:
@ -294,7 +294,7 @@ namespace MWGui
protected: protected:
virtual ~MWDynamicStat(); virtual ~MWDynamicStat();
virtual void initialiseOverride(); void initialiseOverride() final;
private: private:

View file

@ -30,6 +30,7 @@
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/sceneutil/vismask.hpp>
#include <components/sceneutil/workqueue.hpp> #include <components/sceneutil/workqueue.hpp>
#include <components/translation/translation.hpp> #include <components/translation/translation.hpp>
@ -50,8 +51,6 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwrender/vismask.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
@ -1905,8 +1904,8 @@ namespace MWGui
// Turn off all rendering except for the GUI // Turn off all rendering except for the GUI
int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask(); int oldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
int oldCullMask = mViewer->getCamera()->getCullMask(); int oldCullMask = mViewer->getCamera()->getCullMask();
mViewer->getUpdateVisitor()->setTraversalMask(MWRender::Mask_GUI); mViewer->getUpdateVisitor()->setTraversalMask(SceneUtil::Mask_GUI);
mViewer->getCamera()->setCullMask(MWRender::Mask_GUI); mViewer->getCamera()->setCullMask(SceneUtil::Mask_GUI);
MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize();
sizeVideo(screenSize.width, screenSize.height); sizeVideo(screenSize.width, screenSize.height);

View file

@ -4,6 +4,7 @@
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/vismask.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -24,8 +25,6 @@
#include "../mwmechanics/aibreathe.hpp" #include "../mwmechanics/aibreathe.hpp"
#include "../mwrender/vismask.hpp"
#include "spellcasting.hpp" #include "spellcasting.hpp"
#include "steering.hpp" #include "steering.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
@ -452,22 +451,12 @@ namespace MWMechanics
return; return;
CreatureStats &stats = actor.getClass().getCreatureStats(actor); CreatureStats &stats = actor.getClass().getCreatureStats(actor);
int hello = stats.getAiSetting(CreatureStats::AI_Hello).getModified();
if (hello == 0)
return;
if (MWBase::Environment::get().getWorld()->isSwimming(actor))
return;
MWWorld::Ptr player = getPlayer();
osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
osg::Vec3f dir = playerPos - actorPos;
const MWMechanics::AiSequence& seq = stats.getAiSequence(); const MWMechanics::AiSequence& seq = stats.getAiSequence();
int packageId = seq.getTypeId(); int packageId = seq.getTypeId();
if (seq.isInCombat() || (packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1)) if (seq.isInCombat() ||
MWBase::Environment::get().getWorld()->isSwimming(actor) ||
(packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1))
{ {
stats.setTurningToPlayer(false); stats.setTurningToPlayer(false);
stats.setGreetingTimer(0); stats.setGreetingTimer(0);
@ -475,6 +464,11 @@ namespace MWMechanics
return; return;
} }
MWWorld::Ptr player = getPlayer();
osg::Vec3f playerPos(player.getRefData().getPosition().asVec3());
osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3());
osg::Vec3f dir = playerPos - actorPos;
if (stats.isTurningToPlayer()) if (stats.isTurningToPlayer())
{ {
// Reduce the turning animation glitch by using a *HUGE* value of // Reduce the turning animation glitch by using a *HUGE* value of
@ -492,11 +486,10 @@ namespace MWMechanics
return; return;
// Play a random voice greeting if the player gets too close // Play a random voice greeting if the player gets too close
float helloDistance = static_cast<float>(hello);
static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore() static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->mValue.getInteger(); .get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->mValue.getInteger();
helloDistance *= iGreetDistanceMultiplier; float helloDistance = static_cast<float>(stats.getAiSetting(CreatureStats::AI_Hello).getModified() * iGreetDistanceMultiplier);
int greetingTimer = stats.getGreetingTimer(); int greetingTimer = stats.getGreetingTimer();
GreetingState greetingState = stats.getGreetingState(); GreetingState greetingState = stats.getGreetingState();
@ -1241,6 +1234,11 @@ namespace MWMechanics
if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name()) if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name())
inventoryStore.unequipItem(*heldIter, ptr); inventoryStore.unequipItem(*heldIter, ptr);
} }
else if (heldIter == inventoryStore.end() || heldIter->getTypeName() == typeid(ESM::Light).name())
{
// For hostile NPCs, see if they have anything better to equip first
inventoryStore.autoEquip(ptr);
}
heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
@ -1420,11 +1418,11 @@ namespace MWMechanics
const float dist = (player.getRefData().getPosition().asVec3() - ptr.getRefData().getPosition().asVec3()).length(); const float dist = (player.getRefData().getPosition().asVec3() - ptr.getRefData().getPosition().asVec3()).length();
if (dist > mActorsProcessingRange) if (dist > mActorsProcessingRange)
{ {
ptr.getRefData().getBaseNode()->setNodeMask(0); ptr.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Disabled);
return; return;
} }
else else
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor); ptr.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Actor);
// Fade away actors on large distance (>90% of actor's processing distance) // Fade away actors on large distance (>90% of actor's processing distance)
float visibilityRatio = 1.0; float visibilityRatio = 1.0;
@ -1748,12 +1746,12 @@ namespace MWMechanics
if (!inRange) if (!inRange)
{ {
iter->first.getRefData().getBaseNode()->setNodeMask(0); iter->first.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Disabled);
world->setActorCollisionMode(iter->first, false, false); world->setActorCollisionMode(iter->first, false, false);
continue; continue;
} }
else if (!isPlayer) else if (!isPlayer)
iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor); iter->first.getRefData().getBaseNode()->setNodeMask(SceneUtil::Mask_Actor);
const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead(); const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead();
if (!isDead && iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) if (!isDead && iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
@ -1852,6 +1850,8 @@ namespace MWMechanics
stats.getActiveSpells().visitEffectSources(soulTrap); stats.getActiveSpells().visitEffectSources(soulTrap);
} }
// Magic effects will be reset later, and the magic effect that could kill the actor
// needs to be determined now
calculateCreatureStatModifiers(iter->first, 0); calculateCreatureStatModifiers(iter->first, 0);
if (cls.isEssential(iter->first)) if (cls.isEssential(iter->first))
@ -1869,7 +1869,10 @@ namespace MWMechanics
// Make sure spell effects are removed // Make sure spell effects are removed
purgeSpellEffects(stats.getActorId()); purgeSpellEffects(stats.getActorId());
// Reset dynamic stats, attributes and skills
calculateCreatureStatModifiers(iter->first, 0); calculateCreatureStatModifiers(iter->first, 0);
if (iter->first.getClass().isNpc())
calculateNpcStatModifiers(iter->first, 0);
if( iter->first == getPlayer()) if( iter->first == getPlayer())
{ {

View file

@ -44,7 +44,7 @@ namespace MWMechanics
void fastForward(const MWWorld::Ptr& actor, AiState& state); void fastForward(const MWWorld::Ptr& actor, AiState& state);
virtual osg::Vec3f getDestination() { return osg::Vec3f(mX, mY, mZ); } virtual osg::Vec3f getDestination() const { return osg::Vec3f(mX, mY, mZ); }
private: private:
std::string mCellId; std::string mCellId;

View file

@ -76,7 +76,7 @@ namespace MWMechanics
void fastForward(const MWWorld::Ptr& actor, AiState& state); void fastForward(const MWWorld::Ptr& actor, AiState& state);
virtual osg::Vec3f getDestination() virtual osg::Vec3f getDestination() const
{ {
MWWorld::Ptr target = getTarget(); MWWorld::Ptr target = getTarget();
if (target.isEmpty()) if (target.isEmpty())

View file

@ -102,7 +102,7 @@ namespace MWMechanics
/// Return true if this package should repeat. Currently only used for Wander packages. /// Return true if this package should repeat. Currently only used for Wander packages.
virtual bool getRepeat() const; virtual bool getRepeat() const;
virtual osg::Vec3f getDestination() { return osg::Vec3f(0, 0, 0); } virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); }
// Return true if any loaded actor with this AI package must be active. // Return true if any loaded actor with this AI package must be active.
virtual bool alwaysActive() const { return false; } virtual bool alwaysActive() const { return false; }

View file

@ -28,6 +28,10 @@ void AiSequence::copy (const AiSequence& sequence)
for (std::list<AiPackage *>::const_iterator iter (sequence.mPackages.begin()); for (std::list<AiPackage *>::const_iterator iter (sequence.mPackages.begin());
iter!=sequence.mPackages.end(); ++iter) iter!=sequence.mPackages.end(); ++iter)
mPackages.push_back ((*iter)->clone()); mPackages.push_back ((*iter)->clone());
// We need to keep an AiWander storage, if present - it has a state machine.
// Not sure about another temporary storages
sequence.mAiState.copy<AiWanderStorage>(mAiState);
} }
AiSequence::AiSequence() : mDone (false), mRepeat(false), mLastAiPackage(-1) {} AiSequence::AiSequence() : mDone (false), mRepeat(false), mLastAiPackage(-1) {}

View file

@ -39,6 +39,14 @@ namespace MWMechanics
return *result; return *result;
} }
template< class Derived >
void copy(DerivedClassStorage& destination) const
{
Derived* result = dynamic_cast<Derived*>(mStorage);
if (result != nullptr)
destination.store<Derived>(*result);
}
template< class Derived > template< class Derived >
void store( const Derived& payload ) void store( const Derived& payload )
{ {

View file

@ -54,8 +54,9 @@ namespace MWMechanics
stats.setMovementFlag(CreatureStats::Flag_Run, false); stats.setMovementFlag(CreatureStats::Flag_Run, false);
stats.setDrawState(DrawState_Nothing); stats.setDrawState(DrawState_Nothing);
// Note: we should cancel internal "return after combat" package, if original location is too far away
if (!isWithinMaxRange(targetPos, actorPos)) if (!isWithinMaxRange(targetPos, actorPos))
return false; return mHidden;
// Unfortunately, with vanilla assets destination is sometimes blocked by other actor. // Unfortunately, with vanilla assets destination is sometimes blocked by other actor.
// If we got close to target, check for actors nearby. If they are, finish AI package. // If we got close to target, check for actors nearby. If they are, finish AI package.

View file

@ -36,7 +36,7 @@ namespace MWMechanics
virtual bool alwaysActive() const { return true; } virtual bool alwaysActive() const { return true; }
virtual osg::Vec3f getDestination() { return osg::Vec3f(mX, mY, mZ); } virtual osg::Vec3f getDestination() const { return osg::Vec3f(mX, mY, mZ); }
private: private:
float mX; float mX;

View file

@ -61,6 +61,34 @@ namespace MWMechanics
rotation.makeRotate(randomDirection, osg::Vec3f(0.0, 0.0, 1.0)); rotation.makeRotate(randomDirection, osg::Vec3f(0.0, 0.0, 1.0));
return position + osg::Vec3f(distance, 0.0, 0.0) * rotation; return position + osg::Vec3f(distance, 0.0, 0.0) * rotation;
} }
bool isDestinationHidden(const MWWorld::ConstPtr &actor, const osg::Vec3f& destination)
{
const auto position = actor.getRefData().getPosition().asVec3();
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor);
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
osg::Vec3f direction = destination - position;
direction.normalize();
const auto visibleDestination = (
isWaterCreature || isFlyingCreature
? destination
: destination + osg::Vec3f(0, 0, halfExtents.z())
) + direction * std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
const int mask = MWPhysics::CollisionType_World
| MWPhysics::CollisionType_HeightMap
| MWPhysics::CollisionType_Door
| MWPhysics::CollisionType_Actor;
return MWBase::Environment::get().getWorld()->castRay(position, visibleDestination, mask, actor);
}
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr &actor, const osg::Vec3f& destination)
{
const auto world = MWBase::Environment::get().getWorld();
const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor);
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, actor);
}
} }
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
@ -145,15 +173,6 @@ namespace MWMechanics
// get or create temporary storage // get or create temporary storage
AiWanderStorage& storage = state.get<AiWanderStorage>(); AiWanderStorage& storage = state.get<AiWanderStorage>();
const MWWorld::CellStore*& currentCell = storage.mCell;
bool cellChange = currentCell && (actor.getCell() != currentCell);
if(!currentCell || cellChange)
{
stopWalking(actor, storage);
currentCell = actor.getCell();
storage.mPopulateAvailableNodes = true;
mStoredInitialActorPosition = false;
}
mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600);
@ -200,14 +219,13 @@ namespace MWMechanics
if (AI_REACTION_TIME <= lastReaction) if (AI_REACTION_TIME <= lastReaction)
{ {
lastReaction = 0; lastReaction = 0;
return reactionTimeActions(actor, storage, currentCell, cellChange, pos); return reactionTimeActions(actor, storage, pos);
} }
else else
return false; return false;
} }
bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos)
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos)
{ {
if (mDistance <= 0) if (mDistance <= 0)
storage.mCanWanderAlongPathGrid = false; storage.mCanWanderAlongPathGrid = false;
@ -229,7 +247,7 @@ namespace MWMechanics
// Initialization to discover & store allowed node points for this actor. // Initialization to discover & store allowed node points for this actor.
if (storage.mPopulateAvailableNodes) if (storage.mPopulateAvailableNodes)
{ {
getAllowedNodes(actor, currentCell->getCell(), storage); getAllowedNodes(actor, actor.getCell()->getCell(), storage);
} }
if (canActorMoveByZAxis(actor) && mDistance > 0) { if (canActorMoveByZAxis(actor) && mDistance > 0) {
@ -258,10 +276,6 @@ namespace MWMechanics
completeManualWalking(actor, storage); completeManualWalking(actor, storage);
} }
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
if(mDistance && cellChange)
mDistance = 0;
AiWanderStorage::WanderState& wanderState = storage.mState; AiWanderStorage::WanderState& wanderState = storage.mState;
if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid) if ((wanderState == AiWanderStorage::Wander_MoveNow) && storage.mCanWanderAlongPathGrid)
{ {
@ -279,6 +293,11 @@ namespace MWMechanics
completeManualWalking(actor, storage); completeManualWalking(actor, storage);
} }
if (wanderState == AiWanderStorage::Wander_Walking
&& (isDestinationHidden(actor, mPathFinder.getPath().back())
|| isAreaOccupiedByOtherActor(actor, mPathFinder.getPath().back())))
completeManualWalking(actor, storage);
return false; // AiWander package not yet completed return false; // AiWander package not yet completed
} }
@ -330,7 +349,7 @@ namespace MWMechanics
if (!isWaterCreature && !isFlyingCreature) if (!isWaterCreature && !isFlyingCreature)
{ {
// findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance // findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance
if (const auto destination = navigator->findRandomPointAroundCircle(halfExtents, currentPosition, wanderDistance, navigatorFlags)) if (const auto destination = navigator->findRandomPointAroundCircle(halfExtents, mInitialActorPosition, wanderDistance, navigatorFlags))
mDestination = *destination; mDestination = *destination;
else else
mDestination = getRandomPointAround(mInitialActorPosition, wanderRadius); mDestination = getRandomPointAround(mInitialActorPosition, wanderRadius);
@ -342,7 +361,10 @@ namespace MWMechanics
if (!isWaterCreature && destinationIsAtWater(actor, mDestination)) if (!isWaterCreature && destinationIsAtWater(actor, mDestination))
continue; continue;
if ((isWaterCreature || isFlyingCreature) && destinationThroughGround(currentPosition, mDestination)) if (isDestinationHidden(actor, mDestination))
continue;
if (isAreaOccupiedByOtherActor(actor, mDestination))
continue; continue;
if (isWaterCreature || isFlyingCreature) if (isWaterCreature || isFlyingCreature)
@ -371,16 +393,6 @@ namespace MWMechanics
return MWBase::Environment::get().getWorld()->isUnderwater(actor.getCell(), positionBelowSurface); return MWBase::Environment::get().getWorld()->isUnderwater(actor.getCell(), positionBelowSurface);
} }
/*
* Returns true if the start to end point travels through a collision point (land).
*/
bool AiWander::destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination) {
const int mask = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Door;
return MWBase::Environment::get().getWorld()->castRay(startPoint.x(), startPoint.y(), startPoint.z(),
destination.x(), destination.y(), destination.z(),
mask);
}
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
stopWalking(actor, storage); stopWalking(actor, storage);
mObstacleCheck.clear(); mObstacleCheck.clear();
@ -529,7 +541,7 @@ namespace MWMechanics
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size()); unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size());
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]); ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
ToWorldCoordinates(dest, storage.mCell->getCell()); ToWorldCoordinates(dest, actor.getCell()->getCell());
// actor position is already in world coordinates // actor position is already in world coordinates
const osg::Vec3f start = actorPos.asVec3(); const osg::Vec3f start = actorPos.asVec3();

View file

@ -27,8 +27,6 @@ namespace MWMechanics
{ {
float mReaction; // update some actions infrequently float mReaction; // update some actions infrequently
const MWWorld::CellStore* mCell; // for detecting cell change
// AiWander states // AiWander states
enum WanderState enum WanderState
{ {
@ -60,7 +58,6 @@ namespace MWMechanics
AiWanderStorage(): AiWanderStorage():
mReaction(0), mReaction(0),
mCell(nullptr),
mState(Wander_ChooseAction), mState(Wander_ChooseAction),
mIsWanderingManually(false), mIsWanderingManually(false),
mCanWanderAlongPathGrid(true), mCanWanderAlongPathGrid(true),
@ -100,6 +97,8 @@ namespace MWMechanics
virtual int getTypeId() const; virtual int getTypeId() const;
virtual bool useVariableSpeed() const { return true;}
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); virtual void fastForward(const MWWorld::Ptr& actor, AiState& state);
@ -108,6 +107,14 @@ namespace MWMechanics
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const; osg::Vec3f getDestination(const MWWorld::Ptr& actor) const;
virtual osg::Vec3f getDestination() const
{
if (!mHasDestination)
return osg::Vec3f(0, 0, 0);
return mDestination;
}
private: private:
// NOTE: mDistance and mDuration must be set already // NOTE: mDistance and mDuration must be set already
void init(); void init();
@ -125,12 +132,10 @@ namespace MWMechanics
void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage);
void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage);
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos);
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance); void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance);
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination); bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
bool destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination);
void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage); void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage);
int mDistance; // how far the actor can wander from the spawn point int mDistance; // how far the actor can wander from the spawn point
@ -141,7 +146,7 @@ namespace MWMechanics
bool mRepeat; bool mRepeat;
bool mStoredInitialActorPosition; bool mStoredInitialActorPosition;
osg::Vec3f mInitialActorPosition; osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell
bool mHasDestination; bool mHasDestination;
osg::Vec3f mDestination; osg::Vec3f mDestination;

View file

@ -554,3 +554,37 @@ std::string MWMechanics::Alchemy::suggestPotionName()
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find( return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
ESM::MagicEffect::effectIdToString(effectId))->mValue.getString(); ESM::MagicEffect::effectIdToString(effectId))->mValue.getString();
} }
std::vector<std::string> MWMechanics::Alchemy::effectsDescription (const MWWorld::ConstPtr &ptr, const int alchemySkill)
{
std::vector<std::string> effects;
const auto& item = ptr.get<ESM::Ingredient>()->mBase;
const auto& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
const static auto fWortChanceValue = gmst.find("fWortChanceValue")->mValue.getFloat();
const auto& data = item->mData;
for (auto i = 0; i < 4; ++i)
{
const auto effectID = data.mEffectID[i];
const auto skillID = data.mSkills[i];
const auto attributeID = data.mAttributes[i];
if (alchemySkill < fWortChanceValue * (i + 1))
break;
if (effectID != -1)
{
std::string effect = gmst.find(ESM::MagicEffect::effectIdToString(effectID))->mValue.getString();
if (skillID != -1)
effect += " " + gmst.find(ESM::Skill::sSkillNameIds[skillID])->mValue.getString();
else if (attributeID != -1)
effect += " " + gmst.find(ESM::Attribute::sGmstAttributeIds[attributeID])->mValue.getString();
effects.push_back(effect);
}
}
return effects;
}

View file

@ -131,6 +131,8 @@ namespace MWMechanics
///< Try to create potions from the ingredients, place them in the inventory of the alchemist and ///< Try to create potions from the ingredients, place them in the inventory of the alchemist and
/// adjust the skills of the alchemist accordingly. /// adjust the skills of the alchemist accordingly.
/// \param name must not be an empty string, or Result_NoName is returned /// \param name must not be an empty string, or Result_NoName is returned
static std::vector<std::string> effectsDescription (const MWWorld::ConstPtr &ptr, const int alchemySKill);
}; };
} }

View file

@ -455,6 +455,11 @@ void MWMechanics::NpcStats::setTimeToStartDrowning(float time)
mTimeToStartDrowning=time; mTimeToStartDrowning=time;
} }
void MWMechanics::NpcStats::writeState (ESM::CreatureStats& state) const
{
CreatureStats::writeState(state);
}
void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
{ {
for (std::map<std::string, int>::const_iterator iter (mFactionRank.begin()); for (std::map<std::string, int>::const_iterator iter (mFactionRank.begin());
@ -494,6 +499,10 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
state.mTimeToStartDrowning = mTimeToStartDrowning; state.mTimeToStartDrowning = mTimeToStartDrowning;
} }
void MWMechanics::NpcStats::readState (const ESM::CreatureStats& state)
{
CreatureStats::readState(state);
}
void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
{ {

View file

@ -127,8 +127,10 @@ namespace MWMechanics
/// @param time value from [0,20] /// @param time value from [0,20]
void setTimeToStartDrowning(float time); void setTimeToStartDrowning(float time);
void writeState (ESM::CreatureStats& state) const;
void writeState (ESM::NpcStats& state) const; void writeState (ESM::NpcStats& state) const;
void readState (const ESM::CreatureStats& state);
void readState (const ESM::NpcStats& state); void readState (const ESM::NpcStats& state);
}; };
} }

View file

@ -120,6 +120,7 @@ namespace MWMechanics
mWalkState = WalkState::Norm; mWalkState = WalkState::Norm;
mStateDuration = 0; mStateDuration = 0;
mPrev = position; mPrev = position;
mInitialDistance = (destination - position).length();
return; return;
} }
@ -129,10 +130,11 @@ namespace MWMechanics
const float prevDistance = (destination - mPrev).length(); const float prevDistance = (destination - mPrev).length();
const float currentDistance = (destination - position).length(); const float currentDistance = (destination - position).length();
const float movedDistance = prevDistance - currentDistance; const float movedDistance = prevDistance - currentDistance;
const float movedFromInitialDistance = mInitialDistance - currentDistance;
mPrev = position; mPrev = position;
if (movedDistance >= distSameSpot) if (movedDistance >= distSameSpot && movedFromInitialDistance >= distSameSpot)
{ {
mWalkState = WalkState::Norm; mWalkState = WalkState::Norm;
mStateDuration = 0; mStateDuration = 0;
@ -143,6 +145,7 @@ namespace MWMechanics
{ {
mWalkState = WalkState::CheckStuck; mWalkState = WalkState::CheckStuck;
mStateDuration = duration; mStateDuration = duration;
mInitialDistance = (destination - position).length();
return; return;
} }

View file

@ -54,6 +54,7 @@ namespace MWMechanics
float mStateDuration; float mStateDuration;
int mEvadeDirectionIndex; int mEvadeDirectionIndex;
float mInitialDistance = 0;
void chooseEvasionDirection(); void chooseEvasionDirection();
}; };

View file

@ -314,7 +314,9 @@ namespace MWMechanics
{ {
mPath.clear(); mPath.clear();
buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); // If it's not possible to build path over navmesh due to disabled navmesh generation fallback to straight path
if (!buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)))
mPath.push_back(endPoint);
mConstructed = true; mConstructed = true;
} }
@ -335,24 +337,27 @@ namespace MWMechanics
mConstructed = true; mConstructed = true;
} }
void PathFinder::buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, bool PathFinder::buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags, const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags,
std::back_insert_iterator<std::deque<osg::Vec3f>> out) std::back_insert_iterator<std::deque<osg::Vec3f>> out)
{
try
{ {
const auto world = MWBase::Environment::get().getWorld(); const auto world = MWBase::Environment::get().getWorld();
const auto stepSize = getPathStepSize(actor); const auto stepSize = getPathStepSize(actor);
const auto navigator = world->getNavigator(); const auto navigator = world->getNavigator();
navigator->findPath(halfExtents, stepSize, startPoint, endPoint, flags, out); const auto status = navigator->findPath(halfExtents, stepSize, startPoint, endPoint, flags, out);
}
catch (const DetourNavigator::NavigatorException& exception) if (status == DetourNavigator::Status::NavMeshNotFound)
return false;
if (status != DetourNavigator::Status::Success)
{ {
Log(Debug::Debug) << "Build path by navigator exception: \"" << exception.what() Log(Debug::Debug) << "Build path by navigator error: \"" << DetourNavigator::getMessage(status)
<< "\" for \"" << actor.getClass().getName(actor) << "\" (" << actor.getBase() << "\" for \"" << actor.getClass().getName(actor) << "\" (" << actor.getBase()
<< ") from " << startPoint << " to " << endPoint << " with flags (" << ") from " << startPoint << " to " << endPoint << " with flags ("
<< DetourNavigator::WriteFlags {flags} << ")"; << DetourNavigator::WriteFlags {flags} << ")";
} }
return true;
} }
void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents, void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents,
@ -367,11 +372,23 @@ namespace MWMechanics
if (sqrDistanceIgnoreZ(mPath.front(), startPoint) <= 4 * stepSize * stepSize) if (sqrDistanceIgnoreZ(mPath.front(), startPoint) <= 4 * stepSize * stepSize)
return; return;
try
{
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
std::deque<osg::Vec3f> prePath; std::deque<osg::Vec3f> prePath;
navigator->findPath(halfExtents, stepSize, startPoint, mPath.front(), flags, std::back_inserter(prePath)); auto prePathInserter = std::back_inserter(prePath);
const auto status = navigator->findPath(halfExtents, stepSize, startPoint, mPath.front(), flags,
prePathInserter);
if (status == DetourNavigator::Status::NavMeshNotFound)
return;
if (status != DetourNavigator::Status::Success)
{
Log(Debug::Debug) << "Build path by navigator error: \"" << DetourNavigator::getMessage(status)
<< "\" for \"" << actor.getClass().getName(actor) << "\" (" << actor.getBase()
<< ") from " << startPoint << " to " << mPath.front() << " with flags ("
<< DetourNavigator::WriteFlags {flags} << ")";
return;
}
while (!prePath.empty() && sqrDistanceIgnoreZ(prePath.front(), startPoint) < stepSize * stepSize) while (!prePath.empty() && sqrDistanceIgnoreZ(prePath.front(), startPoint) < stepSize * stepSize)
prePath.pop_front(); prePath.pop_front();
@ -381,12 +398,4 @@ namespace MWMechanics
std::copy(prePath.rbegin(), prePath.rend(), std::front_inserter(mPath)); std::copy(prePath.rbegin(), prePath.rend(), std::front_inserter(mPath));
} }
catch (const DetourNavigator::NavigatorException& exception)
{
Log(Debug::Debug) << "Build path by navigator exception: \"" << exception.what()
<< "\" for \"" << actor.getClass().getName(actor) << "\" (" << actor.getBase()
<< ") from " << startPoint << " to " << mPath.front() << " with flags ("
<< DetourNavigator::WriteFlags {flags} << ")";
}
}
} }

View file

@ -201,7 +201,7 @@ namespace MWMechanics
void buildPathByPathgridImpl(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, void buildPathByPathgridImpl(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
const PathgridGraph& pathgridGraph, std::back_insert_iterator<std::deque<osg::Vec3f>> out); const PathgridGraph& pathgridGraph, std::back_insert_iterator<std::deque<osg::Vec3f>> out);
void buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, bool buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags, const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags,
std::back_insert_iterator<std::deque<osg::Vec3f>> out); std::back_insert_iterator<std::deque<osg::Vec3f>> out);
}; };

View file

@ -1199,10 +1199,10 @@ namespace MWMechanics
return false; return false;
} }
void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude) void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude, bool allowDecreaseBelowZero = false)
{ {
DynamicStat<float> stat = creatureStats.getDynamic(index); DynamicStat<float> stat = creatureStats.getDynamic(index);
stat.setCurrent(stat.getCurrent() + magnitude, index == 2); stat.setCurrent(stat.getCurrent() + magnitude, allowDecreaseBelowZero);
creatureStats.setDynamic(index, stat); creatureStats.setDynamic(index, stat);
} }
@ -1241,9 +1241,12 @@ namespace MWMechanics
case ESM::MagicEffect::DamageMagicka: case ESM::MagicEffect::DamageMagicka:
case ESM::MagicEffect::DamageFatigue: case ESM::MagicEffect::DamageFatigue:
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); {
int index = effectKey.mId-ESM::MagicEffect::DamageHealth;
static const bool uncappedDamageFatigue = Settings::Manager::getBool("uncapped damage fatigue", "Game");
adjustDynamicStat(creatureStats, index, -magnitude, index == 2 && uncappedDamageFatigue);
break; break;
}
case ESM::MagicEffect::AbsorbHealth: case ESM::MagicEffect::AbsorbHealth:
if (magnitude > 0.f) if (magnitude > 0.f)
receivedMagicDamage = true; receivedMagicDamage = true;

Some files were not shown because too many files have changed in this diff Show more