diff --git a/.travis.yml b/.travis.yml index 022a49836..cb407fc95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,11 @@ env: global: # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # via the "travis encrypt" command using the project repo's public key - - secure: 1QK0yVyoOB+gf2I7XzvhXu9w/5lq4stBXIwJbVCTjz4Q4XVHCosURaW1MAgKzMrPnbFEwjyn5uQ8BwsvvfkuN1AZD0YXITgc7gyI+J1wQ/p/ljxRxglakU6WEgsTs2J5z9UmGac4YTXg+quK7YP3rv+zuGim2I2rhzImejyzp0Ym3kRCnNcy+SGBsiRaevRJMe00Ch8zGAbEhduQGeSoS6W0rcu02DNlQKiq5NktWsXR+TWWWVfIeIlQR/lbPsCd0pdxMaMv2QCY0rVbwrYxWJwr/Qe45dAdWp+8/C3PbXpeMSGxlLa33nJNX4Lf/djxbjm8KWk6edaXPajrjR/0iwcpwq0jg2Jt6XfEdnJt35F1gpXlc04sxStjG45uloOKCFYT0wdhIO1Lq+hDP54wypQl+JInd5qC001O7pwhVxO36EgKWqo8HD+BqGDBwsNj2engy9Qcp3wO6G0rLBPB3CrZsk9wrHVv5cSiQSLMhId3Xviu3ZI2qEDA+kgTvxrKrsnMj4bILVCyG5Ka2Mj22wIDW9e8oIab9oTdujax3DTN1GkD6QuOAGzwDsNwGASsgfoeZ+FUhgM75RlBWGMilgkmnF7EJ0oAXLEpjtABnEr2d4qHv+y08kOuTDBLB9ExzCIj024dYYYNLZrqPKx0ncHuCMG2QNj2aJAJEZtj1rQ= + - secure: "1QK0yVyoOB+gf2I7XzvhXu9w/5lq4stBXIwJbVCTjz4Q4XVHCosURaW1MAgKzMrPnbFEwjyn5uQ8BwsvvfkuN1AZD0YXITgc7gyI+J1wQ/p/ljxRxglakU6WEgsTs2J5z9UmGac4YTXg+quK7YP3rv+zuGim2I2rhzImejyzp0Ym3kRCnNcy+SGBsiRaevRJMe00Ch8zGAbEhduQGeSoS6W0rcu02DNlQKiq5NktWsXR+TWWWVfIeIlQR/lbPsCd0pdxMaMv2QCY0rVbwrYxWJwr/Qe45dAdWp+8/C3PbXpeMSGxlLa33nJNX4Lf/djxbjm8KWk6edaXPajrjR/0iwcpwq0jg2Jt6XfEdnJt35F1gpXlc04sxStjG45uloOKCFYT0wdhIO1Lq+hDP54wypQl+JInd5qC001O7pwhVxO36EgKWqo8HD+BqGDBwsNj2engy9Qcp3wO6G0rLBPB3CrZsk9wrHVv5cSiQSLMhId3Xviu3ZI2qEDA+kgTvxrKrsnMj4bILVCyG5Ka2Mj22wIDW9e8oIab9oTdujax3DTN1GkD6QuOAGzwDsNwGASsgfoeZ+FUhgM75RlBWGMilgkmnF7EJ0oAXLEpjtABnEr2d4qHv+y08kOuTDBLB9ExzCIj024dYYYNLZrqPKx0ncHuCMG2QNj2aJAJEZtj1rQ=" +cache: + ccache: true + directories: + - ${HOME}/.ccache addons: apt: sources: @@ -19,7 +23,7 @@ addons: - llvm-toolchain-xenial-7 packages: [ # Dev - cmake, clang-7, clang-tools-7, gcc-8, g++-8, + cmake, clang-7, clang-tools-7, gcc-8, g++-8, ccache, # Boost libboost-filesystem-dev, libboost-iostreams-dev, libboost-program-options-dev, libboost-system-dev, # FFmpeg diff --git a/AUTHORS.md b/AUTHORS.md index 074081876..c3a27dea2 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -26,17 +26,21 @@ Programmers Allofich Andrei Kortunov (akortunov) AnyOldName3 - Aussiemon - Austin Salgat (Salgat) + Ardekantur + Armin Preiml Artem Kotsynyak (greye) artemutin Arthur Moore (EmperorArthur) Assumeru athile + Aussiemon + Austin Salgat (Salgat) Ben Shealy (bentsherman) + Berulacks Bret Curtis (psi29a) Britt Mathis (galdor557) Capostrophic + Carl Maxwell cc9cii Cédric Mocquillon Chris Boyce (slothlife) @@ -47,6 +51,7 @@ Programmers DanielVukelich darkf David Cernat (davidcernat) + Declan Millar (declan-millar) devnexen Dieho Dmitry Shkurskiy (endorph) @@ -54,10 +59,11 @@ Programmers Douglas Mencken (dougmencken) dreamer-dead David Teviotdale (dteviot) + Diggory Hardy + Dmitry Marakasov (AMDmi3) Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 - elsid Emanuel Guével (potatoesmaster) eroen escondida @@ -67,13 +73,19 @@ Programmers Finbar Crago (finbar-crago) Florian Weber (Florianjw) Gašper Sedej + Gohan1989 gugus/gus + guidoj Hallfaer Tuilinn Haoda Wang (h313) hristoast Internecine - Jacob Essex (Yacoby) + Jackerty + Jacob Essex (Yacoby) Jake Westrip (16bitint) + James Carty (MrTopCat) + Jan-Peter Nilsson (peppe) + Jan Borsodi (am0s) Jason Hooks (jhooks) jeaye Jeffrey Haines (Jyby) @@ -84,6 +96,7 @@ Programmers John Blomberg (fstp) Jordan Ayers Jordan Milne + Josua Grawitter Jules Blok (Armada651) julianko Julien Voisin (jvoisin/ap0) @@ -95,9 +108,10 @@ Programmers lazydev Leon Krieg (lkrieg) Leon Saunders (emoose) - Łukasz Gołębiewski (lukago) logzero lohikaarme + Lordrea + Łukasz Gołębiewski (lukago) Lukasz Gromanowski (lgro) Manuel Edelmann (vorenon) Marc Bouvier (CramitDeFrog) @@ -112,6 +126,7 @@ Programmers Michael Hogan (Xethik) Michael Mc Donnell Michael Papageorgiou (werdanith) + Michał Ściubidło (mike-sc) Michał Bień (Glorf) Michał Moroz (dragonee) Miloslav Číž (drummyfish) @@ -123,15 +138,20 @@ Programmers Nathan Jeffords (blunted2night) NeveHanter Nialsy + Nicolay Korslund Nikolay Kasyanov (corristo) nobrakal Nolan Poe (nopoe) Oleg Chkan (mrcheko) Paul Cercueil (pcercuei) Paul McElroy (Greendogo) + pchan3 + Perry Hugh + Phillip Andrews (PhillipAnd) Pi03k Pieter van der Kloet (pvdk) pkubik + PLkolek PlutonicOverkill Radu-Marius Popovici (rpopovici) Rafael Moura (dhustkoder) @@ -145,11 +165,12 @@ Programmers Roman Proskuryakov (kpp) Roman Siromakha (elsid) Sandy Carter (bwrsandman) - Scott Howard + Scott Howard (maqifrnswa) scrawl Sebastian Wick (swick) Sergey Fukanchik - Sergey Shambir + Sergey Shambir (sergey-shambir) + sergoz ShadowRadiance Siimacore sir_herrbatka @@ -158,24 +179,33 @@ Programmers spycrab Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) + Stanislaw Halik (sthalik) + Star-Demon stil-t + Stomy svaante Sylvain Thesnieres (Garvek) t6 terrorfisch thegriglat Thomas Luppi (Digmaster) + tlmullis tri4ng1e - unelsson - Will Herrmann (Thunderforge) + Thoronador Tom Mason (wheybags) Torben Leif Carrington (TorbenC) + unelsson + uramer viadanna Vincent Heuken + Vladimir Panteleev (CyberShadow) + Wang Ryu (bzzt) + Will Herrmann (Thunderforge) vocollapse + xyzz Yohaulticetl + Yuri Krupenin zelurker - James Carty (MrTopCat) Documentation ------------- @@ -184,11 +214,12 @@ Documentation Alejandro Sanchez (HiPhish) Bodillium Bret Curtis (psi29a) - David Walley (Loriel) Cramal + David Walley (Loriel) + Diego Crespo + Joakim Berg (lysol90) Ryan Tucker (Ravenwing) sir_herrbatka - Diego Crespo Packagers --------- @@ -207,13 +238,19 @@ Public Relations and Translations Artem Kotsynyak (greye) - Russian News Writer Dawid Lakomy (Vedyimyn) - Polish News Writer + ElderTroll - Release Manager Jim Clauwaert (Zedd) - Public Outreach + juanmnzsk8 - Spanish News Writer Julien Voisin (jvoisin/ap0) - French News Writer + Kingpix - Italian News Writer Lukasz Gromanowski (lgro) - English News Writer Martin Otto (Atahualpa) - Podcaster, Public Outreach, German Translator Mickey Lyle (raevol) - Release Manager + Nekochan - English News Writer + penguinroad - Indonesian News Writer Pithorn - Chinese News Writer sir_herrbatka - Polish News Writer + spyboot - German Translator Tom Koenderink (Okulo) - English News Writer Website @@ -243,34 +280,6 @@ Artwork Mickey Lyle (raevol) - Wordpress Theme Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel, Lamoot - OpenMW Editor Icons -Inactive Contributors ---------------------- - - Ardekantur - Armin Preiml - Berulacks - Carl Maxwell - Diggory Hardy - Dmitry Marakasov (AMDmi3) - ElderTroll - guidoj - Jan-Peter Nilsson (peppe) - Jan Borsodi - Josua Grawitter - juanmnzsk8 - Kingpix - Lordrea - Michal Sciubidlo - Nicolay Korslund - Nekochan - pchan3 - penguinroad - sergoz - spyboot - Star-Demon - Thoronador - Yuri Krupenin - Additional Credits ------------------ In this section we would like to thank people not part of OpenMW for their work. diff --git a/CHANGELOG.md b/CHANGELOG.md index c6013ce55..d0965aea8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ Bug #3623: Fix HiDPI on Windows Bug #3733: Normal maps are inverted on mirrored UVs Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable + Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4383: Bow model obscures crosshair when arrow is drawn + Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4540: Rain delay when exiting water Bug #4701: PrisonMarker record is not hardcoded like other markers @@ -26,6 +28,7 @@ Bug #4800: Standing collisions are not updated immediately when an object is teleported without a cell change Bug #4803: Stray special characters before begin statement break script compilation Bug #4804: Particle system with the "Has Sizes = false" causes an exception + Bug #4810: Raki creature broken in OpenMW Bug #4813: Creatures with known file but no "Sound Gen Creature" assigned use default sounds Bug #4815: "Finished" journal entry with lower index doesn't close journal, SetJournalIndex closes journal Bug #4820: Spell absorption is broken @@ -33,15 +36,21 @@ Bug #4828: Potion looping effects VFX are not shown for NPCs Bug #4837: CTD when a mesh with NiLODNode root node with particles is loaded Bug #4860: Actors outside of processing range visible for one frame after spawning + Bug #4876: AI ratings handling inconsistencies + Bug #4888: Global variable stray explicit reference calls break script compilation Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis Feature #3980: In-game option to disable controller Feature #4209: Editor: Faction rank sub-table Feature #4673: Weapon sheathing + Feature #4675: Support for NiRollController Feature #4730: Native animated containers support Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch + Feature #4859: Make water reflections more configurable + Feature #4887: Add openmw command option to set initial random seed + Feature #4890: Make Distant Terrain configurable Task #4686: Upgrade media decoder to a more current FFmpeg API 0.45.0 diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh old mode 100755 new mode 100644 index 9cd762c02..5ac873853 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -22,6 +22,10 @@ if [[ -z "${BUILD_OPENMW}" ]]; then export BUILD_OPENMW=ON; fi if [[ -z "${BUILD_OPENMW_CS}" ]]; then export BUILD_OPENMW_CS=ON; fi ${ANALYZE} cmake .. \ + -DCMAKE_C_COMPILER="${CC}" \ + -DCMAKE_CXX_COMPILER="${CXX}" \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_OPENMW=${BUILD_OPENMW} \ -DBUILD_OPENCS=${BUILD_OPENMW_CS} \ -DBUILD_LAUNCHER=${BUILD_OPENMW_CS} \ diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 4a114490c..5ed7283fd 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -82,7 +82,7 @@ while [ $# -gt 0 ]; do t ) TEST_FRAMEWORK=true ;; - + h ) cat < Set the build platform, can also be set with environment variable PLATFORM. - -t - Build unit tests / Google test + -t + Build unit tests / Google test -u Configure for unity builds. -v <2013/2015/2017> @@ -402,7 +402,7 @@ if [ -z $SKIP_DOWNLOAD ]; then download "SDL 2.0.7" \ "https://www.libsdl.org/release/SDL2-devel-2.0.7-VC.zip" \ "SDL2-2.0.7.zip" - + # Google test and mock if [ ! -z $TEST_FRAMEWORK ]; then echo "Google test 1.8.1..." @@ -446,7 +446,7 @@ echo if [ -z $APPVEYOR ]; then printf "Boost 1.67.0... " else - if [ $MSVC_VER -eq 12.0 ]; then + if [ "${MSVC_VER}" -eq 12.0 ]; then printf "Boost 1.58.0 AppVeyor... " else printf "Boost 1.67.0 AppVeyor... " @@ -609,7 +609,7 @@ printf "OSG 3.4.1-scrawl... " fi add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer,Shadow}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,freetype,jpeg,osg,png,tga}${SUFFIX}.dll add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll echo Done. } @@ -692,33 +692,33 @@ echo # Google Test and Google Mock if [ ! -z $TEST_FRAMEWORK ]; then printf "Google test 1.8.1 ..." - + cd googletest if [ ! -d build ]; then mkdir build fi - + cd build - + GOOGLE_INSTALL_ROOT="${DEPS_INSTALL}/GoogleTest" if [ $CONFIGURATION == "Debug" ]; then DEBUG_SUFFIX="d" else DEBUG_SUFFIX="" fi - + if [ ! -d $GOOGLE_INSTALL_ROOT ]; then - + cmake .. -DCMAKE_BUILD_TYPE="${CONFIGURATION}" -DCMAKE_INSTALL_PREFIX="${GOOGLE_INSTALL_ROOT}" -DCMAKE_USE_WIN32_THREADS_INIT=1 -G "${GENERATOR}" -DBUILD_SHARED_LIBS=1 cmake --build . --config "${CONFIGURATION}" cmake --build . --target install --config "${CONFIGURATION}" - + add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gtest_main${DEBUG_SUFFIX}.dll" add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gtest${DEBUG_SUFFIX}.dll" add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gmock_main${DEBUG_SUFFIX}.dll" add_runtime_dlls "${GOOGLE_INSTALL_ROOT}\bin\gmock${DEBUG_SUFFIX}.dll" fi - + add_cmake_opts -DBUILD_UNITTESTS=yes # FindGTest and FindGMock do not work perfectly on Windows # but we can help them by telling them everything we know about installation @@ -730,7 +730,7 @@ if [ ! -z $TEST_FRAMEWORK ]; then add_cmake_opts -DGMOCK_MAIN_LIBRARY="$GOOGLE_INSTALL_ROOT/lib/gmock_main${DEBUG_SUFFIX}.lib" add_cmake_opts -DGTEST_LINKED_AS_SHARED_LIBRARY=True echo Done. - + fi echo diff --git a/README.md b/README.md index 2652dfaca..5f648b159 100644 --- a/README.md +++ b/README.md @@ -46,4 +46,4 @@ Getting started * [TES3MP section on OpenMW forums](https://forum.openmw.org/viewforum.php?f=45) * [Discord server](https://discord.gg/ECJk293) * [Subreddit](https://www.reddit.com/r/tes3mp) -* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues) \ No newline at end of file +* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 6cd32077c..cfd658fc9 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -660,7 +660,7 @@ void Record::print() printTransport(mData.getTransport()); - std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; + std::cout << " Artificial Intelligence: " << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; @@ -668,7 +668,6 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; - std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) @@ -1079,7 +1078,7 @@ void Record::print() printTransport(mData.getTransport()); - std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; + std::cout << " Artificial Intelligence: " << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl; @@ -1087,7 +1086,6 @@ void Record::print() std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl; std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl; std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl; - std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; for (const ESM::AIPackage &package : mData.mAiPackage.mList) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 41f546af4..68fe235ce 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -80,6 +80,7 @@ bool Launcher::AdvancedPage::loadSettings() int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game"); if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2) unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex); + loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); // Input Settings loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); @@ -139,6 +140,7 @@ void Launcher::AdvancedPage::saveSettings() int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex(); if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game")) mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex); + saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game"); // Input Settings saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 072f1f36f..56cd08680 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,6 +1,5 @@ #include "graphicspage.hpp" -#include #include #include #include @@ -15,10 +14,11 @@ #include #include +#include QString getAspect(int x, int y) { - int gcd = boost::math::gcd (x, y); + int gcd = Misc::gcd (x, y); int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 233b3e439..76511f535 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -364,6 +364,11 @@ int CSMDoc::Document::getState() const return state; } +const boost::filesystem::path& CSMDoc::Document::getResourceDir() const +{ + return mResDir; +} + const boost::filesystem::path& CSMDoc::Document::getSavePath() const { return mSavePath; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 4c442428e..a2579af4c 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -115,6 +115,8 @@ namespace CSMDoc int getState() const; + const boost::filesystem::path& getResourceDir() const; + const boost::filesystem::path& getSavePath() const; const boost::filesystem::path& getProjectPath() const; diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d3d9d1503..952127edf 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -30,11 +30,11 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); - stream << "line " << loc.mLine << ", column " << loc.mColumn << ": " << message << " (" << loc.mLiteral << ")"; + stream << message << " (" << loc.mLiteral << ")" << " @ line " << loc.mLine+1 << ", column " << loc.mColumn; std::ostringstream hintStream; - hintStream << "l:" << loc.mLine << " " << loc.mColumn; + hintStream << "l:" << loc.mLine+1 << " " << loc.mColumn; mMessages->add (id, stream.str(), hintStream.str(), getSeverity (type)); } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 94ebbef55..b4eee8630 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -87,6 +87,7 @@ namespace CSMWorld //CONCRETE TYPES ENDS HERE Display_UnsignedInteger8, + Display_UnsignedInteger16, Display_Integer, Display_Float, Display_Double, diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index c05a20d07..16b7739f7 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -627,12 +627,12 @@ namespace CSMWorld RecordT record2 = record.get(); if (column==mActors.mHello) record2.mAiData.mHello = value.toInt(); - else if (column==mActors.mFlee) - record2.mAiData.mFlee = value.toInt(); + else if (column==mActors.mFlee) // Flee, Fight and Alarm ratings are probabilities. + record2.mAiData.mFlee = std::min(100, value.toInt()); else if (column==mActors.mFight) - record2.mAiData.mFight = value.toInt(); + record2.mAiData.mFight = std::min(100, value.toInt()); else if (column==mActors.mAlarm) - record2.mAiData.mAlarm = value.toInt(); + record2.mAiData.mAlarm = std::min(100, value.toInt()); else { typename std::map::const_iterator iter = diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 89d346204..bd6849492 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -128,7 +128,7 @@ CSMWorld::RefIdCollection::RefIdCollection() ActorColumns actorsColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger8)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger16)); actorsColumns.mHello = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mFlee = &mColumns.back(); diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 06da68ed8..509e656c3 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -1,7 +1,8 @@ #include "adjusterwidget.hpp" +#include + #include -#include #include #include @@ -70,8 +71,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { boost::filesystem::path path (name.toUtf8().data()); - std::string extension = path.extension().string(); - boost::algorithm::to_lower(extension); + std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); bool isLegacyPath = (extension == ".esm" || extension == ".esp"); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ed4dcff76..42dbe51ac 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,8 @@ #include "../tools/subviews.hpp" +#include + #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -303,6 +306,17 @@ void CSVDoc::View::setupDebugMenu() connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView())); } +void CSVDoc::View::setupHelpMenu() +{ + QMenu *help = menuBar()->addMenu (tr ("Help")); + + QAction* about = createMenuEntry("About OpenMW-CS", ":./info.png", help, "document-help-about"); + connect (about, SIGNAL (triggered()), this, SLOT (infoAbout())); + + QAction* aboutQt = createMenuEntry("About Qt", ":./qt.png", help, "document-help-qt"); + connect (aboutQt, SIGNAL (triggered()), this, SLOT (infoAboutQt())); +} + QAction* CSVDoc::View::createMenuEntry(CSMWorld::UniversalId::Type type, QMenu* menu, const char* shortcutName) { const std::string title = CSMWorld::UniversalId (type).getTypeName(); @@ -339,6 +353,7 @@ void CSVDoc::View::setupUi() setupCharacterMenu(); setupAssetsMenu(); setupDebugMenu(); + setupHelpMenu(); } void CSVDoc::View::setupShortcut(const char* name, QAction* action) @@ -674,6 +689,52 @@ void CSVDoc::View::save() mDocument->save(); } +void CSVDoc::View::infoAbout() +{ + // Get current OpenMW version + QString versionInfo = (Version::getOpenmwVersionDescription(mDocument->getResourceDir().string())+ +#if defined(__x86_64__) || defined(_M_X64) + " (64-bit)").c_str(); +#else + " (32-bit)").c_str(); +#endif + + // Get current year + time_t now = time(NULL); + struct tm tstruct; + char copyrightInfo[40]; + tstruct = *localtime(&now); + strftime(copyrightInfo, sizeof(copyrightInfo), "Copyright © 2008-%Y OpenMW Team", &tstruct); + + QString aboutText = QString( + "

" + "

OpenMW Construction Set

" + "%1\n\n" + "%2\n\n" + "%3\n\n" + "" + "" + "" + "" + "" + "
%4https://openmw.org
%5https://forum.openmw.org
%6https://gitlab.com/OpenMW/openmw/issues
%7irc://irc.freenode.net/#openmw
" + "

") + .arg(versionInfo + , tr("OpenMW-CS is a content file editor for OpenMW, a modern, free and open source game engine.") + , tr(copyrightInfo) + , tr("Home Page:") + , tr("Forum:") + , tr("Bug Tracker:") + , tr("IRC:")); + + QMessageBox::about(this, "About OpenMW-CS", aboutText); +} + +void CSVDoc::View::infoAboutQt() +{ + QMessageBox::aboutQt(this); +} + void CSVDoc::View::verify() { addSubView (mDocument->verify()); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7a9a48b0f..c4046a7a1 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -85,6 +85,8 @@ namespace CSVDoc void setupDebugMenu(); + void setupHelpMenu(); + void setupUi(); void setupShortcut(const char* name, QAction* action); @@ -165,6 +167,10 @@ namespace CSVDoc void exit(); + void infoAbout(); + + void infoAboutQt(); + void verify(); void addGlobalsSubView(); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 14df4658d..eb7b8e334 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -141,13 +141,16 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Preview) { + const CSMWorld::UniversalId id = getUniversalId(currentRow); + const CSMWorld::UniversalId::Type type = id.getType(); + QModelIndex index = mModel->index (row, mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification)); CSMWorld::RecordBase::State state = static_cast ( mModel->data (index).toInt()); - if (state!=CSMWorld::RecordBase::State_Deleted) + if (state!=CSMWorld::RecordBase::State_Deleted && type != CSMWorld::UniversalId::Type_ItemLevelledList) menu.addAction (mPreviewAction); } } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index fef805d56..3aee51e98 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -219,6 +219,13 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return sb; } + case CSMWorld::ColumnBase::Display_UnsignedInteger16: + { + DialogueSpinBox *sb = new DialogueSpinBox(parent); + sb->setRange(0, std::numeric_limits::max()); + return sb; + } + case CSMWorld::ColumnBase::Display_Var: return new QLineEdit(parent); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0b010d7d1..e7f57eebd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -49,7 +49,6 @@ #include "mwgui/windowmanagerimp.hpp" #include "mwscript/scriptmanagerimp.hpp" -#include "mwscript/extensions.hpp" #include "mwscript/interpretercontext.hpp" #include "mwsound/soundmanagerimp.hpp" @@ -320,7 +319,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mNewGame (false) , mCfgMgr(configurationManager) { - Misc::Rng::init(); MWClass::registerClasses(); Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; @@ -786,6 +784,8 @@ void OMW::Engine::go() Log(Debug::Info) << "OSG version: " << osgGetVersion(); + Misc::Rng::init(mRandomSeed); + // Load settings Settings::Manager settings; std::string settingspath; @@ -986,3 +986,8 @@ void OMW::Engine::setSaveGameFile(const std::string &savegame) { mSaveGameFile = savegame; } + +void OMW::Engine::setRandomSeed(unsigned int seed) +{ + mRandomSeed = seed; +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e42a5c94f..bfe9759cd 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -100,6 +100,7 @@ namespace OMW bool mGrab; bool mExportFonts; + unsigned int mRandomSeed; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; @@ -203,6 +204,8 @@ namespace OMW /// Set the save game file to load after initialising the engine. void setSaveGameFile(const std::string& savegame); + void setRandomSeed(unsigned int seed); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index b4cb18822..e795a2320 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "engine.hpp" @@ -154,7 +155,12 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("export-fonts", bpo::value()->implicit_value(true) ->default_value(false), "Export Morrowind .fnt fonts to PNG image and XML file in current directory") - ("activate-dist", bpo::value ()->default_value (-1), "activation distance override"); + ("activate-dist", bpo::value ()->default_value (-1), "activation distance override") + + ("random-seed", bpo::value () + ->default_value(Misc::Rng::generateDefaultSeed()), + "seed value for random number generator") + ; /* Start of tes3mp addition @@ -312,6 +318,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setFallbackValues(variables["fallback"].as().mMap); engine.setActivationDistanceOverride (variables["activate-dist"].as()); engine.enableFontExport(variables["export-fonts"].as()); + engine.setRandomSeed(variables["random-seed"].as()); /* Start of tes3mp addition diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 46cf78e17..ba697e0ec 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -135,6 +135,7 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Ptr getPlayerPtr() = 0; + virtual MWWorld::ConstPtr getPlayerConstPtr() const = 0; virtual const MWWorld::ESMStore& getStore() const = 0; @@ -787,6 +788,9 @@ namespace MWBase virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0; virtual void setNavMeshNumberToRender(const std::size_t value) = 0; + + /// Return physical half extents of the given actor to be used in pathfinding + virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; }; } diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 42ea99b00..eabac1644 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -2,10 +2,10 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/cellstore.hpp" @@ -19,6 +19,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/vismask.hpp" #include "../mwgui/tooltips.hpp" @@ -30,8 +31,10 @@ namespace MWClass void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model, true); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index 73a4d37d7..aa356f62d 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -4,7 +4,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 50e8ee302..7241a5f3b 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -15,11 +15,9 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" #include "../mwphysics/physicssystem.hpp" diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index edf43d09a..1208ba9e1 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -22,7 +22,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index baf3af785..a5f5b005a 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -19,7 +19,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 2448d8367..14b82de19 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -18,7 +18,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwworld/ptr.hpp" @@ -305,8 +304,8 @@ namespace MWClass std::string text; int lockLevel = ptr.getCellRef().getLockLevel(); if (lockLevel > 0 && lockLevel != ESM::UnbreakableLock) - text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ptr.getCellRef().getLockLevel()); - else if (ptr.getCellRef().getLockLevel() < 0) + text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(lockLevel); + else if (lockLevel < 0) text += "\n#{sUnlocked}"; if (ptr.getCellRef().getTrap() != "") text += "\n#{sTrapped}"; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 64d0130a1..dee7d9a17 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -371,6 +371,7 @@ namespace MWClass { damage = attack[0] + ((attack[1]-attack[0])*attackStrength); MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -472,9 +473,6 @@ namespace MWClass if (!object.isEmpty()) stats.setLastHitObject(object.getCellRef().getRefId()); - if (damage > 0.0f && !object.isEmpty()) - MWMechanics::resistNormalWeapon(ptr, attacker, object, damage); - if (damage < 0.001f) damage = 0; @@ -760,11 +758,7 @@ namespace MWClass int Creature::getServices(const MWWorld::ConstPtr &actor) const { - const MWWorld::LiveCellRef* ref = actor.get(); - if (ref->mBase->mHasAI) - return ref->mBase->mAiData.mServices; - else - return 0; + return actor.get()->mBase->mAiData.mServices; } bool Creature::isPersistent(const MWWorld::ConstPtr &actor) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 9efa39aa2..1b6cad350 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -14,15 +14,14 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/actionteleport.hpp" #include "../mwworld/actiondoor.hpp" @@ -38,6 +37,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwrender/animation.hpp" +#include "../mwrender/vismask.hpp" #include "../mwmechanics/actorutil.hpp" @@ -67,8 +67,10 @@ namespace MWClass void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model, true); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 47b72044c..634ccc27a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -19,7 +19,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwphysics/physicssystem.hpp" diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index ea0abd6f6..38b7137f3 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -5,20 +5,16 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwphysics/physicssystem.hpp" -#include "../mwworld/customdata.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 5673465a0..013808bb2 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -4,11 +4,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 73e5f4f3c..8a0644349 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -19,7 +19,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwphysics/physicssystem.hpp" diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c170fde96..8e87ed218 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -682,6 +682,8 @@ namespace MWClass damage = attack[0] + ((attack[1]-attack[0])*attackStrength); } MWMechanics::adjustWeaponDamage(damage, weapon, ptr); + MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage); + MWMechanics::applyWerewolfDamageMult(victim, weapon, damage); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } @@ -1388,11 +1390,7 @@ namespace MWClass int Npc::getServices(const MWWorld::ConstPtr &actor) const { - const MWWorld::LiveCellRef* ref = actor.get(); - if (ref->mBase->mHasAI) - return ref->mBase->mAiData.mServices; - else - return 0; + return actor.get()->mBase->mAiData.mServices; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 7da9fb1ce..796fabb60 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -19,11 +19,9 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionapply.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwphysics/physicssystem.hpp" #include "../mwworld/nullaction.hpp" diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 734b6b1fd..b53e2418a 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -4,11 +4,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 60c48ca05..d4181eeb2 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -15,14 +15,11 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwphysics/physicssystem.hpp" -#include "../mwworld/nullaction.hpp" #include "../mwworld/actionrepair.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 40a6b998c..a6e4fe5e7 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,6 +1,7 @@ #include "static.hpp" #include +#include #include "../mwworld/ptr.hpp" #include "../mwphysics/physicssystem.hpp" @@ -8,14 +9,17 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/vismask.hpp" namespace MWClass { void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ff1fca63a..6bbf6c4fa 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -22,7 +22,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 4998050d8..50647e546 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -1,9 +1,6 @@ #include "dialoguemanagerimp.hpp" -#include -#include #include -#include #include #include diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp index 4f0b7422c..791a4da7e 100644 --- a/apps/openmw/mwdialogue/scripttest.cpp +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "filter.hpp" diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 793963e48..28dbd214b 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -1,9 +1,6 @@ #include "selectwrapper.hpp" -#include - #include -#include #include #include diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index fa8a96185..9db7a055b 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -237,15 +238,15 @@ namespace MWGui std::set effectIds = mAlchemy->listEffects(); Widgets::SpellEffectList list; unsigned int effectIndex=0; - for (std::set::iterator it2 = effectIds.begin(); it2 != effectIds.end(); ++it2) + for (const MWMechanics::EffectKey& effectKey : effectIds) { Widgets::SpellEffectParams params; - params.mEffectID = it2->mId; - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(it2->mId); + params.mEffectID = effectKey.mId; + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectKey.mId); if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) - params.mSkill = it2->mArg; + params.mSkill = effectKey.mArg; else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - params.mAttribute = it2->mArg; + params.mAttribute = effectKey.mArg; params.mIsConstant = true; params.mNoTarget = true; diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index aa23fbaa5..c6eb00792 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -1,12 +1,9 @@ #ifndef MWGUI_ALCHEMY_H #define MWGUI_ALCHEMY_H +#include #include -#include - -#include "../mwmechanics/alchemy.hpp" - #include #include "controllers.hpp" diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index c1867541b..6f6a621ad 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -145,35 +145,35 @@ namespace MWGui // sort by name std::vector < std::pair > birthSigns; - MWWorld::Store::iterator it = signs.begin(); - for (; it != signs.end(); ++it) + for (const ESM::BirthSign& sign : signs) { - birthSigns.push_back(std::make_pair(it->mId, &(*it))); + birthSigns.push_back(std::make_pair(sign.mId, &sign)); } std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); int index = 0; - for (std::vector >::const_iterator it2 = birthSigns.begin(); - it2 != birthSigns.end(); ++it2, ++index) + for (auto& birthsignPair : birthSigns) { - mBirthList->addItem(it2->second->mName, it2->first); + mBirthList->addItem(birthsignPair.second->mName, birthsignPair.first); if (mCurrentBirthId.empty()) { mBirthList->setIndexSelected(index); - mCurrentBirthId = it2->first; + mCurrentBirthId = birthsignPair.first; } - else if (Misc::StringUtils::ciEqual(it2->first, mCurrentBirthId)) + else if (Misc::StringUtils::ciEqual(birthsignPair.first, mCurrentBirthId)) { mBirthList->setIndexSelected(index); } + + index++; } } void BirthDialog::updateSpells() { - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + for (MyGUI::Widget* widget : mSpellItems) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSpellItems.clear(); diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 4ea59414d..7f7dfd20a 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -6,6 +6,7 @@ #include "MyGUI_FontManager.h" #include +#include #include #include diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 5c1dc7b7d..dd910f1b6 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -257,19 +257,17 @@ namespace MWGui { std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map::iterator it = attributes.begin(); - it != attributes.end(); ++it) + for (auto& attributePair : attributes) { - mReviewDialog->setAttribute(static_cast (it->first), it->second); + mReviewDialog->setAttribute(static_cast (attributePair.first), attributePair.second); } } { std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map::iterator it = skills.begin(); - it != skills.end(); ++it) + for (auto& skillPair : skills) { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); + mReviewDialog->setSkillValue(static_cast (skillPair.first), skillPair.second); } mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } @@ -566,7 +564,7 @@ namespace MWGui { if (mGenerateClassStep == 10) { - static boost::array classes = { { + static std::array classes = { { {"Acrobat", {6, 2, 2}}, {"Agent", {6, 1, 3}}, {"Archer", {3, 5, 2}}, diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 45abe889e..a92ad934c 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -207,25 +207,25 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - std::vector > items; // class id, class name - for (MWWorld::Store::iterator it = store.get().begin(); it != store.get().end(); ++it) + std::vector > items; // class id, class name + for (const ESM::Class& classInfo : store.get()) { - bool playable = (it->mData.mIsPlayable != 0); + bool playable = (classInfo.mData.mIsPlayable != 0); if (!playable) // Only display playable classes continue; - if (store.get().isDynamic(it->mId)) + if (store.get().isDynamic(classInfo.mId)) continue; // custom-made class not relevant for this dialog - items.push_back(std::make_pair(it->mId, it->mName)); + items.push_back(std::make_pair(classInfo.mId, classInfo.mName)); } std::sort(items.begin(), items.end(), sortClasses); int index = 0; - for (std::vector >::const_iterator it = items.begin(); it != items.end(); ++it) + for (auto& itemPair : items) { - const std::string &id = it->first; - mClassList->addItem(it->second, id); + const std::string &id = itemPair.first; + mClassList->addItem(itemPair.second, id); if (mCurrentClassId.empty()) { mCurrentClassId = id; @@ -332,19 +332,17 @@ namespace MWGui void InfoBoxDialog::setButtons(ButtonList &buttons) { - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + for (MyGUI::Button* button : this->mButtons) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(button); } this->mButtons.clear(); // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget MyGUI::Button* button; MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); - ButtonList::const_iterator end = buttons.end(); - for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + for (const std::string &text : buttons) { - const std::string &text = *it; button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); button->getSubWidgetText()->setWordWrap(true); button->setCaption(text); @@ -368,11 +366,10 @@ namespace MWGui void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) { - std::vector::const_iterator end = mButtons.end(); int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + for (MyGUI::Button* button : mButtons) { - if (*it == _sender) + if (button == _sender) { eventButtonSelected(i); return; @@ -430,10 +427,9 @@ namespace MWGui mSkills.push_back(mMinorSkill[i]); } - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + for (Widgets::MWSkillPtr& skill : mSkills) { - (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + skill->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); } setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); @@ -642,14 +638,13 @@ namespace MWGui ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); // Avoid duplicate skills by swapping any skill field that matches the selected one - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + for (Widgets::MWSkillPtr& skill : mSkills) { - if (*it == mAffectedSkill) + if (skill == mAffectedSkill) continue; - if ((*it)->getSkillId() == id) + if (skill->getSkillId() == id) { - (*it)->setSkillId(mAffectedSkill->getSkillId()); + skill->setSkillId(mAffectedSkill->getSkillId()); break; } } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 05e6c06e9..1de24b056 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -244,11 +244,13 @@ namespace MWGui { int i = 0; printOK(""); - for(std::vector::iterator it=matches.begin(); it < matches.end(); ++it,++i ) + for(std::string& match : matches) { - printOK( *it ); - if( i == 50 ) + if(i == 50) break; + + printOK(match); + i++; } } } @@ -365,15 +367,16 @@ namespace MWGui } /* Iterate through the vector. */ - for(std::vector::iterator it=mNames.begin(); it < mNames.end();++it) { + for(std::string& name : mNames) + { bool string_different=false; /* Is the string shorter than the input string? If yes skip it. */ - if( (*it).length() < tmp.length() ) + if(name.length() < tmp.length()) continue; /* Is the beginning of the string different from the input string? If yes skip it. */ - for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();++iter, ++iter2) { + for( std::string::iterator iter=tmp.begin(), iter2=name.begin(); iter < tmp.end();++iter, ++iter2) { if( Misc::StringUtils::toLower(*iter) != Misc::StringUtils::toLower(*iter2) ) { string_different=true; break; @@ -384,7 +387,7 @@ namespace MWGui continue; /* The beginning of the string matches the input string, save it for the next test. */ - matches.push_back(*it); + matches.push_back(name); } /* There are no matches. Return the unchanged input. */ @@ -412,11 +415,14 @@ namespace MWGui /* Check if all matching strings match further than input. If yes complete to this match. */ int i = tmp.length(); - for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); ++iter, ++i) { - for(std::vector::iterator it=matches.begin(); it < matches.end();++it) { - if( Misc::StringUtils::toLower((*it)[i]) != Misc::StringUtils::toLower(*iter) ) { + for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); ++iter, ++i) + { + for(std::string& match : matches) + { + if(Misc::StringUtils::toLower(match[i]) != Misc::StringUtils::toLower(*iter)) + { /* Append the longest match to the end of the output string*/ - output.append(matches.front().substr( 0, i)); + output.append(matches.front().substr(0, i)); return output; } } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 4c778034b..ccd026b08 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -21,7 +21,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" @@ -33,7 +32,6 @@ #include "inventorywindow.hpp" #include "itemview.hpp" -#include "itemwidget.hpp" #include "inventoryitemmodel.hpp" #include "containeritemmodel.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 24e7f8d00..5ba5bb0eb 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -13,8 +13,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwmechanics/actorutil.hpp" - namespace { @@ -84,9 +82,9 @@ size_t ContainerItemModel::getItemCount() ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item) { size_t i = 0; - for (std::vector::iterator it = mItems.begin(); it != mItems.end(); ++it) + for (ItemStack& itemStack : mItems) { - if (*it == item) + if (itemStack == item) return i; ++i; } @@ -105,29 +103,29 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) { int toRemove = count; - for (std::vector::iterator source = mItemSources.begin(); source != mItemSources.end(); ++source) + for (MWWorld::Ptr& source : mItemSources) { - MWWorld::ContainerStore& store = source->getClass().getContainerStore(*source); + MWWorld::ContainerStore& store = source.getClass().getContainerStore(source); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { if (stacks(*it, item.mBase)) { - toRemove -= store.remove(*it, toRemove, *source); + toRemove -= store.remove(*it, toRemove, source); if (toRemove <= 0) return; } } } - for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + for (MWWorld::Ptr& source : mWorldItems) { - if (stacks(*source, item.mBase)) + if (stacks(source, item.mBase)) { - int refCount = source->getRefData().getCount(); + int refCount = source.getRefData().getCount(); if (refCount - toRemove <= 0) - MWBase::Environment::get().getWorld()->deleteObject(*source); + MWBase::Environment::get().getWorld()->deleteObject(source); else - source->getRefData().setCount(std::max(0, refCount - toRemove)); + source.getRefData().setCount(std::max(0, refCount - toRemove)); toRemove -= refCount; if (toRemove <= 0) return; @@ -140,27 +138,28 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) void ContainerItemModel::update() { mItems.clear(); - for (std::vector::iterator source = mItemSources.begin(); source != mItemSources.end(); ++source) + for (MWWorld::Ptr& source : mItemSources) { - MWWorld::ContainerStore& store = source->getClass().getContainerStore(*source); + MWWorld::ContainerStore& store = source.getClass().getContainerStore(source); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { if (!(*it).getClass().showsInInventory(*it)) continue; - std::vector::iterator itemStack = mItems.begin(); - for (; itemStack != mItems.end(); ++itemStack) + bool found = false; + for (ItemStack& itemStack : mItems) { - if (stacks(*it, itemStack->mBase)) + if (stacks(*it, itemStack.mBase)) { // we already have an item stack of this kind, add to it - itemStack->mCount += it->getRefData().getCount(); + itemStack.mCount += it->getRefData().getCount(); + found = true; break; } } - if (itemStack == mItems.end()) + if (!found) { // no stack yet, create one ItemStack newItem (*it, this, it->getRefData().getCount()); @@ -168,23 +167,24 @@ void ContainerItemModel::update() } } } - for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + for (MWWorld::Ptr& source : mWorldItems) { - std::vector::iterator itemStack = mItems.begin(); - for (; itemStack != mItems.end(); ++itemStack) + bool found = false; + for (ItemStack& itemStack : mItems) { - if (stacks(*source, itemStack->mBase)) + if (stacks(source, itemStack.mBase)) { // we already have an item stack of this kind, add to it - itemStack->mCount += source->getRefData().getCount(); + itemStack.mCount += source.getRefData().getCount(); + found = true; break; } } - if (itemStack == mItems.end()) + if (!found) { // no stack yet, create one - ItemStack newItem (*source, this, source->getRefData().getCount()); + ItemStack newItem (source, this, source.getRefData().getCount()); mItems.push_back(newItem); } } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index dfb2b15b9..6b400c172 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -184,16 +184,16 @@ namespace MWGui BookTypesetter::Style* style = typesetter->createStyle("", textColours.normal, false); size_t formatted = 0; // points to the first character that is not laid out yet - for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) + for (auto& hyperLink : hyperLinks) { - intptr_t topicId = it->second; + intptr_t topicId = hyperLink.second; BookTypesetter::Style* hotStyle = typesetter->createHotStyle (style, textColours.link, textColours.linkOver, textColours.linkPressed, topicId); - if (formatted < it->first.first) - typesetter->write(style, formatted, it->first.first); - typesetter->write(hotStyle, it->first.first, it->first.second); - formatted = it->first.second; + if (formatted < hyperLink.first.first) + typesetter->write(style, formatted, hyperLink.first.first); + typesetter->write(hotStyle, hyperLink.first.first, hyperLink.first.second); + formatted = hyperLink.first.second; } if (formatted < text.size()) typesetter->write(style, formatted, text.size()); @@ -204,9 +204,8 @@ namespace MWGui keywordSearch->highlightKeywords(text.begin(), text.end(), matches); std::string::const_iterator i = text.begin (); - for (std::vector::iterator it = matches.begin(); it != matches.end(); ++it) + for (KeywordSearchT::Match& match : matches) { - KeywordSearchT::Match match = *it; if (i != match.mBeg) addTopicLink (typesetter, 0, i - text.begin (), match.mBeg - text.begin ()); @@ -419,13 +418,13 @@ namespace MWGui bool sameActor = (mPtr == actor); if (!sameActor) { - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - delete (*it); + for (DialogueText* text : mHistoryContents) + delete text; mHistoryContents.clear(); mKeywords.clear(); mTopicsList->clear(); - for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) - mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers + for (Link* link : mLinks) + mDeleteLater.push_back(link); // Links are not deleted right away to prevent issues with event handlers mLinks.clear(); } @@ -489,8 +488,8 @@ namespace MWGui void DialogueWindow::updateTopicsPane() { mTopicsList->clear(); - for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) - mDeleteLater.push_back(it->second); + for (auto& linkPair : mTopicLinks) + mDeleteLater.push_back(linkPair.second); mTopicLinks.clear(); mKeywordSearch.clear(); @@ -533,15 +532,15 @@ namespace MWGui mTopicsList->addSeparator(); - for(std::list::iterator it = mKeywords.begin(); it != mKeywords.end(); ++it) + for(std::string& keyword : mKeywords) { - mTopicsList->addItem(*it); + mTopicsList->addItem(keyword); - Topic* t = new Topic(*it); + Topic* t = new Topic(keyword); t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); - mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t; + mTopicLinks[Misc::StringUtils::lowerCase(keyword)] = t; - mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); + mKeywordSearch.seed(Misc::StringUtils::lowerCase(keyword), intptr_t(t)); } mTopicsList->adjustSize(); @@ -563,9 +562,8 @@ namespace MWGui BookTypesetter::Ptr typesetter = BookTypesetter::create (mHistory->getWidth(), std::numeric_limits::max()); - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - (*it)->write(typesetter, &mKeywordSearch, mTopicLinks); - + for (DialogueText* text : mHistoryContents) + text->write(typesetter, &mKeywordSearch, mTopicLinks); BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White, false); @@ -573,9 +571,9 @@ namespace MWGui // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); - for (std::vector >::const_iterator it = mChoices.begin(); it != mChoices.end(); ++it) + for (std::pair& choice : mChoices) { - Choice* link = new Choice(it->second); + Choice* link = new Choice(choice.second); link->eventChoiceActivated += MyGUI::newDelegate(this, &DialogueWindow::onChoiceActivated); mLinks.push_back(link); @@ -583,7 +581,7 @@ namespace MWGui BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, textColours.answerPressed, TypesetBook::InteractiveId(link)); - typesetter->write(questionStyle, to_utf8_span(it->first.c_str())); + typesetter->write(questionStyle, to_utf8_span(choice.first.c_str())); } mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index af6567afb..fbdc1bf80 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -348,8 +348,7 @@ namespace MWGui if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr)) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage49")->mValue.getString(); - if (msg.find("%s") != std::string::npos) - msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); + Misc::StringUtils::replace(msg, "%s", item.getClass().getName(item).c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 78359608e..fca05b05c 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -4,15 +4,11 @@ #include #include #include -#include // correctBookartPath #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include -#include - #include #include #include @@ -30,7 +26,7 @@ namespace MWGui MWScript::InterpreterContext interpreterContext(nullptr, MWWorld::Ptr()); // empty arguments, because there is no locals or actor mText = Interpreter::fixDefinesBook(mText, interpreterContext); - boost::algorithm::replace_all(mText, "\r", ""); + Misc::StringUtils::replaceAll(mText, "\r", ""); // vanilla game does not show any text after the last EOL tag. const std::string lowerText = Misc::StringUtils::lowerCase(mText); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 46a0dd18e..97c7fffa0 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -39,7 +39,6 @@ #include "itemmodel.hpp" #include "draganddrop.hpp" -#include "itemmodel.hpp" #include "itemwidget.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index c9f55d352..d74819a89 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -37,9 +37,9 @@ size_t InventoryItemModel::getItemCount() ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item) { size_t i = 0; - for (std::vector::iterator it = mItems.begin(); it != mItems.end(); ++it) + for (ItemStack& itemStack : mItems) { - if (*it == item) + if (itemStack == item) return i; ++i; } diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 10c36c73f..44fa94f3a 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -130,13 +130,13 @@ namespace MWGui { int currentY = 0; - for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter) + for (Line& line : mLines) { - iter->mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18); + line.mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18); currentY += 19; - iter->mIcon->setCoord(16, currentY, 32, 32); - iter->mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20); + line.mIcon->setCoord(16, currentY, 32, 32); + line.mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20); currentY += 32 + 4; } diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index c7c10e8e4..08c5bff35 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -1,13 +1,9 @@ #include "itemmodel.hpp" -#include - #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/store.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index ba3039a16..5ab69e722 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -156,12 +156,19 @@ namespace MWGui void SpellWidget::setSpellIcon(const std::string& icon) { - if (mFrame) + if (mFrame && !mCurrentFrame.empty()) + { + mCurrentFrame.clear(); mFrame->setImageTexture(""); - if (mItemShadow) - mItemShadow->setImageTexture(icon); - if (mItem) - mItem->setImageTexture(icon); + } + if (mCurrentIcon != icon) + { + mCurrentIcon = icon; + if (mItemShadow) + mItemShadow->setImageTexture(icon); + if (mItem) + mItem->setImageTexture(icon); + } } } diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index a5b5a832f..d71a8ca6e 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -178,16 +178,12 @@ namespace MWGui End of tes3mp addition */ - std::stringstream dayStr; - dayStr << mDays; - if (message.find("%d") != std::string::npos) - message.replace(message.find("%d"), 2, dayStr.str()); + Misc::StringUtils::replace(message, "%d", std::to_string(mDays).c_str(), 2); - for (std::set::iterator it = skills.begin(); it != skills.end(); ++it) + for (const int& skill : skills) { - std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->mValue.getString(); - std::stringstream skillValue; - skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase(); + std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[skill])->mValue.getString(); + int skillValue = player.getClass().getNpcStats(player).getSkill(skill).getBase(); std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString(); /* @@ -196,16 +192,14 @@ namespace MWGui Account for usage of ignoreJailSkillIncreases */ if (!localPlayer->ignoreJailSkillIncreases && - (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security)) + (skill == ESM::Skill::Sneak || skill == ESM::Skill::Security)) /* End of tes3mp change (minor) */ skillMsg = gmst.find("sNotifyMessage39")->mValue.getString(); - if (skillMsg.find("%s") != std::string::npos) - skillMsg.replace(skillMsg.find("%s"), 2, skillName); - if (skillMsg.find("%d") != std::string::npos) - skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str()); + Misc::StringUtils::replace(skillMsg, "%s", skillName.c_str(), 2); + Misc::StringUtils::replace(skillMsg, "%d", std::to_string(skillValue).c_str(), 2); message += "\n" + skillMsg; } diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 4302740f6..065a503e6 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -1,7 +1,5 @@ #include "journalbooks.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index f45d73ca9..095d74e8a 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -1,6 +1,5 @@ #include "journalwindow.hpp" -#include #include #include #include diff --git a/apps/openmw/mwgui/layout.cpp b/apps/openmw/mwgui/layout.cpp index 3035adebb..ae1c09659 100644 --- a/apps/openmw/mwgui/layout.cpp +++ b/apps/openmw/mwgui/layout.cpp @@ -21,11 +21,11 @@ namespace MWGui mListWindowRoot = MyGUI::LayoutManager::getInstance().loadLayout(mLayoutName, mPrefix, _parent); const std::string main_name = mPrefix + MAIN_WINDOW; - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); iter!=mListWindowRoot.end(); ++iter) + for (MyGUI::Widget* widget : mListWindowRoot) { - if ((*iter)->getName() == main_name) + if (widget->getName() == main_name) { - mMainWidget = (*iter); + mMainWidget = widget; break; } } @@ -66,10 +66,9 @@ namespace MWGui MyGUI::Widget* Layout::getWidget(const std::string &_name) { - for (MyGUI::VectorWidgetPtr::iterator iter=mListWindowRoot.begin(); - iter!=mListWindowRoot.end(); ++iter) + for (MyGUI::Widget* widget : mListWindowRoot) { - MyGUI::Widget* find = (*iter)->findWidget(mPrefix + _name); + MyGUI::Widget* find = widget->findWidget(mPrefix + _name); if (nullptr != find) { return find; diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 286405f79..415c8e31c 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -12,7 +12,6 @@ #include "../mwbase/soundmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index e74a60206..c054f3bbd 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_LOADINGSCREEN_H #define MWGUI_LOADINGSCREEN_H +#include + #include #include diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index d7a12df45..faf388004 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -270,36 +270,36 @@ namespace MWGui // Create new buttons if needed std::vector allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; - for (std::vector::iterator it = allButtons.begin(); it != allButtons.end(); ++it) + for (std::string& buttonId : allButtons) { - if (mButtons.find(*it) == mButtons.end()) + if (mButtons.find(buttonId) == mButtons.end()) { Gui::ImageButton* button = mButtonBox->createWidget ("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default); - button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds"); - button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds"); - button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds"); + button->setProperty("ImageHighlighted", "textures\\menu_" + buttonId + "_over.dds"); + button->setProperty("ImageNormal", "textures\\menu_" + buttonId + ".dds"); + button->setProperty("ImagePushed", "textures\\menu_" + buttonId + "_pressed.dds"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); - button->setUserData(std::string(*it)); - mButtons[*it] = button; + button->setUserData(std::string(buttonId)); + mButtons[buttonId] = button; } } // Start by hiding all buttons int maxwidth = 0; - for (std::map::iterator it = mButtons.begin(); it != mButtons.end(); ++it) + for (auto& buttonPair : mButtons) { - it->second->setVisible(false); - MyGUI::IntSize requested = it->second->getRequestedSize(); + buttonPair.second->setVisible(false); + MyGUI::IntSize requested = buttonPair.second->getRequestedSize(); if (requested.width > maxwidth) maxwidth = requested.width; } // Now show and position the ones we want - for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + for (std::string& buttonId : buttons) { - assert(mButtons.find(*it) != mButtons.end()); - Gui::ImageButton* button = mButtons[*it]; + assert(mButtons.find(buttonId) != mButtons.end()); + Gui::ImageButton* button = mButtons[buttonId]; button->setVisible(true); MyGUI::IntSize requested = button->getRequestedSize(); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 35ecc8398..6407444a9 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -343,8 +343,8 @@ namespace MWGui void LocalMapBase::updateCustomMarkers() { - for (std::vector::iterator it = mCustomMarkerWidgets.begin(); it != mCustomMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (MyGUI::Widget* widget : mCustomMarkerWidgets) + MyGUI::Gui::getInstance().destroyWidget(widget); mCustomMarkerWidgets.clear(); for (int dX = -mCellDistance; dX <= mCellDistance; ++dX) @@ -546,9 +546,9 @@ namespace MWGui } int counter = 0; - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + for (const MWWorld::Ptr& ptr : markers) { - const ESM::Position& worldPos = it->getRefData().getPosition(); + const ESM::Position& worldPos = ptr.getRefData().getPosition(); MarkerUserData markerPos (mLocalMapRender); MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, @@ -585,8 +585,8 @@ namespace MWGui void LocalMapBase::updateDoorMarkers() { // clear all previous door markers - for (std::vector::iterator it = mDoorMarkerWidgets.begin(); it != mDoorMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (MyGUI::Widget* widget : mDoorMarkerWidgets) + MyGUI::Gui::getInstance().destroyWidget(widget); mDoorMarkerWidgets.clear(); MWBase::World* world = MWBase::Environment::get().getWorld(); @@ -612,10 +612,8 @@ namespace MWGui // Create a widget for each marker int counter = 0; - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + for (MWBase::World::DoorMarker& marker : doors) { - MWBase::World::DoorMarker marker = *it; - std::vector destNotes; CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(marker.dest); for (CustomMarkerCollection::ContainerType::const_iterator iter = markers.first; iter != markers.second; ++iter) @@ -648,8 +646,8 @@ namespace MWGui void LocalMapBase::updateMagicMarkers() { // clear all previous markers - for (std::vector::iterator it = mMagicMarkerWidgets.begin(); it != mMagicMarkerWidgets.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(*it); + for (MyGUI::Widget* widget : mMagicMarkerWidgets) + MyGUI::Gui::getInstance().destroyWidget(widget); mMagicMarkerWidgets.clear(); addDetectionMarkers(MWBase::World::Detect_Creature); @@ -907,9 +905,9 @@ namespace MWGui mGlobalMapRender->cleanupCameras(); - for (std::vector::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it) + for (CellId& cellId : mQueuedToExplore) { - mGlobalMapRender->exploreCell(it->first, it->second, mLocalMapRender->getMapTexture(it->first, it->second)); + mGlobalMapRender->exploreCell(cellId.first, cellId.second, mLocalMapRender->getMapTexture(cellId.first, cellId.second)); } mQueuedToExplore.clear(); @@ -961,11 +959,11 @@ namespace MWGui { LocalMapBase::updateCustomMarkers(); - for (std::map, MyGUI::Widget*>::iterator widgetIt = mGlobalMapMarkers.begin(); widgetIt != mGlobalMapMarkers.end(); ++widgetIt) + for (auto& widgetPair : mGlobalMapMarkers) { - int x = widgetIt->first.first; - int y = widgetIt->first.second; - MyGUI::Widget* markerWidget = widgetIt->second; + int x = widgetPair.first.first; + int y = widgetPair.first.second; + MyGUI::Widget* markerWidget = widgetPair.second; setGlobalMapMarkerTooltip(markerWidget, x, y); } } @@ -1090,8 +1088,8 @@ namespace MWGui mGlobalMapRender->clear(); mChanged = true; - for (std::map, MyGUI::Widget*>::iterator it = mGlobalMapMarkers.begin(); it != mGlobalMapMarkers.end(); ++it) - MyGUI::Gui::getInstance().destroyWidget(it->second); + for (auto& widgetPair : mGlobalMapMarkers) + MyGUI::Gui::getInstance().destroyWidget(widgetPair.second); mGlobalMapMarkers.clear(); } @@ -1116,11 +1114,11 @@ namespace MWGui mGlobalMapRender->read(map); - for (std::set::iterator it = map.mMarkers.begin(); it != map.mMarkers.end(); ++it) + for (const ESM::GlobalMap::CellId& cellId : map.mMarkers) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first, it->second); + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get().search(cellId.first, cellId.second); if (cell && !cell->mName.empty()) - addVisitedLocation(cell->mName, it->first, it->second); + addVisitedLocation(cell->mName, cellId.first, cellId.second); } } } @@ -1130,8 +1128,8 @@ namespace MWGui NoDrop::setAlpha(alpha); // can't allow showing map with partial transparency, as the fog of war will also go transparent // and reveal parts of the map you shouldn't be able to see - for (std::vector::iterator it = mMapWidgets.begin(); it != mMapWidgets.end(); ++it) - (*it)->setVisible(alpha == 1); + for (MyGUI::ImageBox* widget : mMapWidgets) + widget->setVisible(alpha == 1); } void MapWindow::customMarkerCreated(MyGUI::Widget *marker) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index b1360268c..90534bf88 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -2,6 +2,7 @@ #define MWGUI_MAPWINDOW_H #include +#include #include "windowpinnablebase.hpp" diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6c2d85dd9..d64ec9c37 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -28,10 +28,9 @@ namespace MWGui MessageBoxManager::~MessageBoxManager () { - std::vector::iterator it(mMessageBoxes.begin()); - for (; it != mMessageBoxes.end(); ++it) + for (MessageBox* messageBox : mMessageBoxes) { - delete *it; + delete messageBox; } } @@ -50,12 +49,11 @@ namespace MWGui mInterMessageBoxe = nullptr; } - std::vector::iterator it(mMessageBoxes.begin()); - for (; it != mMessageBoxes.end(); ++it) + for (MessageBox* messageBox : mMessageBoxes) { - if (*it == mStaticMessageBox) + if (messageBox == mStaticMessageBox) mStaticMessageBox = nullptr; - delete *it; + delete messageBox; } mMessageBoxes.clear(); @@ -81,9 +79,9 @@ namespace MWGui it = mMessageBoxes.begin(); while(it != mMessageBoxes.end()) { - (*it)->update(static_cast(height)); - height += (*it)->getHeight(); - ++it; + (*it)->update(static_cast(height)); + height += (*it)->getHeight(); + ++it; } if(mInterMessageBoxe != nullptr && mInterMessageBoxe->mMarkedToDelete) { @@ -114,10 +112,10 @@ namespace MWGui } int height = 0; - for(std::vector::iterator it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + for (MessageBox* messageBox : mMessageBoxes) { - (*it)->update(height); - height += (*it)->getHeight(); + messageBox->update(height); + height += messageBox->getHeight(); } } @@ -240,14 +238,14 @@ namespace MWGui int buttonHeight = 0; MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - for(std::vector::const_iterator it = buttons.begin(); it != buttons.end(); ++it) + for(const std::string& buttonId : buttons) { MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, std::string("MW_Button"), dummyCoord, MyGUI::Align::Default); - button->setCaptionWithReplacing(*it); + button->setCaptionWithReplacing(buttonId); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); @@ -300,16 +298,16 @@ namespace MWGui MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2; - for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) + for(MyGUI::Button* button : mButtons) { buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; - buttonSize.width = (*button)->getTextSize().width + 2*buttonLabelLeftPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonLabelTopPadding; + buttonSize.width = button->getTextSize().width + 2*buttonLabelLeftPadding; + buttonSize.height = button->getTextSize().height + 2*buttonLabelTopPadding; - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); + button->setCoord(buttonCord); + button->setSize(buttonSize); left += buttonSize.width + buttonLeftPadding; } @@ -329,16 +327,16 @@ namespace MWGui int top = textPadding + textSize.height + textButtonPadding; - for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) + for(MyGUI::Button* button : mButtons) { - buttonSize.width = (*button)->getTextSize().width + buttonLabelLeftPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonLabelTopPadding*2; + buttonSize.width = button->getTextSize().width + buttonLabelLeftPadding*2; + buttonSize.height = button->getTextSize().height + buttonLabelTopPadding*2; buttonCord.top = top; buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2; - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); + button->setCoord(buttonCord); + button->setSize(buttonSize); top += buttonSize.height + buttonTopPadding; } @@ -368,13 +366,13 @@ namespace MWGui MyGUI::Widget* InteractiveMessageBox::getDefaultKeyFocus() { std::vector keywords { "sOk", "sYes" }; - for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) + for(MyGUI::Button* button : mButtons) { for (const std::string& keyword : keywords) { - if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), (*button)->getCaption())) + if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), button->getCaption())) { - return *button; + return button; } } } @@ -390,10 +388,9 @@ namespace MWGui { mMarkedToDelete = true; int index = 0; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(const MyGUI::Button* button : mButtons) { - if(*button == pressed) + if(button == pressed) { mButtonPressed = index; mMessageBoxManager.onButtonPressed(mButtonPressed); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 95ed0982f..621f32e09 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -667,32 +667,32 @@ namespace MWGui MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); int i=0; - for (std::vector::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it) + for (ESM::QuickKeys::QuickKey& quickKey : keys.mKeys) { if (i >= 10) return; mSelected = &mKey[i]; - switch (it->mType) + switch (quickKey.mType) { case Type_Magic: - if (MWBase::Environment::get().getWorld()->getStore().get().search(it->mId)) - onAssignMagic(it->mId); + if (MWBase::Environment::get().getWorld()->getStore().get().search(quickKey.mId)) + onAssignMagic(quickKey.mId); break; case Type_Item: case Type_MagicItem: { // Find the item by id - MWWorld::Ptr item = store.findReplacement(it->mId); + MWWorld::Ptr item = store.findReplacement(quickKey.mId); if (item.isEmpty()) unassign(mSelected); else { - if (it->mType == Type_Item) + if (quickKey.mType == Type_Item) onAssignItem(item); - else // if (it->mType == Type_MagicItem) + else // if (quickKey.mType == Type_MagicItem) onAssignMagicItem(item); } diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9e99b3bc8..c85e7eca7 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -301,9 +301,8 @@ namespace MWGui const MWWorld::Store &store = MWBase::Environment::get().getWorld()->getStore().get(); - for (MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + for (const ESM::BodyPart& bodypart : store) { - const ESM::BodyPart& bodypart = *it; if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) continue; if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) @@ -364,22 +363,21 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); std::vector > items; // ID, name - MWWorld::Store::iterator it = races.begin(); - for (; it != races.end(); ++it) + for (const ESM::Race& race : races) { - bool playable = it->mData.mFlags & ESM::Race::Playable; + bool playable = race.mData.mFlags & ESM::Race::Playable; if (!playable) // Only display playable races continue; - items.push_back(std::make_pair(it->mId, it->mName)); + items.push_back(std::make_pair(race.mId, race.mName)); } std::sort(items.begin(), items.end(), sortRaces); int index = 0; - for (std::vector >::const_iterator iter = items.begin(); iter != items.end(); ++iter) + for (auto& item : items) { - mRaceList->addItem(iter->second, iter->first); - if (Misc::StringUtils::ciEqual(iter->first, mCurrentRaceId)) + mRaceList->addItem(item.second, item.first); + if (Misc::StringUtils::ciEqual(item.first, mCurrentRaceId)) mRaceList->setIndexSelected(index); ++index; } @@ -387,9 +385,9 @@ namespace MWGui void RaceDialog::updateSkills() { - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + for (MyGUI::Widget* widget : mSkillItems) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSkillItems.clear(); @@ -424,9 +422,9 @@ namespace MWGui void RaceDialog::updateSpellPowers() { - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + for (MyGUI::Widget* widget : mSpellPowerItems) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSpellPowerItems.clear(); @@ -439,11 +437,9 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mCurrentRaceId); - std::vector::const_iterator it = race->mPowers.mList.begin(); - std::vector::const_iterator end = race->mPowers.mList.end(); - for (int i = 0; it != end; ++it) + int i = 0; + for (const std::string& spellpower : race->mPowers.mList) { - const std::string &spellpower = *it; Widgets::MWSpellPtr spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + MyGUI::utility::toString(i)); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index c9e31d42d..0fa4fdec5 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H +#include + #include "windowbase.hpp" #include diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 4ecd21cef..2c8157284 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -1,7 +1,5 @@ #include "recharge.hpp" -#include - #include #include @@ -209,7 +207,8 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) if (gem.getRefData().getCount() == 0) { std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage51")->mValue.getString(); - message = boost::str(boost::format(message) % gem.getClass().getName(gem)); + Misc::StringUtils::replace(message, "%s", gem.getClass().getName(gem).c_str(), 2); + MWBase::Environment::get().getWindowManager()->messageBox(message); // special case: readd Azura's Star diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 004a172b3..e76cbe770 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -228,11 +228,9 @@ namespace MWGui std::set skillSet; std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + for (const int skill : ESM::Skill::sSkillIds) { - int skill = *it; if (skillSet.find(skill) == skillSet.end()) mMiscSkills.push_back(skill); } @@ -355,9 +353,9 @@ namespace MWGui void ReviewDialog::updateSkillArea() { - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (MyGUI::Widget* skillWidget : mSkillWidgets) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(skillWidget); } mSkillWidgets.clear(); @@ -390,19 +388,18 @@ namespace MWGui attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase(); std::vector selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race); - for (std::vector::iterator iter = selectedSpells.begin(); iter != selectedSpells.end(); ++iter) + for (std::string& spellId : selectedSpells) { - std::string lower = Misc::StringUtils::lowerCase(*iter); + std::string lower = Misc::StringUtils::lowerCase(spellId); if (std::find(spells.begin(), spells.end(), lower) == spells.end()) spells.push_back(lower); } if (race) { - for (std::vector::const_iterator iter = race->mPowers.mList.begin(); - iter != race->mPowers.mList.end(); ++iter) + for (const std::string& spellId : race->mPowers.mList) { - std::string lower = Misc::StringUtils::lowerCase(*iter); + std::string lower = Misc::StringUtils::lowerCase(spellId); if (std::find(spells.begin(), spells.end(), lower) == spells.end()) spells.push_back(lower); } @@ -411,10 +408,9 @@ namespace MWGui if (!mBirthSignId.empty()) { const ESM::BirthSign* sign = MWBase::Environment::get().getWorld()->getStore().get().find(mBirthSignId); - for (std::vector::const_iterator iter = sign->mPowers.mList.begin(); - iter != sign->mPowers.mList.end(); ++iter) + for (const std::string& spellId : sign->mPowers.mList) { - std::string lower = Misc::StringUtils::lowerCase(*iter); + std::string lower = Misc::StringUtils::lowerCase(spellId); if (std::find(spells.begin(), spells.end(), lower) == spells.end()) spells.push_back(lower); } @@ -423,27 +419,27 @@ namespace MWGui if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeAbility", "Abilities"), coord1, coord2); - for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + for (std::string& spellId : spells) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); if (spell->mData.mType == ESM::Spell::ST_Ability) addItem(spell, coord1, coord2); } addSeparator(coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypePower", "Powers"), coord1, coord2); - for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + for (std::string& spellId : spells) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); if (spell->mData.mType == ESM::Spell::ST_Power) addItem(spell, coord1, coord2); } addSeparator(coord1, coord2); addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeSpell", "Spells"), coord1, coord2); - for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + for (std::string& spellId : spells) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); if (spell->mData.mType == ESM::Spell::ST_Spell) addItem(spell, coord1, coord2); } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 0a87b6600..a9915ee9d 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWGUI_SAVEGAMEDIALOG_H #define OPENMW_MWGUI_SAVEGAMEDIALOG_H +#include + #include "windowbase.hpp" namespace MWState diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 79bea30e5..aa17ed4e8 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -2,6 +2,7 @@ #define OPENMW_MWGUI_SCREENFADER_H #include +#include #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 8ab7eed0f..8615778d5 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -8,11 +8,12 @@ #include #include -#include #include #include +#include +#include #include #include @@ -58,7 +59,7 @@ namespace std::string getAspect (int x, int y) { - int gcd = boost::math::gcd (x, y); + int gcd = Misc::gcd (x, y); int xaspect = x / gcd; int yaspect = y / gcd; // special case: 8 : 5 is usually referred to as 16:10 @@ -174,7 +175,7 @@ namespace MWGui MyGUI::TextBox* textBox; getWidget(textBox, labelWidgetName); std::string labelCaption = scroller->getUserString("SettingLabelCaption"); - boost::algorithm::replace_all(labelCaption, "%s", value); + Misc::StringUtils::replaceAll(labelCaption, "%s", value.c_str(), 2); textBox->setCaptionWithReplacing(labelCaption); } } @@ -199,6 +200,7 @@ namespace MWGui getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); getWidget(mWaterTextureSize, "WaterTextureSize"); + getWidget(mWaterReflectionDetail, "WaterReflectionDetail"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -222,6 +224,7 @@ namespace MWGui mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); + mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged); mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); @@ -241,11 +244,10 @@ namespace MWGui resolutions.push_back(std::make_pair(mode.w, mode.h)); } std::sort(resolutions.begin(), resolutions.end(), sortResolutions); - for (std::vector < std::pair >::const_iterator it=resolutions.begin(); - it!=resolutions.end(); ++it) + for (std::pair& resolution : resolutions) { - std::string str = MyGUI::utility::toString(it->first) + " x " + MyGUI::utility::toString(it->second) - + " (" + getAspect(it->first,it->second) + ")"; + std::string str = MyGUI::utility::toString(resolution.first) + " x " + MyGUI::utility::toString(resolution.second) + + " (" + getAspect(resolution.first, resolution.second) + ")"; if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) mResolutionList->addItem(str); @@ -255,7 +257,7 @@ namespace MWGui std::string tmip = Settings::Manager::getString("texture mipmap", "General"); mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); - int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); + int waterTextureSize = Settings::Manager::getInt("rtt size", "Water"); if (waterTextureSize >= 512) mWaterTextureSize->setIndexSelected(0); if (waterTextureSize >= 1024) @@ -263,6 +265,10 @@ namespace MWGui if (waterTextureSize >= 2048) mWaterTextureSize->setIndexSelected(2); + int waterReflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + waterReflectionDetail = std::min(4, std::max(0, waterReflectionDetail)); + mWaterReflectionDetail->setIndexSelected(waterReflectionDetail); + mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); mKeyboardSwitch->setStateSelected(true); @@ -342,6 +348,13 @@ namespace MWGui apply(); } + void SettingsWindow::onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos) + { + unsigned int level = std::min((unsigned int)4, (unsigned int)pos); + Settings::Manager::setInt("reflection detail", "Water", level); + apply(); + } + void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); @@ -490,17 +503,17 @@ namespace MWGui else actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); - for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) + for (const int& action : actions) { - std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (action); if (desc == "") continue; std::string binding; if(mKeyboardMode) - binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(*it); + binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(action); else - binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); + binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(action); Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); @@ -508,7 +521,7 @@ namespace MWGui Gui::SharedStateButton* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default); rightText->setCaptionWithReplacing(binding); rightText->setTextAlign (MyGUI::Align::Right); - rightText->setUserData(*it); // save the action id for callbacks + rightText->setUserData(action); // save the action id for callbacks rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction); rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index c6e48819c..37d671a5a 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -33,6 +33,7 @@ namespace MWGui MyGUI::Widget* mAnisotropyBox; MyGUI::ComboBox* mWaterTextureSize; + MyGUI::ComboBox* mWaterReflectionDetail; // controls MyGUI::ScrollView* mControlsBox; @@ -52,6 +53,7 @@ namespace MWGui void highlightCurrentResolution(); void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); + void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 5e692238a..5bf89bc20 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -133,9 +133,9 @@ namespace MWGui std::stable_sort(spellsToSort.begin(), spellsToSort.end(), sortSpells); - for (std::vector::iterator it = spellsToSort.begin() ; it != spellsToSort.end(); ++it) + for (const ESM::Spell* spell : spellsToSort) { - addSpell(**it); + addSpell(*spell); } spellsToSort.clear(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index ac7687c54..5864a5451 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -481,10 +481,8 @@ namespace MWGui const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + for (const ESM::ENAMstruct& effect : mEffects) { - const ESM::ENAMstruct& effect = *it; - y += std::max(1.f, MWMechanics::calcEffectCost(effect)); if (effect.mRange == ESM::RT_Target) @@ -556,18 +554,17 @@ namespace MWGui if (spell->mData.mType != ESM::Spell::ST_Spell) continue; - const std::vector& list = spell->mEffects.mList; - for (std::vector::const_iterator it2 = list.begin(); it2 != list.end(); ++it2) + for (const ESM::ENAMstruct& effectInfo : spell->mEffects.mList) { - const ESM::MagicEffect * effect = MWBase::Environment::get().getWorld()->getStore().get().find(it2->mEffectID); + const ESM::MagicEffect * effect = MWBase::Environment::get().getWorld()->getStore().get().find(effectInfo.mEffectID); // skip effects that do not allow spellmaking/enchanting int requiredFlags = (mType == Spellmaking) ? ESM::MagicEffect::AllowSpellmaking : ESM::MagicEffect::AllowEnchanting; if (!(effect->mData.mFlags & requiredFlags)) continue; - if (std::find(knownEffects.begin(), knownEffects.end(), it2->mEffectID) == knownEffects.end()) - knownEffects.push_back(it2->mEffectID); + if (std::find(knownEffects.begin(), knownEffects.end(), effectInfo.mEffectID) == knownEffects.end()) + knownEffects.push_back(effectInfo.mEffectID); } } @@ -576,23 +573,23 @@ namespace MWGui mAvailableEffectsList->clear (); int i=0; - for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) + for (const short effectId : knownEffects) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( - ESM::MagicEffect::effectIdToString (*it))->mValue.getString()); - mButtonMapping[i] = *it; + ESM::MagicEffect::effectIdToString(effectId))->mValue.getString()); + mButtonMapping[i] = effectId; ++i; } mAvailableEffectsList->adjustSize (); mAvailableEffectsList->scrollToTop(); - for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) + for (const short effectId : knownEffects) { std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( - ESM::MagicEffect::effectIdToString (*it))->mValue.getString(); + ESM::MagicEffect::effectIdToString(effectId))->mValue.getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); - ToolTips::createMagicEffectToolTip (w, *it); + ToolTips::createMagicEffectToolTip (w, effectId); } mEffects.clear(); @@ -672,9 +669,9 @@ namespace MWGui } else { - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + for (const ESM::ENAMstruct& effectInfo : mEffects) { - if (it->mEffectID == mSelectedKnownEffectId) + if (effectInfo.mEffectID == mSelectedKnownEffectId) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}"); return; @@ -706,17 +703,17 @@ namespace MWGui MyGUI::IntSize size(0,0); int i = 0; - for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + for (const ESM::ENAMstruct& effectInfo : mEffects) { Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; + params.mEffectID = effectInfo.mEffectID; + params.mSkill = effectInfo.mSkill; + params.mAttribute = effectInfo.mAttribute; + params.mDuration = effectInfo.mDuration; + params.mMagnMin = effectInfo.mMagnMin; + params.mMagnMax = effectInfo.mMagnMax; + params.mRange = effectInfo.mRange; + params.mArea = effectInfo.mArea; params.mIsConstant = mConstantEffect; MyGUI::Button* button = mUsedEffectsView->createWidget("", MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index c0f56e654..c1bd421db 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -65,10 +65,11 @@ namespace MWGui int w=2; - for (std::map >::const_iterator it = effects.begin(); it != effects.end(); ++it) + for (auto& effectInfoPair : effects) { + const int effectId = effectInfoPair.first; const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld ()->getStore ().get().find(it->first); + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectId); float remainingDuration = 0; float totalDuration = 0; @@ -77,46 +78,50 @@ namespace MWGui static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get().find("fMagicStartIconBlink")->mValue.getFloat(); - for (std::vector::const_iterator effectIt = it->second.begin(); - effectIt != it->second.end(); ++effectIt) + std::vector& effectInfos = effectInfoPair.second; + bool addNewLine = true; + for (const MagicEffectInfo& effectInfo : effectInfos) { - if (effectIt != it->second.begin()) + if (addNewLine) + { sourcesDescription += "\n"; + addNewLine = false; + } // if at least one of the effect sources is permanent, the effect will never wear off - if (effectIt->mPermanent) + if (effectInfo.mPermanent) { remainingDuration = fadeTime; totalDuration = fadeTime; } else { - remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime); - totalDuration = std::max(totalDuration, effectIt->mTotalTime); + remainingDuration = std::max(remainingDuration, effectInfo.mRemainingTime); + totalDuration = std::max(totalDuration, effectInfo.mTotalTime); } - sourcesDescription += effectIt->mSource; + sourcesDescription += effectInfo.mSource; if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) sourcesDescription += " (" + MWBase::Environment::get().getWindowManager()->getGameSettingString( - ESM::Skill::sSkillNameIds[effectIt->mKey.mArg], "") + ")"; + ESM::Skill::sSkillNameIds[effectInfo.mKey.mArg], "") + ")"; if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) sourcesDescription += " (" + MWBase::Environment::get().getWindowManager()->getGameSettingString( - ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")"; + ESM::Attribute::sGmstAttributeIds[effectInfo.mKey.mArg], "") + ")"; ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType(); if (displayType == ESM::MagicEffect::MDT_TimesInt) { std::string timesInt = MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", ""); std::stringstream formatter; - formatter << std::fixed << std::setprecision(1) << " " << (effectIt->mMagnitude / 10.0f) << timesInt; + formatter << std::fixed << std::setprecision(1) << " " << (effectInfo.mMagnitude / 10.0f) << timesInt; sourcesDescription += formatter.str(); } else if ( displayType != ESM::MagicEffect::MDT_None ) { - sourcesDescription += ": " + MyGUI::utility::toString(effectIt->mMagnitude); + sourcesDescription += ": " + MyGUI::utility::toString(effectInfo.mMagnitude); if ( displayType == ESM::MagicEffect::MDT_Percentage ) sourcesDescription += MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", ""); @@ -124,32 +129,35 @@ namespace MWGui sourcesDescription += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", ""); else if ( displayType == ESM::MagicEffect::MDT_Level ) { - sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? + sourcesDescription += " " + ((effectInfo.mMagnitude > 1) ? MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", "") ); } else // ESM::MagicEffect::MDT_Points { - sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? + sourcesDescription += " " + ((effectInfo.mMagnitude > 1) ? MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "") : MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "") ); } } - if (effectIt->mRemainingTime > -1 && + if (effectInfo.mRemainingTime > -1 && Settings::Manager::getBool("show effect duration","Game")) { sourcesDescription += " #{sDuration}: "; - float duration = effectIt->mRemainingTime; - if (duration > 3600) { + float duration = effectInfo.mRemainingTime; + if (duration > 3600) + { int hour = duration / 3600; duration -= hour*3600; sourcesDescription += MWGui::ToolTips::toString(hour) + "h"; } - if (duration > 60) { + if (duration > 60) + { int minute = duration / 60; duration -= minute*60; sourcesDescription += MWGui::ToolTips::toString(minute) + "m"; } - if (duration > 0.1) { + if (duration > 0.1) + { sourcesDescription += MWGui::ToolTips::toString(duration) + "s"; } } @@ -158,15 +166,15 @@ namespace MWGui if (remainingDuration > 0.f) { MyGUI::ImageBox* image; - if (mWidgetMap.find(it->first) == mWidgetMap.end()) + if (mWidgetMap.find(effectId) == mWidgetMap.end()) { image = parent->createWidget ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); - mWidgetMap[it->first] = image; + mWidgetMap[effectId] = image; image->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(effect->mIcon)); - std::string name = ESM::MagicEffect::effectIdToString (it->first); + std::string name = ESM::MagicEffect::effectIdToString (effectId); ToolTipInfo tooltipInfo; tooltipInfo.caption = "#{" + name + "}"; @@ -178,7 +186,7 @@ namespace MWGui image->setUserString("ToolTipType", "ToolTipInfo"); } else - image = mWidgetMap[it->first]; + image = mWidgetMap[effectId]; image->setPosition(w,2); image->setVisible(true); @@ -191,9 +199,9 @@ namespace MWGui if (totalDuration >= fadeTime && fadeTime > 0.f) image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); } - else if (mWidgetMap.find(it->first) != mWidgetMap.end()) + else if (mWidgetMap.find(effectId) != mWidgetMap.end()) { - mWidgetMap[it->first]->setVisible(false); + mWidgetMap[effectId]->setVisible(false); } } @@ -208,10 +216,10 @@ namespace MWGui } // hide inactive effects - for (std::map::iterator it = mWidgetMap.begin(); it != mWidgetMap.end(); ++it) + for (auto& widgetPair : mWidgetMap) { - if (effects.find(it->first) == effects.end()) - it->second->setVisible(false); + if (effects.find(widgetPair.first) == effects.end()) + widgetPair.second->setVisible(false); } } diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 879ce471f..f03c1cedb 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -149,13 +149,13 @@ namespace MWGui mModel->update(); bool fullUpdateRequired = false; SpellModel::ModelIndex maxSpellIndexFound = -1; - for (std::vector< LineInfo >::iterator it = mLines.begin(); it != mLines.end(); ++it) + for (LineInfo& line : mLines) { // only update the lines that are "updateable" - SpellModel::ModelIndex spellIndex(it->mSpellIndex); + SpellModel::ModelIndex spellIndex(line.mSpellIndex); if (spellIndex != NoSpellIndex) { - Gui::SharedStateButton* nameButton = reinterpret_cast(it->mLeftWidget); + Gui::SharedStateButton* nameButton = reinterpret_cast(line.mLeftWidget); // match model against line // if don't match, then major change has happened, so do a full update @@ -176,7 +176,7 @@ namespace MWGui else { maxSpellIndexFound = spellIndex; - Gui::SharedStateButton* costButton = reinterpret_cast(it->mRightWidget); + Gui::SharedStateButton* costButton = reinterpret_cast(line.mRightWidget); if ((costButton != nullptr) && (costButton->getCaption() != spell.mCostColumn)) { costButton->setCaption(spell.mCostColumn); @@ -198,27 +198,25 @@ namespace MWGui void SpellView::layoutWidgets() { int height = 0; - for (std::vector< LineInfo >::iterator it = mLines.begin(); - it != mLines.end(); ++it) + for (LineInfo& line : mLines) { - height += (it->mLeftWidget)->getHeight(); + height += line.mLeftWidget->getHeight(); } bool scrollVisible = height > mScrollView->getHeight(); int width = mScrollView->getWidth() - (scrollVisible ? 18 : 0); height = 0; - for (std::vector< LineInfo >::iterator it = mLines.begin(); - it != mLines.end(); ++it) + for (LineInfo& line : mLines) { - int lineHeight = (it->mLeftWidget)->getHeight(); - (it->mLeftWidget)->setCoord(4, height, width - 8, lineHeight); - if (it->mRightWidget) + int lineHeight = line.mLeftWidget->getHeight(); + line.mLeftWidget->setCoord(4, height, width - 8, lineHeight); + if (line.mRightWidget) { - (it->mRightWidget)->setCoord(4, height, width - 8, lineHeight); - MyGUI::TextBox* second = (it->mRightWidget)->castType(false); + line.mRightWidget->setCoord(4, height, width - 8, lineHeight); + MyGUI::TextBox* second = line.mRightWidget->castType(false); if (second) - (it->mLeftWidget)->setSize(width - 8 - second->getTextSize().width, lineHeight); + line.mLeftWidget->setSize(width - 8 - second->getTextSize().width, lineHeight); } height += lineHeight; diff --git a/apps/openmw/mwgui/spellview.hpp b/apps/openmw/mwgui/spellview.hpp index 0eb69f6ba..66113d869 100644 --- a/apps/openmw/mwgui/spellview.hpp +++ b/apps/openmw/mwgui/spellview.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_GUI_SPELLVIEW_H #define OPENMW_GUI_SPELLVIEW_H +#include #include #include diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 5fc18a1c7..54bda650c 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,10 +1,9 @@ #include "spellwindow.hpp" -#include - #include #include +#include #include /* @@ -168,7 +167,7 @@ namespace MWGui mSpellToDelete = spellId; ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); + Misc::StringUtils::replace(question, "%s", spell->mName.c_str(), 2); dialog->askForConfirmation(question); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index df292cfaa..c3f852c5b 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -278,11 +278,9 @@ namespace MWGui std::set skillSet; std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + for (const int skill : ESM::Skill::sSkillIds) { - int skill = *it; if (skillSet.find(skill) == skillSet.end()) mMiscSkills.push_back(skill); } @@ -435,16 +433,11 @@ namespace MWGui addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + for (const int skillId : skills) { - int skillId = *it; if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes continue; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; - int base = stat.getBase(); - int modified = stat.getModified(); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -456,13 +449,9 @@ namespace MWGui const ESM::Attribute* attr = esmStore.get().find(skill->mData.mAttribute); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; std::pair widgets = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - MyGUI::utility::toString(static_cast(modified)), state, coord1, coord2); + "", "normal", coord1, coord2); + mSkillWidgetMap[skillId] = widgets; for (int i=0; i<2; ++i) { @@ -473,27 +462,9 @@ namespace MWGui mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - if (base < 100) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "false"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "true"); - - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "true"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "false"); - - setSkillProgress(mSkillWidgets[mSkillWidgets.size()-1-i], stat.getProgress(), skillId); - } - else - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "true"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "false"); - - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "false"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "true"); - } } - mSkillWidgetMap[skillId] = widgets; + setValue(static_cast(skillId), mSkillValues.find(skillId)->second); } } @@ -501,9 +472,9 @@ namespace MWGui { mChanged = false; - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (MyGUI::Widget* widget : mSkillWidgets) { - MyGUI::Gui::getInstance().destroyWidget(*it); + MyGUI::Gui::getInstance().destroyWidget(widget); } mSkillWidgets.clear(); @@ -552,11 +523,11 @@ namespace MWGui const std::set &expelled = PCstats.getExpelled(); bool firstFaction=true; - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + for (auto& factionPair : mFactions) { + const std::string& factionId = factionPair.first; const ESM::Faction *faction = - store.get().find(it->first); + store.get().find(factionId); if (faction->mData.mIsHidden == 1) continue; @@ -577,11 +548,11 @@ namespace MWGui text += std::string("#{fontcolourhtml=header}") + faction->mName; - if (expelled.find(it->first) != expelled.end()) + if (expelled.find(factionId) != expelled.end()) text += "\n#{fontcolourhtml=normal}#{sExpelled}"; else { - int rank = it->second; + int rank = factionPair.second; rank = std::max(0, std::min(9, rank)); text += std::string("\n#{fontcolourhtml=normal}") + faction->mRanks[rank]; diff --git a/apps/openmw/mwgui/timeadvancer.cpp b/apps/openmw/mwgui/timeadvancer.cpp index 43504ce87..a07da1682 100644 --- a/apps/openmw/mwgui/timeadvancer.cpp +++ b/apps/openmw/mwgui/timeadvancer.cpp @@ -1,8 +1,5 @@ #include "timeadvancer.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { TimeAdvancer::TimeAdvancer(float delay) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a1879c2f9..f9775253a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -226,18 +226,17 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); info.caption = spell->mName; Widgets::SpellEffectList effects; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + for (const ESM::ENAMstruct& spellEffect : spell->mEffects.mList) { Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; + params.mEffectID = spellEffect.mEffectID; + params.mSkill = spellEffect.mSkill; + params.mAttribute = spellEffect.mAttribute; + params.mDuration = spellEffect.mDuration; + params.mMagnMin = spellEffect.mMagnMin; + params.mMagnMax = spellEffect.mMagnMax; + params.mRange = spellEffect.mRange; + params.mArea = spellEffect.mArea; params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); params.mNoTarget = false; effects.push_back(params); @@ -260,14 +259,13 @@ namespace MWGui tooltip->setVisible(true); std::map userStrings = focus->getUserStrings(); - for (std::map::iterator it = userStrings.begin(); - it != userStrings.end(); ++it) + for (auto& userStringPair : userStrings) { - size_t underscorePos = it->first.find("_"); + size_t underscorePos = userStringPair.first.find("_"); if (underscorePos == std::string::npos) continue; - std::string key = it->first.substr(0, underscorePos); - std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + std::string key = userStringPair.first.substr(0, underscorePos); + std::string widgetName = userStringPair.first.substr(underscorePos+1, userStringPair.first.size()-(underscorePos+1)); type = "Property"; size_t caretPos = key.find("^"); @@ -280,9 +278,9 @@ namespace MWGui MyGUI::Widget* w; getWidget(w, widgetName); if (type == "Property") - w->setProperty(key, it->second); + w->setProperty(key, userStringPair.second); else if (type == "UserData") - w->setUserString(key, it->second); + w->setUserString(key, userStringPair.second); } tooltipSize = tooltip->getSize(); @@ -458,7 +456,7 @@ namespace MWGui MyGUI::IntSize totalSize = MyGUI::IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - for (std::vector::const_iterator it = info.notes.begin(); it != info.notes.end(); ++it) + for (const std::string& note : info.notes) { MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); @@ -468,7 +466,7 @@ namespace MWGui MyGUI::Align::Default); edit->setEditMultiLine(true); edit->setEditWordWrap(true); - edit->setCaption(*it); + edit->setCaption(note); edit->setSize(edit->getWidth(), edit->getTextSize().height); icon->setPosition(icon->getLeft(),(edit->getTop()+edit->getBottom())/2-icon->getHeight()/2); totalSize.height += std::max(edit->getHeight(), icon->getHeight()); @@ -653,12 +651,12 @@ namespace MWGui std::vector > itemOwners = MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId()); - for (std::vector >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it) + for (std::pair& owner : itemOwners) { - if (it->second == std::numeric_limits::max()) - ret += std::string("\nStolen from ") + it->first; // for legacy (ESS) savegames + if (owner.second == std::numeric_limits::max()) + ret += std::string("\nStolen from ") + owner.first; // for legacy (ESS) savegames else - ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first; + ret += std::string("\nStolen ") + MyGUI::utility::toString(owner.second) + " from " + owner.first; } ret += getMiscString(cellref.getGlobalVariable(), "Global"); @@ -732,17 +730,16 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); bool isFirst = true; - MWWorld::Store::iterator it = skills.begin(); - for (; it != skills.end(); ++it) + for (auto& skillPair : skills) { - if (it->second.mData.mSpecialization == specId) + if (skillPair.second.mData.mSpecialization == specId) { if (isFirst) isFirst = false; else specText += "\n"; - specText += std::string("#{") + ESM::Skill::sSkillNameIds[it->first] + "}"; + specText += std::string("#{") + ESM::Skill::sSkillNameIds[skillPair.first] + "}"; } } widget->setUserString("Caption_ColumnText", specText); @@ -767,9 +764,8 @@ namespace MWGui std::vector abilities, powers, spells; - for (std::vector::const_iterator it = sign->mPowers.mList.begin(); it != sign->mPowers.mList.end(); ++it) + for (const std::string& spellId : sign->mPowers.mList) { - const std::string &spellId = *it; const ESM::Spell *spell = store.get().search(spellId); if (!spell) continue; // Skip spells which cannot be found @@ -797,15 +793,15 @@ namespace MWGui for (int category = 0; category < 3; ++category) { - for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + bool addHeader = true; + for (const std::string& spellId : categories[category].spells) { - if (it == categories[category].spells.begin()) + if (addHeader) { text += std::string("\n\n#{fontcolourhtml=header}") + std::string("#{") + categories[category].label + "}"; + addHeader = false; } - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().find(spellId); text += "\n#{fontcolourhtml=normal}" + spell->mName; } diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index a26294a0e..84b23ee2b 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -36,13 +36,12 @@ namespace MWGui void TradeItemModel::borrowImpl(const ItemStack &item, std::vector &out) { - std::vector::iterator it = out.begin(); bool found = false; - for (; it != out.end(); ++it) + for (ItemStack& itemStack : out) { - if (it->mBase == item.mBase) + if (itemStack.mBase == item.mBase) { - it->mCount += item.mCount; + itemStack.mCount += item.mCount; found = true; break; } @@ -100,15 +99,15 @@ namespace MWGui void TradeItemModel::adjustEncumbrance(float &encumbrance) { - for (std::vector::iterator it = mBorrowedToUs.begin(); it != mBorrowedToUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedToUs) { - MWWorld::Ptr item = it->mBase; - encumbrance += item.getClass().getWeight(item) * it->mCount; + MWWorld::Ptr& item = itemStack.mBase; + encumbrance += item.getClass().getWeight(item) * itemStack.mCount; } - for (std::vector::iterator it = mBorrowedFromUs.begin(); it != mBorrowedFromUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedFromUs) { - MWWorld::Ptr item = it->mBase; - encumbrance -= item.getClass().getWeight(item) * it->mCount; + MWWorld::Ptr& item = itemStack.mBase; + encumbrance -= item.getClass().getWeight(item) * itemStack.mCount; } encumbrance = std::max(0.f, encumbrance); } @@ -126,15 +125,14 @@ namespace MWGui void TradeItemModel::transferItems() { - std::vector::iterator it = mBorrowedToUs.begin(); - for (; it != mBorrowedToUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedToUs) { // get index in the source model - ItemModel* sourceModel = it->mCreator; + ItemModel* sourceModel = itemStack.mCreator; size_t i=0; for (; igetItemCount(); ++i) { - if (it->mBase == sourceModel->getItem(i).mBase) + if (itemStack.mBase == sourceModel->getItem(i).mBase) break; } if (i == sourceModel->getItemCount()) @@ -142,9 +140,9 @@ namespace MWGui const ItemStack& item = sourceModel->getItem(i); // copy the borrowed items to our model - copyItem(item, it->mCount); + copyItem(item, itemStack.mCount); // then remove them from the source model - sourceModel->removeItem(item, it->mCount); + sourceModel->removeItem(item, itemStack.mCount); } mBorrowedToUs.clear(); mBorrowedFromUs.clear(); @@ -189,14 +187,13 @@ namespace MWGui } // don't show items that we borrowed to someone else - std::vector::iterator it = mBorrowedFromUs.begin(); - for (; it != mBorrowedFromUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedFromUs) { - if (it->mBase == item.mBase) + if (itemStack.mBase == item.mBase) { - if (item.mCount < it->mCount) + if (item.mCount < itemStack.mCount) throw std::runtime_error("Lent more items than present"); - item.mCount -= it->mCount; + item.mCount -= itemStack.mCount; } } @@ -205,12 +202,10 @@ namespace MWGui } // add items borrowed to us - std::vector::iterator it = mBorrowedToUs.begin(); - for (; it != mBorrowedToUs.end(); ++it) + for (ItemStack& itemStack : mBorrowedToUs) { - ItemStack item = *it; - item.mType = ItemStack::Type_Barter; - mItems.push_back(item); + itemStack.mType = ItemStack::Type_Barter; + mItems.push_back(itemStack); } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 90698dfc4..b197ecef6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -106,9 +106,9 @@ namespace MWGui // Also restock any containers owned by this merchant, which are also available to buy in the trade window std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources); - for (std::vector::iterator it = itemSources.begin(); it != itemSources.end(); ++it) + for (MWWorld::Ptr& source : itemSources) { - it->getClass().restock(*it); + source.getClass().restock(source); } } @@ -306,16 +306,15 @@ namespace MWGui } // check if the player is attempting to sell back an item stolen from this actor - for (std::vector::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) + for (ItemStack& itemStack : merchantBought) { - if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr)) + if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(itemStack.mBase.getCellRef().getRefId(), mPtr)) { std::string msg = gmst.find("sNotifyMessage49")->mValue.getString(); - if (msg.find("%s") != std::string::npos) - msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); + Misc::StringUtils::replace(msg, "%s", itemStack.mBase.getClass().getName(itemStack.mBase).c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, itemStack.mBase, mPtr, itemStack.mCount); onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); @@ -470,15 +469,15 @@ namespace MWGui int merchantOffer = 0; std::vector playerBorrowed = playerTradeModel->getItemsBorrowedToUs(); - for (std::vector::const_iterator it = playerBorrowed.begin(); it != playerBorrowed.end(); ++it) + for (const ItemStack& itemStack : playerBorrowed) { - merchantOffer -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(it->mBase, it->mCount), true); + merchantOffer -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(itemStack.mBase, itemStack.mCount), true); } std::vector merchantBorrowed = mTradeModel->getItemsBorrowedToUs(); - for (std::vector::const_iterator it = merchantBorrowed.begin(); it != merchantBorrowed.end(); ++it) + for (const ItemStack& itemStack : merchantBorrowed) { - merchantOffer += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(it->mBase, it->mCount), false); + merchantOffer += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, getEffectiveValue(itemStack.mBase, itemStack.mCount), false); } int diff = merchantOffer - mCurrentMerchantOffer; diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp index 20af579a2..dadd1471a 100644 --- a/apps/openmw/mwgui/videowidget.hpp +++ b/apps/openmw/mwgui/videowidget.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MWGUI_VIDEOWIDGET_H #define OPENMW_MWGUI_VIDEOWIDGET_H +#include + #include namespace Video diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index c90d54072..093824d4b 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -222,18 +222,17 @@ namespace MWGui const ESM::Spell *spell = store.get().search(mId); MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + for (const ESM::ENAMstruct& effectInfo : spell->mEffects.mList) { MWSpellEffectPtr effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; + params.mEffectID = effectInfo.mEffectID; + params.mSkill = effectInfo.mSkill; + params.mAttribute = effectInfo.mAttribute; + params.mDuration = effectInfo.mDuration; + params.mMagnMin = effectInfo.mMagnMin; + params.mMagnMax = effectInfo.mMagnMax; + params.mRange = effectInfo.mRange; params.mIsConstant = (flags & MWEffectList::EF_Constant) != 0; params.mNoTarget = (flags & MWEffectList::EF_NoTarget); effect->setSpellEffect(params); @@ -289,13 +288,12 @@ namespace MWGui MWSpellEffectPtr effect = nullptr; int maxwidth = coord.width; - for (SpellEffectList::iterator it=mEffectList.begin(); - it != mEffectList.end(); ++it) + for (auto& effectInfo : mEffectList) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; - it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; - effect->setSpellEffect(*it); + effectInfo.mIsConstant = (flags & EF_Constant) || effectInfo.mIsConstant; + effectInfo.mNoTarget = (flags & EF_NoTarget) || effectInfo.mNoTarget; + effect->setSpellEffect(effectInfo); effects.push_back(effect); if (effect->getRequestedWidth() > maxwidth) maxwidth = effect->getRequestedWidth(); @@ -304,9 +302,9 @@ namespace MWGui } // ... then adjust the size for all widgets - for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + for (MyGUI::Widget* effectWidget : effects) { - effect = (*it)->castType(); + effect = effectWidget->castType(); bool needcenter = center && (maxwidth > effect->getRequestedWidth()); int diff = maxwidth - effect->getRequestedWidth(); if (needcenter) @@ -339,18 +337,17 @@ namespace MWGui SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) { SpellEffectList result; - std::vector::const_iterator end = effects->mList.end(); - for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) + for (const ESM::ENAMstruct& effectInfo : effects->mList) { SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; + params.mEffectID = effectInfo.mEffectID; + params.mSkill = effectInfo.mSkill; + params.mAttribute = effectInfo.mAttribute; + params.mDuration = effectInfo.mDuration; + params.mMagnMin = effectInfo.mMagnMin; + params.mMagnMax = effectInfo.mMagnMax; + params.mRange = effectInfo.mRange; + params.mArea = effectInfo.mArea; result.push_back(params); } return result; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 86c780325..727493892 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e6e5aedb0..b91379d21 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,13 +1,11 @@ #include "windowmanagerimp.hpp" #include -#include #include #include #include -#include #include #include #include @@ -50,7 +48,6 @@ #include #include -#include #include #include #include @@ -59,8 +56,6 @@ #include -#include - #include #include "../mwbase/inputmanager.hpp" @@ -696,9 +691,9 @@ namespace MWGui // Delete any dialogs which are no longer in use if (!mGarbageDialogs.empty()) { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + for (Layout* widget : mGarbageDialogs) { - delete *it; + delete widget; } mGarbageDialogs.clear(); } @@ -1287,14 +1282,13 @@ namespace MWGui { mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); - for (Settings::CategorySettingVector::const_iterator it = changed.begin(); - it != changed.end(); ++it) + for (const auto& setting : changed) { - if (it->first == "HUD" && it->second == "crosshair") + if (setting.first == "HUD" && setting.second == "crosshair") mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); - else if (it->first == "GUI" && it->second == "subtitles") + else if (setting.first == "GUI" && setting.second == "subtitles") mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); - else if (it->first == "GUI" && it->second == "menu transparency") + else if (setting.first == "GUI" && setting.second == "menu transparency") setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } } diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 271d4e3a8..88e88b494 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -16,10 +16,10 @@ namespace MWGui MyGUI::Button* button = nullptr; MyGUI::VectorWidgetPtr widgets = window->getSkinWidgetsByName("Action"); - for (MyGUI::VectorWidgetPtr::iterator it = widgets.begin(); it != widgets.end(); ++it) + for (MyGUI::Widget* widget : widgets) { - if ((*it)->isUserString("HideWindowOnDoubleClick")) - button = (*it)->castType(); + if (widget->isUserString("HideWindowOnDoubleClick")) + button = widget->castType(); } if (button) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9e11363d9..e4cfe73a8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -74,14 +74,18 @@ namespace MWInput , mTimeIdle(0.f) , mMouseLookEnabled(false) , mGuiCursorEnabled(true) + , mGamepadGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) , mGuiCursorX(0) , mGuiCursorY(0) , mMouseWheel(0) + , mGamepadZoom(0) , mUserFileExists(userFileExists) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) + , mSneakToggleShortcutTimer(0.f) + , mSneakGamepadShortcut(false) , mSneaking(false) , mAttemptJump(false) , mInvUiScalingFactor(1.f) @@ -204,6 +208,8 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + // Temporary shut-down of this function until deemed necessary. + return; if (SDL_IsTextInputActive()) return; @@ -231,6 +237,96 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); } + bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release=false) + { + // Presumption of GUI mode will be removed in the future. + // MyGUI KeyCodes *may* change. + // Currently button releases are ignored. + if (release) + return false; + + MyGUI::KeyCode key = MyGUI::KeyCode::None; + switch (arg.button) + { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + key = MyGUI::KeyCode::ArrowUp; + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + key = MyGUI::KeyCode::ArrowRight; + break; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + key = MyGUI::KeyCode::ArrowDown; + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + key = MyGUI::KeyCode::ArrowLeft; + break; + case SDL_CONTROLLER_BUTTON_A: + // If we are using the joystick as a GUI mouse, A must be handled via mouse. + if (mGamepadGuiCursorEnabled) + return false; + key = MyGUI::KeyCode::Space; + break; + case SDL_CONTROLLER_BUTTON_B: + if (MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + else + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + return true; + case SDL_CONTROLLER_BUTTON_X: + key = MyGUI::KeyCode::Semicolon; + break; + case SDL_CONTROLLER_BUTTON_Y: + key = MyGUI::KeyCode::Apostrophe; + break; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + key = MyGUI::KeyCode::Period; + break; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + key = MyGUI::KeyCode::Slash; + break; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled; + MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled); + return true; + default: + return false; + } + + // Some keys will work even when Text Input windows/modals are in focus. + if (SDL_IsTextInputActive()) + return false; + + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); + return true; + } + + bool InputManager::gamepadToGuiControl(const SDL_ControllerAxisEvent &arg) + { + switch (arg.axis) + { + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); + break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); + break; + case SDL_CONTROLLER_AXIS_LEFTX: + case SDL_CONTROLLER_AXIS_LEFTY: + case SDL_CONTROLLER_AXIS_RIGHTX: + case SDL_CONTROLLER_AXIS_RIGHTY: + // If we are using the joystick as a GUI mouse, process mouse movement elsewhere. + if (mGamepadGuiCursorEnabled) + return false; + break; + default: + return false; + } + + return true; + } + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { resetIdleTime (); @@ -265,11 +361,29 @@ namespace MWInput { if (action == A_Use) { - MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState(); - mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing); + if(mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) + action = A_CycleWeaponRight; + + else if (mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) + action = A_CycleSpellRight; + + else + { + MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState(); + mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing); + } } else if (action == A_Jump) - mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); + { + if(mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) + action = A_CycleWeaponLeft; + + else if (mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) + action = A_CycleSpellLeft; + + else + mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); + } } if (currentValue == 1) @@ -280,6 +394,9 @@ namespace MWInput case A_GameMenu: toggleMainMenu (); break; + case A_OptionsMenu: + toggleOptionsMenu(); + break; case A_Screenshot: screenshot(); break; @@ -442,7 +559,7 @@ namespace MWInput updateCursorMode(); - if (mGuiCursorEnabled) + if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled)) { float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; @@ -506,28 +623,17 @@ namespace MWInput // joystick movement float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); - if (xAxis < .5) + if (xAxis != .5) { triedToMove = true; - mPlayer->setLeftRight (-1); - } - else if (xAxis > .5) - { - triedToMove = true; - mPlayer->setLeftRight (1); + mPlayer->setLeftRight((xAxis - 0.5f) * 2); } - if (yAxis < .5) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); - } - else if (yAxis > .5) + if (yAxis != .5) { triedToMove = true; mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); + mPlayer->setForwardBackward((yAxis - 0.5f) * 2 * -1); } else if(mPlayer->getAutoMove()) { @@ -572,7 +678,35 @@ namespace MWInput if (!mSneakToggles) { - mPlayer->setSneak(actionIsActive(A_Sneak)); + if(mJoystickLastUsed) + { + if(actionIsActive(A_Sneak)) + { + if(mSneakToggleShortcutTimer) // New Sneak Button Press + { + if(mSneakToggleShortcutTimer <= 0.3f) + { + mSneakGamepadShortcut = true; + toggleSneaking(); + } + else + mSneakGamepadShortcut = false; + } + + if(!mSneaking) + toggleSneaking(); + mSneakToggleShortcutTimer = 0.f; + } + else + { + if(!mSneakGamepadShortcut && mSneaking) + toggleSneaking(); + if(mSneakToggleShortcutTimer <= 0.3f) + mSneakToggleShortcutTimer += dt; + } + } + else + mPlayer->setSneak(actionIsActive(A_Sneak)); } if (mAttemptJump && mControlSwitch["playerjumping"]) @@ -619,6 +753,13 @@ namespace MWInput MWBase::Environment::get().getWorld()->togglePOV(); } mPreviewPOVDelay = 0.f; + mGamepadZoom = 0; + } + + if(mGamepadZoom) + { + MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom); + MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true); } } } @@ -635,6 +776,8 @@ namespace MWInput updateIdleTime(dt); } } + else + mGamepadZoom = 0; mAttemptJump = false; // Can only jump on first frame input is on } @@ -649,7 +792,7 @@ namespace MWInput mMouseLookEnabled = !guiMode; if (guiMode) MWBase::Environment::get().getWindowManager()->showCrosshair(false); - MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode); + MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode && (mJoystickLastUsed && !mGamepadGuiCursorEnabled)); // if not in gui mode, the camera decides whether to show crosshair or not. } @@ -830,6 +973,8 @@ namespace MWInput if (mGuiCursorEnabled) { + if (!mGamepadGuiCursorEnabled) + mGamepadGuiCursorEnabled = true; // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor mGuiCursorX = static_cast(arg.x) * mInvUiScalingFactor; @@ -875,36 +1020,37 @@ namespace MWInput void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) { - if (!mJoystickEnabled) + if (!mJoystickEnabled || mInputBinder->detectingBindingState()) return; mJoystickLastUsed = true; - bool guiMode = false; - - if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - if(!mInputBinder->detectingBindingState()) + if (gamepadToGuiControl(arg, false)) + return; + else if (mGamepadGuiCursorEnabled) { - guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), - sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; - if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + // Temporary mouse binding until keyboard controls are available: + if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. { - MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); - if (b && b->getEnabled()) + bool mousePressSuccess = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(SDL_BUTTON_LEFT)); + if (MyGUI::InputManager::getInstance().getMouseFocusWidget()) { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); + MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType(false); + if (b && b->getEnabled()) + MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); } + + setPlayerControlsEnabled(!mousePressSuccess); } } } - - setPlayerControlsEnabled(!guiMode); + else + setPlayerControlsEnabled(true); //esc, to leave initial movie screen OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0)); if (!mControlsDisabled) mInputBinder->buttonPressed(deviceID, arg); @@ -912,34 +1058,69 @@ namespace MWInput void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) { - if (!mJoystickEnabled) + if(mInputBinder->detectingBindingState()) + { + mInputBinder->buttonReleased(deviceID, arg); + return; + } + if (!mJoystickEnabled || mControlsDisabled) return; mJoystickLastUsed = true; - if(mInputBinder->detectingBindingState()) - mInputBinder->buttonReleased(deviceID, arg); - else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; - - if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind + if (gamepadToGuiControl(arg, true)) + return; + else if (mGamepadGuiCursorEnabled) + { + // Temporary mouse binding until keyboard controls are available: + if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. + { + bool mousePressSuccess = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mGuiCursorX), static_cast(mGuiCursorY), sdlButtonToMyGUI(SDL_BUTTON_LEFT)); + if (mInputBinder->detectingBindingState()) // If the player just triggered binding, don't let button release bind. + return; - setPlayerControlsEnabled(!guiMode); - mInputBinder->buttonReleased(deviceID, arg); + setPlayerControlsEnabled(!mousePressSuccess); + } + } } else - mInputBinder->buttonReleased(deviceID, arg); + setPlayerControlsEnabled(true); - ///to escape initial movie + //esc, to leave initial movie screen OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + + mInputBinder->buttonReleased(deviceID, arg); } void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) { - if (!mControlsDisabled && mJoystickEnabled) - mInputBinder->axisMoved(deviceID, arg); + if(!mJoystickEnabled || mControlsDisabled) + return; + + mJoystickLastUsed = true; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + gamepadToGuiControl(arg); + } + else + { + if(mPreviewPOVDelay == 1.f && arg.value) // Preview Mode Gamepad Zooming + { + if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + { + mGamepadZoom = static_cast(arg.value / 10000 * 8.5f); + return; // Do not propogate event. + } + else if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) + { + mGamepadZoom = static_cast(-(arg.value / 10000 * 8.5f)); + return; // Do not propogate event. + } + } + } + mInputBinder->axisMoved(deviceID, arg); } void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) @@ -975,19 +1156,38 @@ namespace MWInput void InputManager::toggleMainMenu() { - if (MyGUI::InputManager::getInstance().isModalAny()) { + if (MyGUI::InputManager::getInstance().isModalAny()) + { MWBase::Environment::get().getWindowManager()->exitCurrentModal(); return; } - if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu - { - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); - } - else //Close current GUI + bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame; + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + + if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + if (inGame && mode != MWGui::GM_MainMenu) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); + } + + void InputManager::toggleOptionsMenu() + { + if (MyGUI::InputManager::getInstance().isModalAny()) { - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + return; } + + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame; + + if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + if (inGame && mode != MWGui::GM_Settings) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); } void InputManager::quickLoad() { @@ -1397,20 +1597,20 @@ namespace MWInput defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A; defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X; - defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_Y; //defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9) - defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; - defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y; - defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK; - defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; + defaultButtonBindings[A_OptionsMenu] = SDL_CONTROLLER_BUTTON_BACK; defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; - defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; - defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; - defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; - defaultButtonBindings[A_QuickKey4] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP; + defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + defaultButtonBindings[A_MoveBackward] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + defaultButtonBindings[A_MoveRight] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; std::map defaultAxisBindings; defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY; @@ -1418,6 +1618,7 @@ namespace MWInput defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY; defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX; defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + defaultAxisBindings[A_Jump] = SDL_CONTROLLER_AXIS_TRIGGERLEFT; for (int i = 0; i < A_Last; i++) { @@ -1485,6 +1686,7 @@ namespace MWInput descriptions[A_Journal] = "sJournal"; descriptions[A_Rest] = "sRestKey"; descriptions[A_Inventory] = "sInventory"; + descriptions[A_OptionsMenu] = "sPreferences"; descriptions[A_TogglePOV] = "sTogglePOVCmd"; descriptions[A_QuickKeysMenu] = "sQuickMenu"; descriptions[A_QuickKey1] = "sQuick1Cmd"; @@ -1622,6 +1824,7 @@ namespace MWInput ret.push_back(A_Inventory); ret.push_back(A_Journal); ret.push_back(A_Rest); + ret.push_back(A_OptionsMenu); ret.push_back(A_Console); ret.push_back(A_QuickSave); ret.push_back(A_QuickLoad); @@ -1654,6 +1857,7 @@ namespace MWInput ret.push_back(A_Inventory); ret.push_back(A_Journal); ret.push_back(A_Rest); + ret.push_back(A_OptionsMenu); ret.push_back(A_QuickSave); ret.push_back(A_QuickLoad); ret.push_back(A_Screenshot); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 41b0bd404..8b3253dcd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -188,6 +188,7 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mGamepadGuiCursorEnabled; bool mDetectingKeyboard; @@ -196,9 +197,12 @@ namespace MWInput float mGuiCursorX; float mGuiCursorY; int mMouseWheel; + float mGamepadZoom; bool mUserFileExists; bool mAlwaysRunActive; bool mSneakToggles; + float mSneakToggleShortcutTimer; + bool mSneakGamepadShortcut; bool mSneaking; bool mAttemptJump; @@ -219,6 +223,9 @@ namespace MWInput void setPlayerControlsEnabled(bool enabled); void handleGuiArrowKey(int action); + // Return true if GUI consumes input. + bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release); + bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg); void updateCursorMode(); @@ -226,6 +233,7 @@ namespace MWInput private: void toggleMainMenu(); + void toggleOptionsMenu(); void toggleSpell(); void toggleWeapon(); void toggleInventory(); @@ -318,6 +326,8 @@ namespace MWInput A_MoveForwardBackward, A_MoveLeftRight, + A_OptionsMenu, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 9fc7c2300..c745ed76b 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -20,7 +20,6 @@ #include "../mwworld/class.hpp" #include "creaturestats.hpp" -#include "steering.hpp" #include "movement.hpp" namespace MWMechanics diff --git a/apps/openmw/mwmechanics/aicast.cpp b/apps/openmw/mwmechanics/aicast.cpp index e448313bf..b7c9bac3b 100644 --- a/apps/openmw/mwmechanics/aicast.cpp +++ b/apps/openmw/mwmechanics/aicast.cpp @@ -8,7 +8,6 @@ #include "aicombataction.hpp" #include "creaturestats.hpp" -#include "spellcasting.hpp" #include "steering.hpp" MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 045cd9a0f..aa7b4fe05 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -28,15 +28,12 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwrender/animation.hpp" - #include "pathgrid.hpp" #include "creaturestats.hpp" #include "steering.hpp" #include "movement.hpp" #include "character.hpp" #include "aicombataction.hpp" -#include "combat.hpp" #include "coordinateconverter.hpp" #include "actorutil.hpp" diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 3d018d780..03951d279 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -11,7 +11,6 @@ #include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" -#include "steering.hpp" #include "movement.hpp" /* diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 4646875fd..90da9d160 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -1,7 +1,5 @@ #include "aipackage.hpp" -#include - #include #include #include @@ -137,9 +135,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& { if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path { - const osg::Vec3f playerHalfExtents = world->getHalfExtents(getPlayer()); // Using player half extents for better performance + const auto pathfindingHalfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), - playerHalfExtents, getNavigatorFlags(actor)); + pathfindingHalfExtents, getNavigatorFlags(actor)); mRotateOnTheRunChecks = 3; // give priority to go directly on target if there is minimal opportunity @@ -169,7 +167,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& mTimer = 0; } - const float pointTolerance = std::min(actor.getClass().getSpeed(actor), DEFAULT_TOLERANCE); + const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration + + 1.2 * std::max(halfExtents.x(), halfExtents.y()); + const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance); mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE); diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 82641af8d..e1b9548c9 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -1,7 +1,6 @@ #include "aipursue.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index cf572abc0..13f34058c 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -5,7 +5,6 @@ #include #include -#include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "aipackage.hpp" @@ -470,7 +469,7 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) for (std::vector::const_iterator it = sequence.mPackages.begin(); it != sequence.mPackages.end(); ++it) { - std::unique_ptr package (nullptr); + std::unique_ptr package; switch (it->mType) { case ESM::AiSequence::Ai_Wander: diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index d87029809..a2876da4f 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,7 +1,6 @@ #include "aitravel.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -10,7 +9,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" -#include "steering.hpp" #include "movement.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 05465c6b0..405f36767 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -155,9 +155,9 @@ namespace MWMechanics } else { - const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); // Using player half extents for better performance + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); } if (mPathFinder.isPathConstructed()) @@ -312,10 +312,9 @@ namespace MWMechanics if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || (isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) { - // Using player half extents for better performance - const osg::Vec3f playerHalfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(getPlayer()); + const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), - getPathGridGraph(actor.getCell()), playerHalfExtents, getNavigatorFlags(actor)); + getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); mPathFinder.addPointToPath(mDestination); if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 13c06225a..9c6f8e6e0 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,7 +1,6 @@ #include "alchemy.hpp" #include -#include #include #include diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4789e999a..43144d87e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -947,7 +947,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) { mAnimation->showWeapons(true); - mAnimation->setWeaponGroup(mCurrentWeapon); + // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly, + // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example) + bool useRelativeDuration = mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Crossbow; + mAnimation->setWeaponGroup(mCurrentWeapon, useRelativeDuration); } mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType)); @@ -1435,7 +1438,10 @@ bool CharacterController::updateWeaponState(CharacterState& idle) mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype)); getWeaponGroup(weaptype, weapgroup); - mAnimation->setWeaponGroup(weapgroup); + // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly, + // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example) + bool useRelativeDuration = weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow; + mAnimation->setWeaponGroup(weapgroup, useRelativeDuration); if (!isStillWeapon) { @@ -2078,6 +2084,23 @@ void CharacterController::update(float duration, bool animationOnly) osg::Vec3f rot = cls.getRotationVector(mPtr); speed = cls.getSpeed(mPtr); + if(isPlayer) + { + // Joystick anologue movement. + float xAxis = std::abs(cls.getMovementSettings(mPtr).mPosition[0]); + float yAxis = std::abs(cls.getMovementSettings(mPtr).mPosition[1]); + float analogueMovement = ((xAxis > yAxis) ? xAxis : yAxis); + + // If Strafing, our max speed is slower so multiply by X axis instead. + if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) + analogueMovement = xAxis; + + // Due to the half way split between walking/running, we multiply speed by 2 while walking, unless a keyboard was used. + if(!isrunning && !sneak && !flying && analogueMovement <= 0.5f) + speed *= 2; + + speed *= (analogueMovement); + } vec.x() *= speed; vec.y() *= speed; diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index af39bc335..2c0100469 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -187,30 +187,49 @@ namespace MWMechanics return false; } - void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) + bool isNormalWeapon(const MWWorld::Ptr &weapon) { - const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); - float resistance = std::min(100.f, effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() - - effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude()); + if (weapon.isEmpty()) + return false; - float multiplier = 1.f - resistance / 100.f; + const int flags = weapon.get()->mBase->mData.mFlags; + bool isSilver = flags & ESM::Weapon::Silver; + bool isMagical = flags & ESM::Weapon::Magical; + bool isEnchanted = !weapon.getClass().getEnchantment(weapon).empty(); - if (!(weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver - || weapon.get()->mBase->mData.mFlags & ESM::Weapon::Magical)) - { - if (weapon.getClass().getEnchantment(weapon).empty() - || !Settings::Manager::getBool("enchanted weapons are magical", "Game")) - damage *= multiplier; - } + return !isSilver && !isMagical && (!isEnchanted || !Settings::Manager::getBool("enchanted weapons are magical", "Game")); + } - if ((weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver) - && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) - damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + void resistNormalWeapon(const MWWorld::Ptr &actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr &weapon, float &damage) + { + if (damage == 0 || weapon.isEmpty() || !isNormalWeapon(weapon)) + return; + + const MWMechanics::MagicEffects& effects = actor.getClass().getCreatureStats(actor).getMagicEffects(); + const float resistance = effects.get(ESM::MagicEffect::ResistNormalWeapons).getMagnitude() / 100.f; + const float weakness = effects.get(ESM::MagicEffect::WeaknessToNormalWeapons).getMagnitude() / 100.f; + + damage *= 1.f - std::min(1.f, resistance-weakness); if (damage == 0 && attacker == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } + void applyWerewolfDamageMult(const MWWorld::Ptr &actor, const MWWorld::Ptr &weapon, float &damage) + { + if (damage == 0 || weapon.isEmpty() || !actor.getClass().isNpc()) + return; + + const int flags = weapon.get()->mBase->mData.mFlags; + bool isSilver = flags & ESM::Weapon::Silver; + + if (isSilver && actor.getClass().getNpcStats(actor).isWerewolf()) + { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + damage *= store.get().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat(); + } + } + void projectileHit(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, const osg::Vec3f& hitPosition, float attackStrength) { @@ -291,6 +310,9 @@ namespace MWMechanics damage += attack[0] + ((attack[1] - attack[0]) * attackStrength); adjustWeaponDamage(damage, weapon, attacker); + if (weapon == projectile || Settings::Manager::getBool("only appropriate ammunition bypasses resistance", "Game") || isNormalWeapon(weapon)) + resistNormalWeapon(victim, attacker, projectile, damage); + applyWerewolfDamageMult(victim, projectile, damage); if (attacker == getPlayer()) { diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index e5b6b5dd8..6be783219 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -20,8 +20,13 @@ bool applyOnStrikeEnchantment(const MWWorld::Ptr& attacker, const MWWorld::Ptr& /// @return can we block the attack? bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker, const MWWorld::Ptr& weapon, float damage, float attackStrength); +/// @return does normal weapon resistance and weakness apply to the weapon? +bool isNormalWeapon (const MWWorld::Ptr& weapon); + void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); +void applyWerewolfDamageMult (const MWWorld::Ptr& actor, const MWWorld::Ptr& weapon, float &damage); + /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt /// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index fec3bdd37..8bca9f9b5 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -60,8 +60,7 @@ namespace MWMechanics std::string msg = "sMagicContractDisease"; msg = MWBase::Environment::get().getWorld()->getStore().get().find(msg)->mValue.getString(); - if (msg.find("%s") != std::string::npos) - msg.replace(msg.find("%s"), 2, spell->mName); + Misc::StringUtils::replace(msg, "%s", spell->mName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msg); } } diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 021691d6a..1a1a44f63 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -1,7 +1,5 @@ #include "magiceffects.hpp" -#include - #include #include diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8d2e30fd9..db45aca4d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -34,7 +34,6 @@ #include "aicombat.hpp" #include "aipursue.hpp" -#include "aitravel.hpp" #include "spellcasting.hpp" #include "autocalcspell.hpp" #include "npcstats.hpp" diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7c62e8dba..bd01f5cf8 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -2,14 +2,11 @@ #include -#include - #include #include #include #include -#include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" @@ -252,16 +249,14 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas /// \todo check if character is the player, if levelling is ever implemented for NPCs MWBase::Environment::get().getWindowManager()->playSound("skillraise"); - std::stringstream message; + std::string message = MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", ""); + Misc::StringUtils::replace(message, "%s", ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}").c_str(), 2); + Misc::StringUtils::replace(message, "%d", std::to_string(base).c_str(), 2); if (readBook) - message << std::string("#{sBookSkillMessage}\n"); - - message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) - % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") - % static_cast (base); + message = "#{sBookSkillMessage}\n" + message; - MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never); + MWBase::Environment::get().getWindowManager ()->messageBox(message, MWGui::ShowInDialogueMode_Never); if (mLevelProgress >= gmst.find("iLevelUpTotal")->mValue.getInteger()) { diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index 9562c74df..3d8fe7919 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -1,9 +1,7 @@ #include "obstacle.hpp" -#include #include -#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 8c7d6fce9..e0285be92 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -262,9 +262,10 @@ namespace MWMechanics if (mPath.empty()) return; - const auto tolerance = mPath.size() > 1 ? pointTolerance : destinationTolerance; + while (mPath.size() > 1 && sqrDistanceIgnoreZ(mPath.front(), position) < pointTolerance * pointTolerance) + mPath.pop_front(); - if (sqrDistanceIgnoreZ(mPath.front(), position) < tolerance * tolerance) + if (mPath.size() == 1 && sqrDistanceIgnoreZ(mPath.front(), position) < destinationTolerance * destinationTolerance) mPath.pop_front(); } @@ -286,7 +287,8 @@ namespace MWMechanics mPath.clear(); mCell = cell; - buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); + if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor)) + buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath)); if (mPath.empty()) buildPathByPathgridImpl(startPoint, endPoint, pathgridGraph, std::back_inserter(mPath)); @@ -300,8 +302,11 @@ namespace MWMechanics { try { - const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); - navigator->findPath(halfExtents, startPoint, endPoint, flags, out); + const auto world = MWBase::Environment::get().getWorld(); + const auto realHalfExtents = world->getHalfExtents(actor); // This may differ from halfExtents argument + const auto stepSize = 2 * std::max(realHalfExtents.x(), realHalfExtents.y()); + const auto navigator = world->getNavigator(); + navigator->findPath(halfExtents, stepSize, startPoint, endPoint, flags, out); } catch (const DetourNavigator::NavigatorException& exception) { diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 567056fa5..8a5b8338a 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -46,10 +46,10 @@ namespace MWMechanics } const float PATHFIND_Z_REACH = 50.0f; - //static const float sMaxSlope = 49.0f; // duplicate as in physicssystem // distance after which actor (failed previously to shortcut) will try again const float PATHFIND_SHORTCUT_RETRY_DIST = 300.0f; + const float MIN_TOLERANCE = 1.0f; const float DEFAULT_TOLERANCE = 32.0f; // cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 2d9b7ccf7..778989b81 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -1,7 +1,5 @@ #include "repair.hpp" -#include - #include /* @@ -19,7 +17,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/containerstore.hpp" @@ -116,8 +113,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) std::string message = MWBase::Environment::get().getWorld()->getStore().get() .find("sNotifyMessage51")->mValue.getString(); + Misc::StringUtils::replace(message, "%s", mTool.getClass().getName(mTool).c_str(), 2); - MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % mTool.getClass().getName(mTool)).str()); + MWBase::Environment::get().getWindowManager()->messageBox(message); // try to find a new tool of the same ID for (MWWorld::ContainerStoreIterator iter (store.begin()); diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index f7f241c4d..ad1e2b7cd 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -22,7 +22,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e13b2e64f..fc3aee937 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include @@ -40,7 +38,6 @@ #include "../mwworld/inventorystore.hpp" #include "../mwrender/animation.hpp" -#include "../mwrender/vismask.hpp" #include "npcstats.hpp" #include "actorutil.hpp" @@ -1146,7 +1143,7 @@ namespace MWMechanics { // "X has no effect on you" std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage50")->mValue.getString(); - message = boost::str(boost::format(message) % ingredient->mName); + Misc::StringUtils::replace(message, "%s", ingredient->mName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(message); return false; } diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index c55d5ab10..79606fda6 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -12,12 +12,10 @@ #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/actionequip.hpp" #include "../mwworld/cellstore.hpp" #include "creaturestats.hpp" #include "spellcasting.hpp" -#include "combat.hpp" namespace { diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 0a11ed641..3214b3fc9 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,7 +1,5 @@ #include "spells.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 55fb2eaf0..66fbbcdcc 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -1,7 +1,6 @@ #include "weaponpriority.hpp" #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -78,7 +77,10 @@ namespace MWMechanics adjustWeaponDamage(rating, item, actor); if (weapon->mData.mType != ESM::Weapon::MarksmanBow && weapon->mData.mType != ESM::Weapon::MarksmanCrossbow) + { resistNormalWeapon(enemy, actor, item, rating); + applyWerewolfDamageMult(enemy, item, rating); + } else if (weapon->mData.mType == ESM::Weapon::MarksmanBow) { if (arrowRating <= 0.f) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 3ea3cbc20..f4f451db2 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -20,10 +20,10 @@ #include #include #include +#include #include "../mwworld/class.hpp" -#include "convert.hpp" #include "collisiontype.hpp" namespace MWPhysics @@ -75,7 +75,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr } else { - mShape.reset(new btBoxShape(toBullet(mHalfExtents))); + mShape.reset(new btBoxShape(Misc::Convert::toBullet(mHalfExtents))); mRotationallyInvariant = false; } @@ -172,13 +172,13 @@ void Actor::updateCollisionObjectPosition() btTransform tr = mCollisionObject->getWorldTransform(); osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale); osg::Vec3f newPosition = scaledTranslation + mPosition; - tr.setOrigin(toBullet(newPosition)); + tr.setOrigin(Misc::Convert::toBullet(newPosition)); mCollisionObject->setWorldTransform(tr); } osg::Vec3f Actor::getCollisionObjectPosition() const { - return toOsg(mCollisionObject->getWorldTransform().getOrigin()); + return Misc::Convert::toOsg(mCollisionObject->getWorldTransform().getOrigin()); } void Actor::setPosition(const osg::Vec3f &position) @@ -203,7 +203,7 @@ void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); - tr.setRotation(toBullet(mRotation)); + tr.setRotation(Misc::Convert::toBullet(mRotation)); mCollisionObject->setWorldTransform(tr); updateCollisionObjectPosition(); @@ -221,7 +221,7 @@ void Actor::updateScale() mPtr.getClass().adjustScale(mPtr, scaleVec, false); mScale = scaleVec; - mShape->setLocalScaling(toBullet(mScale)); + mShape->setLocalScaling(Misc::Convert::toBullet(mScale)); scaleVec = osg::Vec3f(scale,scale,scale); mPtr.getClass().adjustScale(mPtr, scaleVec, true); @@ -235,6 +235,11 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } +osg::Vec3f Actor::getOriginalHalfExtents() const +{ + return mHalfExtents; +} + osg::Vec3f Actor::getRenderingHalfExtents() const { return osg::componentMultiply(mHalfExtents, mRenderingScale); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 31dd22a22..8752f7fee 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,6 +66,11 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; + /** + * Returns the half extents of the collision body (not scaled) + */ + osg::Vec3f getOriginalHalfExtents() const; + /** * Returns the position of the collision body * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. diff --git a/apps/openmw/mwphysics/object.cpp b/apps/openmw/mwphysics/object.cpp index 2f2866821..950630141 100644 --- a/apps/openmw/mwphysics/object.cpp +++ b/apps/openmw/mwphysics/object.cpp @@ -1,12 +1,10 @@ #include "object.hpp" -#include "convert.hpp" #include #include #include #include - -#include +#include #include #include @@ -28,7 +26,7 @@ namespace MWPhysics mCollisionObject->setUserPointer(static_cast(this)); setScale(ptr.getCellRef().getScale()); - setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); const float* pos = ptr.getRefData().getPosition().pos; setOrigin(btVector3(pos[0], pos[1], pos[2])); } @@ -114,7 +112,7 @@ namespace MWPhysics matrix.orthoNormalize(matrix); btTransform transform; - transform.setOrigin(toBullet(matrix.getTrans()) * compound->getLocalScaling()); + transform.setOrigin(Misc::Convert::toBullet(matrix.getTrans()) * compound->getLocalScaling()); for (int i=0; i<3; ++i) for (int j=0; j<3; ++j) transform.getBasis()[i][j] = matrix(j,i); // NB column/row major difference diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 73a5dbe6a..3e3e42f13 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,15 +1,7 @@ #include "physicssystem.hpp" -#include -#include -#include -#include - -#include - #include -#include #include #include #include @@ -21,12 +13,6 @@ #include -#include -#include -#include -#include -#include - #include #include #include @@ -35,6 +21,7 @@ #include #include #include +#include #include // FindRecIndexVisitor @@ -50,14 +37,10 @@ #include "../mwrender/bulletdebugdraw.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" - #include "../mwworld/class.hpp" #include "collisiontype.hpp" #include "actor.hpp" -#include "convert.hpp" #include "trace.h" #include "object.hpp" #include "heightfield.hpp" @@ -260,7 +243,7 @@ namespace MWPhysics // Check if we actually found a valid spawn point (use an infinitely thin ray this time). // Required for some broken door destinations in Morrowind.esm, where the spawn point // intersects with other geometry if the actor's base is taken into account - btVector3 from = toBullet(position); + btVector3 from = Misc::Convert::toBullet(position); btVector3 to = from - btVector3(0,0,maxHeight); btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); @@ -270,11 +253,11 @@ namespace MWPhysics collisionWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit() && - ( (toOsg(resultCallback1.m_hitPointWorld) - (tracer.mEndPos-offset)).length2() > 35*35 + ( (Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) - (tracer.mEndPos-offset)).length2() > 35*35 || !isWalkableSlope(tracer.mPlaneNormal))) { actor->setOnSlope(!isWalkableSlope(resultCallback1.m_hitNormalWorld)); - return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); + return Misc::Convert::toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, sGroundOffset); } else { @@ -735,7 +718,7 @@ namespace MWPhysics btCollisionObject object; object.setCollisionShape(&shape); - object.setWorldTransform(btTransform(toBullet(orient), toBullet(center))); + object.setWorldTransform(btTransform(Misc::Convert::toBullet(orient), Misc::Convert::toBullet(center))); const btCollisionObject* me = nullptr; std::vector targetCollisionObjects; @@ -746,15 +729,15 @@ namespace MWPhysics if (!targets.empty()) { - for (std::vector::const_iterator it = targets.begin(); it != targets.end(); ++it) + for (MWWorld::Ptr& target : targets) { - const Actor* physactor2 = getActor(*it); - if (physactor2) - targetCollisionObjects.push_back(physactor2->getCollisionObject()); + const Actor* targetActor = getActor(target); + if (targetActor) + targetCollisionObjects.push_back(targetActor->getCollisionObject()); } } - DeepestNotMeContactTestResultCallback resultCallback(me, targetCollisionObjects, toBullet(origin)); + DeepestNotMeContactTestResultCallback resultCallback(me, targetCollisionObjects, Misc::Convert::toBullet(origin)); resultCallback.m_collisionFilterGroup = CollisionType_Actor; resultCallback.m_collisionFilterMask = CollisionType_World | CollisionType_Door | CollisionType_HeightMap | CollisionType_Actor; mCollisionWorld->contactTest(&object, resultCallback); @@ -763,7 +746,7 @@ namespace MWPhysics { PtrHolder* holder = static_cast(resultCallback.mObject->getUserPointer()); if (holder) - return std::make_pair(holder->getPtr(), toOsg(resultCallback.mContactPoint)); + return std::make_pair(holder->getPtr(), Misc::Convert::toOsg(resultCallback.mContactPoint)); } return std::make_pair(MWWorld::Ptr(), osg::Vec3f()); } @@ -779,7 +762,7 @@ namespace MWPhysics btTransform rayFrom; rayFrom.setIdentity(); - rayFrom.setOrigin(toBullet(point)); + rayFrom.setOrigin(Misc::Convert::toBullet(point)); // target the collision object's world origin, this should be the center of the collision object btTransform rayTo; @@ -795,7 +778,7 @@ namespace MWPhysics return 0.f; } else - return (point - toOsg(cb.m_hitPointWorld)).length(); + return (point - Misc::Convert::toOsg(cb.m_hitPointWorld)).length(); } class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback @@ -829,8 +812,8 @@ namespace MWPhysics PhysicsSystem::RayResult PhysicsSystem::castRay(const osg::Vec3f &from, const osg::Vec3f &to, const MWWorld::ConstPtr& ignore, std::vector targets, int mask, int group) const { - btVector3 btFrom = toBullet(from); - btVector3 btTo = toBullet(to); + btVector3 btFrom = Misc::Convert::toBullet(from); + btVector3 btTo = Misc::Convert::toBullet(to); const btCollisionObject* me = nullptr; std::vector targetCollisionObjects; @@ -850,9 +833,9 @@ namespace MWPhysics if (!targets.empty()) { - for (std::vector::const_iterator it = targets.begin(); it != targets.end(); ++it) + for (MWWorld::Ptr& target : targets) { - const Actor* actor = getActor(*it); + const Actor* actor = getActor(target); if (actor) targetCollisionObjects.push_back(actor->getCollisionObject()); } @@ -868,8 +851,8 @@ namespace MWPhysics result.mHit = resultCallback.hasHit(); if (resultCallback.hasHit()) { - result.mHitPos = toOsg(resultCallback.m_hitPointWorld); - result.mHitNormal = toOsg(resultCallback.m_hitNormalWorld); + result.mHitPos = Misc::Convert::toOsg(resultCallback.m_hitPointWorld); + result.mHitNormal = Misc::Convert::toOsg(resultCallback.m_hitNormalWorld); if (PtrHolder* ptrHolder = static_cast(resultCallback.m_collisionObject->getUserPointer())) result.mHitObject = ptrHolder->getPtr(); } @@ -878,15 +861,15 @@ namespace MWPhysics PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) { - btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); + btCollisionWorld::ClosestConvexResultCallback callback(Misc::Convert::toBullet(from), Misc::Convert::toBullet(to)); callback.m_collisionFilterGroup = 0xff; callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap|CollisionType_Door; btSphereShape shape(radius); const btQuaternion btrot = btQuaternion::getIdentity(); - btTransform from_ (btrot, toBullet(from)); - btTransform to_ (btrot, toBullet(to)); + btTransform from_ (btrot, Misc::Convert::toBullet(from)); + btTransform to_ (btrot, Misc::Convert::toBullet(to)); mCollisionWorld->convexSweepTest(&shape, from_, to_, callback); @@ -894,8 +877,8 @@ namespace MWPhysics result.mHit = callback.hasHit(); if (result.mHit) { - result.mHitPos = toOsg(callback.m_hitPointWorld); - result.mHitNormal = toOsg(callback.m_hitNormalWorld); + result.mHitPos = Misc::Convert::toOsg(callback.m_hitPointWorld); + result.mHitNormal = Misc::Convert::toOsg(callback.m_hitNormalWorld); } return result; } @@ -945,6 +928,14 @@ namespace MWPhysics return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getOriginalHalfExtents(const MWWorld::ConstPtr &actor) const + { + if (const Actor* physactor = getActor(actor)) + return physactor->getOriginalHalfExtents(); + else + return osg::Vec3f(); + } + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); @@ -1170,7 +1161,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - found->second->setRotation(toBullet(ptr.getRefData().getBaseNode()->getAttitude())); + found->second->setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } @@ -1191,7 +1182,7 @@ namespace MWPhysics ObjectMap::iterator found = mObjects.find(ptr); if (found != mObjects.end()) { - found->second->setOrigin(toBullet(ptr.getRefData().getPosition().asVec3())); + found->second->setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3())); mCollisionWorld->updateSingleAabb(found->second->getCollisionObject()); return; } @@ -1351,8 +1342,8 @@ namespace MWPhysics void PhysicsSystem::stepSimulation(float dt) { - for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) - (*it)->animateCollisionShapes(mCollisionWorld); + for (Object* animatedObject : mAnimatedObjects) + animatedObject->animateCollisionShapes(mCollisionWorld); #ifndef BT_NO_PROFILE CProfileManager::Reset(); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 6a44b3792..1cb575cbe 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -136,6 +136,9 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; + /// Get physical half extents (not scaled) of the given actor. + osg::Vec3f getOriginalHalfExtents(const MWWorld::ConstPtr& actor) const; + /// @see MWPhysics::Actor::getRenderingHalfExtents osg::Vec3f getRenderingHalfExtents(const MWWorld::ConstPtr& actor) const; diff --git a/apps/openmw/mwphysics/trace.cpp b/apps/openmw/mwphysics/trace.cpp index 204ec1467..57b0a8368 100644 --- a/apps/openmw/mwphysics/trace.cpp +++ b/apps/openmw/mwphysics/trace.cpp @@ -1,13 +1,12 @@ #include "trace.h" -#include +#include #include #include #include "collisiontype.hpp" #include "actor.hpp" -#include "convert.hpp" namespace MWPhysics { @@ -51,8 +50,8 @@ protected: void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& start, const osg::Vec3f& end, const btCollisionWorld* world) { - const btVector3 btstart = toBullet(start); - const btVector3 btend = toBullet(end); + const btVector3 btstart = Misc::Convert::toBullet(start); + const btVector3 btend = Misc::Convert::toBullet(end); const btTransform &trans = actor->getWorldTransform(); btTransform from(trans); @@ -77,7 +76,7 @@ void ActorTracer::doTrace(const btCollisionObject *actor, const osg::Vec3f& star mFraction = newTraceCallback.m_closestHitFraction; mPlaneNormal = osg::Vec3f(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); mEndPos = (end-start)*mFraction + start; - mHitPoint = toOsg(newTraceCallback.m_hitPointWorld); + mHitPoint = Misc::Convert::toOsg(newTraceCallback.m_hitPointWorld); mHitObject = newTraceCallback.m_hitCollisionObject; } else diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index afe8f5cd3..68b4c2ac8 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -194,15 +194,16 @@ void ActorAnimation::injectWeaponBones() } } -// To make sure we do not run morph controllers for weapons, i.e. bows -class EmptyCallback : public osg::NodeCallback +void ActorAnimation::resetControllers(osg::Node* node) { - public: + if (node == nullptr) + return; - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - } -}; + std::shared_ptr src; + src.reset(new NullAnimationTime); + SceneUtil::AssignControllerSourcesVisitor removeVisitor(src); + node->accept(removeVisitor); +} void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) { @@ -230,7 +231,9 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) if (mesh.empty() || boneName.empty()) return; - // If the scabbard is not found, use a weapon mesh as fallback + // If the scabbard is not found, use a weapon mesh as fallback. + // Note: it is unclear how to handle time for controllers attached to bodyparts, so disable them for now. + // We use the similar approach for other bodyparts. scabbardName = scabbardName.replace(scabbardName.size()-4, 4, "_sh.nif"); bool isEnchanted = !weapon->getClass().getEnchantment(*weapon).empty(); if(!mResourceSystem->getVFS()->exists(scabbardName)) @@ -239,8 +242,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) { osg::Vec4f glowColor = getEnchantmentColor(*weapon); mScabbard = getWeaponPart(mesh, boneName, isEnchanted, &glowColor); - if (mScabbard) - mScabbard->getNode()->setUpdateCallback(new EmptyCallback); + resetControllers(mScabbard->getNode()); } return; @@ -265,7 +267,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) if (!weaponNode->getNumChildren()) { osg::ref_ptr fallbackNode = mResourceSystem->getSceneManager()->getInstance(mesh, weaponNode); - fallbackNode->setUpdateCallback(new EmptyCallback); + resetControllers(fallbackNode); } if (isEnchanted) diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp index 7a8acd3a8..2146a0260 100644 --- a/apps/openmw/mwrender/actoranimation.hpp +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -59,6 +59,7 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener private: void addHiddenItemLight(const MWWorld::ConstPtr& item, const ESM::Light* esmLight); void removeHiddenItemLight(const MWWorld::ConstPtr& item); + void resetControllers(osg::Node* node); typedef std::map > ItemLightMap; ItemLightMap mItemLights; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4b0eec7b9..c21cab6c9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -79,10 +79,9 @@ namespace void remove() { - for (std::vector >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) + for (osg::Node* node : mToRemove) { // FIXME: a Drawable might have more than one parent - osg::Node* node = *it; if (node->getNumParents()) node->getParent(0)->removeChild(node); } @@ -843,9 +842,9 @@ namespace MWRender if (!mAccumRoot) { - NodeMap::const_iterator found = nodeMap.find("root bone"); + NodeMap::const_iterator found = nodeMap.find("bip01"); if (found == nodeMap.end()) - found = nodeMap.find("bip01"); + found = nodeMap.find("root bone"); if (found != nodeMap.end()) mAccumRoot = found->second; @@ -1436,7 +1435,7 @@ namespace MWRender return sceneMgr->createInstance(found->second); } else - return sceneMgr->createInstance(model); + return sceneMgr->getInstance(model); } void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 153f2ead9..f638a4db7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -457,7 +457,7 @@ public: virtual void showWeapons(bool showWeapon) {} virtual void showCarriedLeft(bool show) {} - virtual void setWeaponGroup(const std::string& group) {} + virtual void setWeaponGroup(const std::string& group, bool relativeDuration) {} virtual void setVampire(bool vampire) {} /// A value < 1 makes the animation translucent, 1.f = fully opaque void setAlpha(float alpha); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index d0fd5bdb4..524272584 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -44,7 +44,7 @@ namespace MWRender virtual osg::Node* getWeaponNode(); virtual Resource::ResourceSystem* getResourceSystem(); virtual void showWeapon(bool show) { showWeapons(show); } - virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } + virtual void setWeaponGroup(const std::string& group, bool relativeDuration) { mWeaponAnimationTime->setGroup(group, relativeDuration); } virtual void addControllers(); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 40365f718..ffff45e25 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -270,10 +270,10 @@ namespace MWRender GlobalMap::~GlobalMap() { - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); - for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) - removeCamera(*it); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); + for (auto& camera : mActiveCameras) + removeCamera(camera); if (mWorkItem) mWorkItem->waitTillDone(); @@ -628,8 +628,8 @@ namespace MWRender void GlobalMap::cleanupCameras() { - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); mCamerasPendingRemoval.clear(); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index a7f9247f7..1650dc92c 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -92,10 +92,10 @@ LocalMap::LocalMap(osg::Group* root) LocalMap::~LocalMap() { - for (CameraVector::iterator it = mActiveCameras.begin(); it != mActiveCameras.end(); ++it) - removeCamera(*it); - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); + for (auto& camera : mActiveCameras) + removeCamera(camera); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); } const osg::Vec2f LocalMap::rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle) @@ -178,7 +178,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object); + camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object | Mask_Static); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -259,16 +259,14 @@ bool needUpdate(std::set >& renderedGrid, std::set cells) { std::set > grid; - for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + for (const MWWorld::CellStore* cell : cells) { - const MWWorld::CellStore* cell = *it; if (cell->isExterior()) grid.insert(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())); } - for (std::set::iterator it = cells.begin(); it != cells.end(); ++it) + for (const MWWorld::CellStore* cell : cells) { - const MWWorld::CellStore* cell = *it; if (cell->isExterior()) { int cellX = cell->getCell()->getGridX(); @@ -341,8 +339,8 @@ void LocalMap::cleanupCameras() if (mCamerasPendingRemoval.empty()) return; - for (CameraVector::iterator it = mCamerasPendingRemoval.begin(); it != mCamerasPendingRemoval.end(); ++it) - removeCamera(*it); + for (auto& camera : mCamerasPendingRemoval) + removeCamera(camera); mCamerasPendingRemoval.clear(); } @@ -380,7 +378,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object); + computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object | Mask_Static); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); diff --git a/apps/openmw/mwrender/navmesh.cpp b/apps/openmw/mwrender/navmesh.cpp index 331f506ab..bfc80914a 100644 --- a/apps/openmw/mwrender/navmesh.cpp +++ b/apps/openmw/mwrender/navmesh.cpp @@ -34,7 +34,7 @@ namespace MWRender void NavMesh::update(const dtNavMesh& navMesh, const std::size_t id, const std::size_t generation, const std::size_t revision, const DetourNavigator::Settings& settings) { - if (!mEnabled || (mId == id && mGeneration >= generation && mRevision >= revision)) + if (!mEnabled || (mGroup && mId == id && mGeneration >= generation && mRevision >= revision)) return; mId = id; @@ -53,7 +53,10 @@ namespace MWRender void NavMesh::reset() { if (mGroup) + { mRootNode->removeChild(mGroup); + mGroup = nullptr; + } } void NavMesh::enable() @@ -65,7 +68,8 @@ namespace MWRender void NavMesh::disable() { - reset(); + if (mGroup) + mRootNode->removeChild(mGroup); mEnabled = false; } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4b36686f1..f1ebc80df 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include @@ -1031,9 +1030,9 @@ void NpcAnimation::enableHeadAnimation(bool enable) mHeadAnimationTime->setEnabled(enable); } -void NpcAnimation::setWeaponGroup(const std::string &group) +void NpcAnimation::setWeaponGroup(const std::string &group, bool relativeDuration) { - mWeaponAnimationTime->setGroup(group); + mWeaponAnimationTime->setGroup(group, relativeDuration); } void NpcAnimation::equipmentChanged() diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1fbdd863c..1ec0dfa59 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -117,7 +117,7 @@ public: /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands virtual void setAccurateAiming(bool enabled); - virtual void setWeaponGroup(const std::string& group); + virtual void setWeaponGroup(const std::string& group, bool relativeDuration); virtual osg::Vec3f runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 659853763..98ebb95d9 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -2,7 +2,6 @@ #define GAME_RENDER_OBJECTS_H #include -#include #include #include diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index ee4120d6f..797794457 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -6,14 +6,12 @@ #include #include -#include #include #include #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/pathfinding.hpp" @@ -78,17 +76,17 @@ void Pathgrid::togglePathgrid() mPathGridRoot->setNodeMask(Mask_Debug); mRootNode->addChild(mPathGridRoot); - for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) + for(const MWWorld::CellStore* cell : mActiveCells) { - enableCellPathgrid(*it); + enableCellPathgrid(cell); } } else { // remove path grid meshes from already loaded cells - for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) + for(const MWWorld::CellStore* cell : mActiveCells) { - disableCellPathgrid(*it); + disableCellPathgrid(cell); } if (mPathGridRoot) diff --git a/apps/openmw/mwrender/pathgrid.hpp b/apps/openmw/mwrender/pathgrid.hpp index 22bfa8e73..77f1a7f33 100644 --- a/apps/openmw/mwrender/pathgrid.hpp +++ b/apps/openmw/mwrender/pathgrid.hpp @@ -4,7 +4,6 @@ #include #include -#include #include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 51a92a280..f54e423f1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,6 +1,5 @@ #include "renderingmanager.hpp" -#include #include #include @@ -221,8 +220,8 @@ namespace MWRender resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows")); // Shadows have problems with fixed-function mode + // FIXME: calling dummy method because terrain needs to know whether lighting is clamped resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); - resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders")); resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::Manager::getString("normal height map pattern", "Shaders")); @@ -244,8 +243,8 @@ namespace MWRender int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; if (Settings::Manager::getBool("object shadows", "Shadows")) - shadowCastingTraversalMask |= Mask_Object; - + shadowCastingTraversalMask |= (Mask_Object|Mask_Static); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); @@ -254,6 +253,9 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; + globalDefines["forcePPL"] = Settings::Manager::getBool("force per pixel lighting", "Shaders") ? "1" : "0"; + globalDefines["clamp"] = Settings::Manager::getBool("clamp lighting", "Shaders") ? "1" : "0"; + // It is unnecessary to stop/start the viewer as no frames are being rendered yet. mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); @@ -284,12 +286,29 @@ namespace MWRender mDistantFog = Settings::Manager::getBool("use distant fog", "Fog"); mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); - mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"), - Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), - Settings::Manager::getBool("auto use terrain specular maps", "Shaders")); + + const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders"); + const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders"); + const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders"); + const bool useTerrainNormalMaps = Settings::Manager::getBool("auto use terrain normal maps", "Shaders"); + const bool useTerrainSpecularMaps = Settings::Manager::getBool("auto use terrain specular maps", "Shaders"); + + mTerrainStorage = new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps); if (mDistantTerrain) - mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); + { + const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain"); + int compMapPower = Settings::Manager::getInt("composite map level", "Terrain"); + compMapPower = std::max(-3, compMapPower); + float compMapLevel = pow(2, compMapPower); + const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); + const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain"); + float maxCompGeometrySize = Settings::Manager::getFloat("max composite geometry size", "Terrain"); + maxCompGeometrySize = std::max(maxCompGeometrySize, 1.f); + mTerrain.reset(new Terrain::QuadTreeWorld( + sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug, + compMapResolution, compMapLevel, lodFactor, vertexLodMod, maxCompGeometrySize)); + } else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile, Mask_Debug)); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 3daf81071..8cede92d0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -13,6 +13,7 @@ #include "rendermode.hpp" #include +#include namespace osg { diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 21bd48d9a..a12487060 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -118,21 +118,22 @@ RippleSimulation::~RippleSimulation() void RippleSimulation::update(float dt) { const MWBase::World* world = MWBase::Environment::get().getWorld(); - for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) + for (Emitter& emitter : mEmitters) { - if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) + MWWorld::ConstPtr& ptr = emitter.mPtr; + if (ptr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) { // fetch a new ptr (to handle cell change etc) // for non-player actors this is done in updateObjectCell - it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); + ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); + osg::Vec3f currentPos (ptr.getRefData().getPosition().asVec3()); - bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr); - if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 ) + bool shouldEmit = (world->isUnderwater(ptr.getCell(), currentPos) && !world->isSubmerged(ptr)) || world->isWalkingOnWater(ptr); + if (shouldEmit && (currentPos - emitter.mLastEmitPosition).length() > 10) { - it->mLastEmitPosition = currentPos; + emitter.mLastEmitPosition = currentPos; currentPos.z() = mParticleNode->getPosition().z(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 194646f2a..3b5f0a4fa 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1813,8 +1813,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? - for (std::vector >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it) - (*it)->setAlpha(weather.mEffectFade); + for (AlphaFader* fader : mParticleFaders) + fader->setAlpha(weather.mEffectFade); } void SkyManager::sunEnable() diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e70f16521..f6472fbde 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index ff2a8bfc7..7894a8393 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -1,7 +1,5 @@ #include "terrainstorage.hpp" -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 1d94b4bf9..f9f9dc74c 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -34,25 +34,26 @@ namespace MWRender Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), Mask_Object = (1<<10), + Mask_Static = (1<<11), // child of Sky - Mask_Sun = (1<<11), - Mask_WeatherParticles = (1<<12), + Mask_Sun = (1<<12), + Mask_WeatherParticles = (1<<13), // top level masks - Mask_Scene = (1<<13), - Mask_GUI = (1<<14), + Mask_Scene = (1<<14), + Mask_GUI = (1<<15), // Set on a ParticleSystem Drawable - Mask_ParticleSystem = (1<<15), + Mask_ParticleSystem = (1<<16), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<16), + Mask_RenderToTexture = (1<<17), - Mask_PreCompile = (1<<17), + Mask_PreCompile = (1<<18), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<18) + Mask_Lighting = (1<<19) }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 376924d82..d047130d4 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -225,7 +225,7 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("RefractionCamera"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Static|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -307,7 +307,7 @@ private: class Reflection : public osg::Camera { public: - Reflection() + Reflection(bool isInterior) { setRenderOrder(osg::Camera::PRE_RENDER); setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -316,9 +316,14 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("ReflectionCamera"); - bool reflectActors = Settings::Manager::getBool("reflect actors", "Water"); - - setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); + int reflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + reflectionDetail = std::min(4, std::max(isInterior ? 2 : 0, reflectionDetail)); + unsigned int extraMask = 0; + if(reflectionDetail >= 1) extraMask |= Mask_Terrain; + if(reflectionDetail >= 2) extraMask |= Mask_Static; + if(reflectionDetail >= 3) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object; + if(reflectionDetail >= 4) extraMask |= Mask_Player|Mask_Actor; + setCullMask(Mask_Scene|Mask_Sky|Mask_Lighting|extraMask); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); @@ -405,6 +410,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem , mEnabled(true) , mToggled(true) , mTop(0) + , mInterior(false) { mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); @@ -457,7 +463,7 @@ void Water::updateWaterMaterial() if (Settings::Manager::getBool("shader", "Water")) { - mReflection = new Reflection; + mReflection = new Reflection(mInterior); mReflection->setWaterLevel(mTop); mReflection->setScene(mSceneRoot); mParent->addChild(mReflection); @@ -630,10 +636,20 @@ void Water::setEnabled(bool enabled) void Water::changeCell(const MWWorld::CellStore* store) { - if (store->getCell()->isExterior()) + bool isInterior = !store->getCell()->isExterior(); + bool wasInterior = mInterior; + if (!isInterior) + { mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + mInterior = false; + } else + { mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); + mInterior = true; + } + if(mInterior != wasInterior) + updateWaterMaterial(); // create a new StateSet to prevent threading issues osg::ref_ptr nodeStateSet (new osg::StateSet); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 32a7977d2..1ad16ca24 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -70,6 +70,7 @@ namespace MWRender bool mEnabled; bool mToggled; float mTop; + bool mInterior; osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 60a9bd29d..3b09706eb 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -43,15 +43,20 @@ float WeaponAnimationTime::getValue(osg::NodeVisitor*) return current - mStartTime; } -void WeaponAnimationTime::setGroup(const std::string &group) +void WeaponAnimationTime::setGroup(const std::string &group, bool relativeTime) { mWeaponGroup = group; - mStartTime = mAnimation->getStartTime(mWeaponGroup); + mRelativeTime = relativeTime; + + if (mRelativeTime) + mStartTime = mAnimation->getStartTime(mWeaponGroup); + else + mStartTime = 0; } void WeaponAnimationTime::updateStartTime() { - setGroup(mWeaponGroup); + setGroup(mWeaponGroup, mRelativeTime); } WeaponAnimation::WeaponAnimation() diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index d50729c62..ece0beaa6 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -17,9 +17,10 @@ namespace MWRender Animation* mAnimation; std::string mWeaponGroup; float mStartTime; + bool mRelativeTime; public: - WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {} - void setGroup(const std::string& group); + WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0), mRelativeTime(false) {} + void setGroup(const std::string& group, bool relativeTime); void updateStartTime(); virtual float getValue(osg::NodeVisitor* nv); diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 9e8ea801a..4a6b7b518 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -19,7 +19,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" -#include #include #include @@ -85,6 +84,7 @@ namespace MWScript { mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); objectList->reset(); + objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); objectList->addObjectAnimPlay(ptr, group, mode); objectList->sendObjectAnimPlay(); diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index f01fed2ce..80d4f7eb8 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -4,7 +4,6 @@ #include "../mwworld/esmstore.hpp" -#include #include #include diff --git a/apps/openmw/mwscript/consoleextensions.cpp b/apps/openmw/mwscript/consoleextensions.cpp index d2e07d3e1..749ec8096 100644 --- a/apps/openmw/mwscript/consoleextensions.cpp +++ b/apps/openmw/mwscript/consoleextensions.cpp @@ -1,11 +1,6 @@ #include "consoleextensions.hpp" -#include -#include - #include -#include -#include namespace MWScript { diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 2a9b5ab97..2e4c300f3 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -2,8 +2,6 @@ #include -#include - #include /* @@ -17,13 +15,13 @@ #include "../mwmp/PlayerList.hpp" #include "../mwmp/ObjectList.hpp" #include "../mwmp/ScriptController.hpp" +#include /* End of tes3mp addition */ #include -#include #include #include @@ -37,14 +35,13 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/actionequip.hpp" +#include "../mwworld/action.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/actorutil.hpp" -#include "interpretercontext.hpp" #include "ref.hpp" namespace MWScript @@ -122,13 +119,13 @@ namespace MWScript if (count == 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); - msgBox = boost::str(boost::format(msgBox) % itemName); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); - msgBox = boost::str(boost::format(msgBox) % count % itemName); + ::Misc::StringUtils::replace(msgBox, "%d", std::to_string(count).c_str(), 2); } + ::Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } /* @@ -254,16 +251,16 @@ namespace MWScript // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; - if(numRemoved > 1) + if (numRemoved > 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - msgBox = boost::str (boost::format(msgBox) % numRemoved % itemName); + ::Misc::StringUtils::replace(msgBox, "%d", std::to_string(numRemoved).c_str(), 2); } else { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); - msgBox = boost::str (boost::format(msgBox) % itemName); } + ::Misc::StringUtils::replace(msgBox, "%s", itemName.c_str(), 2); MWBase::Environment::get().getWindowManager()->messageBox(msgBox, MWGui::ShowInDialogueMode_Only); } /* diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 4b1eabe2d..b24c3b1b5 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -344,6 +344,7 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); + interpreter.installSegment5 (Compiler::Dialogue::opcodeJournalExplicit, new OpJournal); interpreter.installSegment5 (Compiler::Dialogue::opcodeSetJournalIndex, new OpSetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeAddTopic, new OpAddTopic); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index d346ab6e4..d97f2a134 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -458,5 +458,6 @@ op 0x2000307: ToggleBorders, tb op 0x2000308: ToggleNavMesh op 0x2000309: ToggleActorsPaths op 0x200030a: SetNavMeshNumber +op 0x200030b: Journal, explicit -opcodes 0x200030b-0x3ffffff unused +opcodes 0x200030c-0x3ffffff unused diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 22706e6bf..2d7e9ece1 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -1,7 +1,5 @@ #include "globalscripts.hpp" -#include - #include #include #include diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index e96322427..bbf259cf6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -11,7 +11,6 @@ End of tes3mp addition */ -#include #include #include diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index dceecc3bc..8edb44fab 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include @@ -33,6 +31,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwworld/action.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 23fda1770..224190019 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -4,7 +4,6 @@ #include #include "../mwworld/ptr.hpp" -#include "../mwworld/action.hpp" namespace MWSound { diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 4c5573168..699200590 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -13,8 +13,6 @@ #include "../mwworld/esmstore.hpp" -#include - namespace MWScript { void Locals::ensure (const std::string& scriptName) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9cbc4c60a..058b7cf7a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -16,7 +16,6 @@ End of tes3mp addition */ -#include #include #include diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index 479c9d70c..efcef6827 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -2,7 +2,6 @@ #include -#include #include #include diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 784dbd933..5af07e9b1 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -1,4 +1,4 @@ -#include "extensions.hpp" +#include "soundextensions.hpp" /* Start of tes3mp addition @@ -13,7 +13,6 @@ End of tes3mp addition */ -#include #include #include diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 1eaedb19a..61f544533 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -25,7 +25,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -38,7 +37,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "interpretercontext.hpp" #include "ref.hpp" namespace diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8f91ecc9c..e608eddc7 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -21,7 +21,6 @@ #include -#include #include #include @@ -35,7 +34,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwmechanics/actorutil.hpp" diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 146023bc1..b0bfd52e1 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -1,7 +1,5 @@ #include "movieaudiofactory.hpp" -#include - #include #include diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index ccb3f22b5..ba75534b6 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/apps/openmw/mwstate/character.cpp b/apps/openmw/mwstate/character.cpp index a8fffaec6..3c5c4f8b2 100644 --- a/apps/openmw/mwstate/character.cpp +++ b/apps/openmw/mwstate/character.cpp @@ -1,5 +1,6 @@ #include "character.hpp" +#include #include #include diff --git a/apps/openmw/mwstate/charactermanager.cpp b/apps/openmw/mwstate/charactermanager.cpp index d440ba869..856264d03 100644 --- a/apps/openmw/mwstate/charactermanager.cpp +++ b/apps/openmw/mwstate/charactermanager.cpp @@ -1,5 +1,6 @@ #include "charactermanager.hpp" +#include #include #include @@ -58,7 +59,7 @@ MWState::Character* MWState::CharacterManager::createCharacter(const std::string // The character name is user-supplied, so we need to escape the path for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) { - if (isalnum(*it)) // Ignores multibyte characters and non alphanumeric characters + if (std::isalnum(*it)) // Ignores multibyte characters and non alphanumeric characters stream << *it; else stream << "_"; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 946c5eef7..01da76e90 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -32,7 +32,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 4fb7f7ada..4fe48b4b4 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -3,7 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" #include "../mwmechanics/actorutil.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 89e5357f0..65ba19b4a 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -10,9 +10,7 @@ #include #include #include -#include #include -#include #include #include @@ -74,9 +72,9 @@ namespace MWWorld const std::vector& objectIds = cell->getPreloadedIds(); // could possibly build the model list in the worker thread if we manage to make the Store thread safe - for (std::vector::const_iterator it = objectIds.begin(); it != objectIds.end(); ++it) + for (const std::string& id : objectIds) { - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), *it); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id); std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); if (!model.empty()) mMeshes.push_back(model); @@ -104,14 +102,13 @@ namespace MWWorld } } - for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) + for (std::string& mesh: mMeshes) { if (mAbort) break; try { - std::string mesh = *it; mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); if (mPreloadInstances) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 2b032e1d7..4d2583d53 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -11,7 +11,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "class.hpp" #include "esmstore.hpp" #include "containerstore.hpp" #include "cellstore.hpp" diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4516f5878..abee49a6e 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -20,7 +20,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/magiceffects.hpp" namespace MWWorld { @@ -421,7 +420,7 @@ namespace MWWorld return false; } - bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const + bool Class::isPureWaterCreature(const ConstPtr& ptr) const { return canSwim(ptr) && !isBipedal(ptr) @@ -429,7 +428,7 @@ namespace MWWorld && !canWalk(ptr); } - bool Class::isPureFlyingCreature(const Ptr& ptr) const + bool Class::isPureFlyingCreature(const ConstPtr& ptr) const { return canFly(ptr) && !isBipedal(ptr) diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index c776e8541..6112bc5a1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -335,8 +335,8 @@ namespace MWWorld virtual bool canFly(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; virtual bool canWalk(const MWWorld::ConstPtr& ptr) const; - bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; - bool isPureFlyingCreature(const MWWorld::Ptr& ptr) const; + bool isPureWaterCreature(const MWWorld::ConstPtr& ptr) const; + bool isPureFlyingCreature(const MWWorld::ConstPtr& ptr) const; bool isPureLandCreature(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp index 2069a78fc..b529ae9db 100644 --- a/apps/openmw/mwworld/contentloader.hpp +++ b/apps/openmw/mwworld/contentloader.hpp @@ -1,7 +1,6 @@ #ifndef CONTENTLOADER_HPP #define CONTENTLOADER_HPP -#include #include #include diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index acc06b28a..69ec5563b 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -37,10 +37,9 @@ namespace MWWorld const MWWorld::Store& globals = store.get(); - for (MWWorld::Store::iterator iter = globals.begin(); iter!=globals.end(); - ++iter) + for (const ESM::Global& esmGlobal : globals) { - mVariables.insert (std::make_pair (Misc::StringUtils::lowerCase (iter->mId), *iter)); + mVariables.insert (std::make_pair (Misc::StringUtils::lowerCase (esmGlobal.mId), esmGlobal)); } } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index fb06f0a4d..19936a6f9 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -25,9 +25,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwgui/inventorywindow.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" @@ -502,14 +499,13 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& iter->getClass().getEquipmentSlots (*iter); // checking if current item pointed by iter can be equipped - for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); - iter2!=itemsSlots.first.end(); ++iter2) + for (int slot : itemsSlots.first) { // if true then it means slot is equipped already // check if slot may require swapping if current item is more valuable - if (slots_.at (*iter2)!=end()) + if (slots_.at (slot)!=end()) { - Ptr old = *slots_.at (*iter2); + Ptr old = *slots_.at (slot); if (iter.getType() == ContainerStore::Type_Armor) { @@ -530,7 +526,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& else if (iter.getType() == ContainerStore::Type_Clothing) { // if left ring is equipped - if (*iter2 == Slot_LeftRing) + if (slot == Slot_LeftRing) { // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) @@ -570,7 +566,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots& } // if we are here it means item can be equipped or swapped - slots_[*iter2] = iter; + slots_[slot] = iter; break; } } @@ -685,10 +681,9 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Try resisting each effect int i=0; - for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt) + for (const ESM::ENAMstruct& effect : enchantment.mEffects.mList) { - params[i].mMultiplier = MWMechanics::getEffectMultiplier(effectIt->mEffectID, actor, actor); + params[i].mMultiplier = MWMechanics::getEffectMultiplier(effect.mEffectID, actor, actor); ++i; } @@ -702,18 +697,20 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()]; int i=0; - for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) + for (const ESM::ENAMstruct& effect : enchantment.mEffects.mList) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( - effectIt->mEffectID); + effect.mEffectID); // Fully resisted or can't be applied to target? - if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer())) + if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effect.mEffectID, actor, actor, actor == MWMechanics::getPlayer())) + { + i++; continue; + } - float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom; + float magnitude = effect.mMagnMin + (effect.mMagnMax - effect.mMagnMin) * params[i].mRandom; magnitude *= params[i].mMultiplier; if (!existed) @@ -725,7 +722,9 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) } if (magnitude) - mMagicEffects.add (*effectIt, magnitude); + mMagicEffects.add (effect, magnitude); + + i++; } } } @@ -989,17 +988,17 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito continue; int i=0; - for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) + for (const ESM::ENAMstruct& effect : enchantment.mEffects.mList) { + i++; // Don't get spell icon display information for enchantments that weren't actually applied - if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0) + if (mMagicEffects.get(MWMechanics::EffectKey(effect)).getMagnitude() == 0) continue; - const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; - float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; + const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i-1]; + float magnitude = effect.mMagnMin + (effect.mMagnMax - effect.mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; if (magnitude > 0) - visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); + visitor.visit(MWMechanics::EffectKey(effect), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); } } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index eb1440fb9..34812fa2b 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -27,7 +27,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwmechanics/movement.hpp" @@ -135,6 +134,12 @@ namespace MWWorld return ptr; } + MWWorld::ConstPtr Player::getConstPlayer() const + { + MWWorld::ConstPtr ptr (&mPlayer, mCellStore); + return ptr; + } + void Player::setBirthSign (const std::string &sign) { mSign = sign; @@ -167,16 +172,16 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); + ptr.getClass().getMovementSettings(ptr).mPosition[1] = value; } - void Player::setLeftRight (int value) + void Player::setLeftRight (float value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings(ptr).mPosition[0] = static_cast(value); + ptr.getClass().getMovementSettings(ptr).mPosition[0] = value; } - void Player::setForwardBackward (int value) + void Player::setForwardBackward (float value) { MWWorld::Ptr ptr = getPlayer(); @@ -185,7 +190,7 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); + ptr.getClass().getMovementSettings(ptr).mPosition[1] = value; } void Player::setUpDown(int value) diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 7f37de010..96ed20adf 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -27,6 +27,7 @@ namespace Loading namespace MWWorld { class CellStore; + class ConstPtr; /// \brief NPC object representing the player and additional player data class Player @@ -42,7 +43,7 @@ namespace MWWorld CellStore* mMarkedCell; bool mAutoMove; - int mForwardBackward; + float mForwardBackward; bool mTeleported; int mCurrentCrimeId; // the id assigned witnesses @@ -81,6 +82,7 @@ namespace MWWorld void setCell (MWWorld::CellStore *cellStore); MWWorld::Ptr getPlayer(); + MWWorld::ConstPtr getConstPlayer() const; void setBirthSign(const std::string &sign); const std::string &getBirthSign() const; @@ -94,9 +96,9 @@ namespace MWWorld bool getAutoMove() const; void setAutoMove (bool enable); - void setLeftRight (int value); + void setLeftRight (float value); - void setForwardBackward (int value); + void setForwardBackward (float value); void setUpDown(int value); void setRunState(bool run); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ff449acf5..b13db3a3e 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -3,7 +3,6 @@ #include #include -#include #include @@ -34,7 +33,6 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/aipackage.hpp" -#include "../mwrender/effectmanager.hpp" #include "../mwrender/animation.hpp" #include "../mwrender/vismask.hpp" #include "../mwrender/renderingmanager.hpp" @@ -205,12 +203,6 @@ namespace MWWorld osg::ref_ptr projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); - osg::ref_ptr boundVisitor = new osg::ComputeBoundsVisitor(); - projectile->accept(*boundVisitor.get()); - osg::BoundingBox bb = boundVisitor->getBoundingBox(); - - state.mNode->setPivotPoint(bb.center()); - if (state.mIdMagic.size() > 1) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) { @@ -466,24 +458,14 @@ namespace MWWorld osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f newPos = pos + it->mVelocity * duration; - osg::Quat orient; - - if (it->mThrown) - orient.set( - osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) * - osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) * - osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) * - osg::Matrixd::inverse( - osg::Matrixd::lookAt( - osg::Vec3f(0,0,0), - it->mVelocity, - osg::Vec3f(0,0,1)) - ) - ); - else + // rotation does not work well for throwing projectiles - their roll angle will depend on shooting direction. + if (!it->mThrown) + { + osg::Quat orient; orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity); + it->mNode->setAttitude(orient); + } - it->mNode->setAttitude(orient); it->mNode->setPosition(newPos); update(*it, duration); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d6c02d6c0..4ff6842a6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -15,6 +14,7 @@ #include #include #include +#include /* Start of tes3mp addition @@ -40,7 +40,6 @@ #include "../mwphysics/actor.hpp" #include "../mwphysics/object.hpp" #include "../mwphysics/heightfield.hpp" -#include "../mwphysics/convert.hpp" #include "player.hpp" #include "localscripts.hpp" @@ -147,16 +146,16 @@ namespace const auto& transform = object->getCollisionObject()->getWorldTransform(); const btTransform closedDoorTransform( - MWPhysics::toBullet(makeObjectOsgQuat(ptr.getCellRef().getPosition())), + Misc::Convert::toBullet(makeObjectOsgQuat(ptr.getCellRef().getPosition())), transform.getOrigin() ); - const auto start = DetourNavigator::makeOsgVec3f(closedDoorTransform(center + toPoint)); + const auto start = Misc::Convert::makeOsgVec3f(closedDoorTransform(center + toPoint)); const auto startPoint = physics.castRay(start, start - osg::Vec3f(0, 0, 1000), ptr, {}, MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water); const auto connectionStart = startPoint.mHit ? startPoint.mHitPos : start; - const auto end = DetourNavigator::makeOsgVec3f(closedDoorTransform(center - toPoint)); + const auto end = Misc::Convert::makeOsgVec3f(closedDoorTransform(center - toPoint)); const auto endPoint = physics.castRay(end, end - osg::Vec3f(0, 0, 1000), ptr, {}, MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water); const auto connectionEnd = endPoint.mHit ? endPoint.mHitPos : end; @@ -184,12 +183,9 @@ namespace ); } } - else if (const auto actor = physics.getActor(ptr)) + else if (physics.getActor(ptr)) { - const auto halfExtents = ptr.getCell()->isExterior() - ? physics.getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) - : actor->getHalfExtents(); - navigator.addAgent(halfExtents); + navigator.addAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } } @@ -245,9 +241,8 @@ namespace template void InsertVisitor::insert(AddObject&& addObject) { - for (std::vector::iterator it = mToInsert.begin(); it != mToInsert.end(); ++it) + for (MWWorld::Ptr& ptr : mToInsert) { - MWWorld::Ptr ptr = *it; if (mRescale) { if (ptr.getCellRef().getScale()<0.5) @@ -360,15 +355,14 @@ namespace MWWorld */ (*iter)->forEach(visitor); - const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - const auto playerHalfExtents = mPhysics->getHalfExtents(player); + const auto world = MWBase::Environment::get().getWorld(); for (const auto& ptr : visitor.mObjects) { if (const auto object = mPhysics->getObject(ptr)) navigator->removeObject(DetourNavigator::ObjectId(object)); else if (const auto actor = mPhysics->getActor(ptr)) { - navigator->removeAgent(ptr.getCell()->isExterior() ? playerHalfExtents : actor->getHalfExtents()); + navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); mRendering.removeActorPath(ptr); } mPhysics->remove(ptr); @@ -395,6 +389,7 @@ namespace MWWorld if ((*iter)->getCell()->hasWater()) navigator->removeWater(osg::Vec2i(cellX, cellY)); + const auto player = world->getPlayerPtr(); navigator->update(player.getRefData().getPosition().asVec3()); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -899,10 +894,7 @@ namespace MWWorld } else if (const auto actor = mPhysics->getActor(ptr)) { - const auto& halfExtents = ptr.getCell()->isExterior() - ? mPhysics->getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr()) - : actor->getHalfExtents(); - navigator->removeAgent(halfExtents); + navigator->removeAgent(MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(ptr)); } mPhysics->remove(ptr); mRendering.removeObject (ptr); @@ -995,24 +987,22 @@ namespace MWWorld void Scene::preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos, std::vector& exteriorPositions) { std::vector teleportDoors; - for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); - iter!=mActiveCells.end(); ++iter) + for (const MWWorld::CellStore* cellStore : mActiveCells) { - const MWWorld::CellStore* cellStore = *iter; typedef MWWorld::CellRefList::List DoorList; const DoorList &doors = cellStore->getReadOnlyDoors().mList; - for (DoorList::const_iterator doorIt = doors.begin(); doorIt != doors.end(); ++doorIt) + for (auto& door : doors) { - if (!doorIt->mRef.getTeleport()) { + if (!door.mRef.getTeleport()) + { continue; } - teleportDoors.push_back(MWWorld::ConstPtr(&*doorIt, cellStore)); + teleportDoors.push_back(MWWorld::ConstPtr(&door, cellStore)); } } - for (std::vector::iterator it = teleportDoors.begin(); it != teleportDoors.end(); ++it) + for (const MWWorld::ConstPtr& door : teleportDoors) { - const MWWorld::ConstPtr& door = *it; float sqrDistToPlayer = (playerPos - door.getRefData().getPosition().asVec3()).length2(); sqrDistToPlayer = std::min(sqrDistToPlayer, (predictedPos - door.getRefData().getPosition().asVec3()).length2()); @@ -1136,20 +1126,19 @@ namespace MWWorld const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3()); - for (CellStoreCollection::const_iterator iter (mActiveCells.begin()); iter!=mActiveCells.end(); ++iter) + for (MWWorld::CellStore* cellStore : mActiveCells) { - MWWorld::CellStore* cellStore = *iter; cellStore->forEachType(listVisitor); cellStore->forEachType(listVisitor); } - for (std::vector::const_iterator it = listVisitor.mList.begin(); it != listVisitor.mList.end(); ++it) + for (ESM::Transport::Dest& dest : listVisitor.mList) { - if (!it->mCellName.empty()) - preloadCell(MWBase::Environment::get().getWorld()->getInterior(it->mCellName)); + if (!dest.mCellName.empty()) + preloadCell(MWBase::Environment::get().getWorld()->getInterior(dest.mCellName)); else { - osg::Vec3f pos = it->mPos.asVec3(); + osg::Vec3f pos = dest.mPos.asVec3(); int x,y; MWBase::Environment::get().getWorld()->positionToIndex( pos.x(), pos.y(), x, y); preloadCell(MWBase::Environment::get().getWorld()->getExterior(x,y), true); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 631b6e081..79d9174ed 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -420,10 +420,9 @@ namespace MWWorld //========================================================================= Store::~Store() { - for (std::vector::const_iterator it = - mStatic.begin(); it != mStatic.end(); ++it) + for (const ESM::Land* staticLand : mStatic) { - delete *it; + delete staticLand; } } @@ -737,15 +736,16 @@ namespace MWWorld } const ESM::Cell *Store::searchExtByName(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mName, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + const ESM::Cell *cell = nullptr; + for (const ESM::Cell *sharedCell : mSharedExt) + { + if (Misc::StringUtils::ciEqual(sharedCell->mName, id)) + { + if (cell == 0 || + (sharedCell->mData.mX > cell->mData.mX) || + (sharedCell->mData.mX == cell->mData.mX && sharedCell->mData.mY > cell->mData.mY)) { - cell = *it; + cell = sharedCell; } } } @@ -753,15 +753,16 @@ namespace MWWorld } const ESM::Cell *Store::searchExtByRegion(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + const ESM::Cell *cell = nullptr; + for (const ESM::Cell *sharedCell : mSharedExt) + { + if (Misc::StringUtils::ciEqual(sharedCell->mRegion, id)) + { + if (cell == nullptr || + (sharedCell->mData.mX > cell->mData.mX) || + (sharedCell->mData.mX == cell->mData.mX && sharedCell->mData.mY > cell->mData.mY)) { - cell = *it; + cell = sharedCell; } } } @@ -775,9 +776,9 @@ namespace MWWorld { list.reserve(list.size() + mSharedInt.size()); - std::vector::const_iterator it = mSharedInt.begin(); - for (; it != mSharedInt.end(); ++it) { - list.push_back((*it)->mName); + for (const ESM::Cell *sharedCell : mSharedInt) + { + list.push_back(sharedCell->mName); } } ESM::Cell *Store::insert(const ESM::Cell &cell) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5c2195307..aca0e90c5 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -4,7 +4,6 @@ #include #include -#include #include /* @@ -312,10 +311,11 @@ void RegionWeather::setChances(const std::vector& chances) mChances.reserve(chances.size()); } - std::vector::const_iterator it = chances.begin(); - for(size_t i = 0; it != chances.end(); ++it, ++i) + int i = 0; + for(char chance : chances) { - mChances[i] = *it; + mChances[i] = chance; + i++; } // Regional weather no longer supports the current type, select a new weather pattern. @@ -1065,11 +1065,10 @@ inline void WeatherManager::addWeather(const std::string& name, inline void WeatherManager::importRegions() { - Store::iterator it = mStore.get().begin(); - for(; it != mStore.get().end(); ++it) + for(const ESM::Region& region : mStore.get()) { - std::string regionID = Misc::StringUtils::lowerCase(it->mId); - mRegions.insert(std::make_pair(regionID, RegionWeather(*it))); + std::string regionID = Misc::StringUtils::lowerCase(region.mId); + mRegions.insert(std::make_pair(regionID, RegionWeather(region))); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 09ec6e316..b493622a7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -56,7 +56,6 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/levelledlist.hpp" @@ -69,7 +68,6 @@ #include "../mwrender/camera.hpp" #include "../mwrender/vismask.hpp" -#include "../mwscript/interpretercontext.hpp" #include "../mwscript/globalscripts.hpp" #include "../mwclass/door.hpp" @@ -441,7 +439,8 @@ namespace MWWorld if (getPlayerPtr().isInCell()) { mWorldScene->preloadCell(getPlayerPtr().getCell(), true); - mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); + if (getPlayerPtr().getCell()->isExterior()) + mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); } break; default: @@ -1500,6 +1499,9 @@ namespace MWWorld { mPhysics->updatePosition(newPtr); mPhysics->updatePtr(ptr, newPtr); + + if (const auto object = mPhysics->getObject(newPtr)) + updateNavigatorObject(object); } } if (isPlayer) @@ -1531,9 +1533,17 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { + if (mPhysics->getActor(ptr)) + mNavigator->removeAgent(getPathfindingHalfExtents(ptr)); + ptr.getCellRef().setScale(scale); mWorldScene->updateObjectScale(ptr); + + if (mPhysics->getActor(ptr)) + mNavigator->addAgent(getPathfindingHalfExtents(ptr)); + else if (const auto object = mPhysics->getObject(ptr)) + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; } void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust) @@ -1573,7 +1583,12 @@ namespace MWWorld ptr.getRefData().setPosition(pos); if(ptr.getRefData().getBaseNode() != 0) + { mWorldScene->updateObjectRotation(ptr, true); + + if (const auto object = mPhysics->getObject(ptr)) + updateNavigatorObject(object); + } } void World::adjustPosition(const Ptr &ptr, bool force) @@ -1795,19 +1810,20 @@ namespace MWWorld void World::updateNavigator() { - bool updated = false; - mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) { - updated = updateNavigatorObject(object) || updated; + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; }); for (const auto& door : mDoorStates) if (const auto object = mPhysics->getObject(door.first)) - updated = updateNavigatorObject(object) || updated; + mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator; - if (updated) + if (mShouldUpdateNavigator) + { mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3()); + mShouldUpdateNavigator = false; + } } bool World::updateNavigatorObject(const MWPhysics::Object* object) @@ -1863,13 +1879,13 @@ namespace MWWorld /// \todo should use convexSweepTest here std::vector collisions = mPhysics->getCollisions(it->first, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); - for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + for (MWWorld::Ptr& ptr : collisions) { - MWWorld::Ptr ptr = *cit; if (ptr.getClass().isActor()) { // Collided with actor, ask actor to try to avoid door - if(ptr != getPlayerPtr() ) { + if(ptr != getPlayerPtr() ) + { MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence(); if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr); @@ -2701,7 +2717,7 @@ namespace MWWorld { // Remove the old CharacterController MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr()); - mNavigator->removeAgent(mPhysics->getHalfExtents(getPlayerPtr())); + mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr())); mPhysics->remove(getPlayerPtr()); mRendering->removePlayer(getPlayerPtr()); @@ -2736,7 +2752,8 @@ namespace MWWorld applyLoopingParticles(player); - mNavigator->addAgent(mPhysics->getHalfExtents(getPlayerPtr())); + mDefaultHalfExtents = mPhysics->getOriginalHalfExtents(getPlayerPtr()); + mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr())); } World::RestPermitted World::canRest () const @@ -3834,6 +3851,11 @@ namespace MWWorld return mPlayer->getPlayer(); } + MWWorld::ConstPtr World::getPlayerConstPtr() const + { + return mPlayer->getConstPlayer(); + } + void World::updateDialogueGlobals() { MWWorld::Ptr player = getPlayerPtr(); @@ -4016,18 +4038,17 @@ namespace MWWorld const std::string& id, const std::string& sourceName, const bool fromProjectile) { std::map > toApply; - for (std::vector::const_iterator effectIt = effects.mList.begin(); - effectIt != effects.mList.end(); ++effectIt) + for (const ESM::ENAMstruct& effectInfo : effects.mList) { - const ESM::MagicEffect* effect = mStore.get().find(effectIt->mEffectID); + const ESM::MagicEffect* effect = mStore.get().find(effectInfo.mEffectID); - if (effectIt->mRange != rangeType || (effectIt->mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor())) + if (effectInfo.mRange != rangeType || (effectInfo.mArea <= 0 && !ignore.isEmpty() && ignore.getClass().isActor())) continue; // Not right range type, or not area effect and hit an actor - if (fromProjectile && effectIt->mArea <= 0) + if (fromProjectile && effectInfo.mArea <= 0) continue; // Don't play explosion for projectiles with 0-area effects - if (!fromProjectile && effectIt->mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore))) + if (!fromProjectile && effectInfo.mRange == ESM::RT_Touch && (!ignore.isEmpty()) && (!ignore.getClass().isActor() && !ignore.getClass().canBeActivated(ignore))) continue; // Don't play explosion for touch spells on non-activatable objects except when spell is from the projectile enchantment // Spawn the explosion orb effect @@ -4039,14 +4060,14 @@ namespace MWWorld std::string texture = effect->mParticle; - if (effectIt->mArea <= 0) + if (effectInfo.mArea <= 0) { - if (effectIt->mRange == ESM::RT_Target) + if (effectInfo.mRange == ESM::RT_Target) mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, 1.0f); continue; } else - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectIt->mArea * 2)); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, texture, origin, static_cast(effectInfo.mArea * 2)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -4062,40 +4083,40 @@ namespace MWWorld // Get the actors in range of the effect std::vector objects; MWBase::Environment::get().getMechanicsManager()->getObjectsInRange( - origin, feetToGameUnits(static_cast(effectIt->mArea)), objects); + origin, feetToGameUnits(static_cast(effectInfo.mArea)), objects); for (const Ptr& affected : objects) { // Ignore actors without collisions here, otherwise it will be possible to hit actors outside processing range. if (affected.getClass().isActor() && !isActorCollisionEnabled(affected)) continue; - toApply[affected].push_back(*effectIt); + toApply[affected].push_back(effectInfo); } } // Now apply the appropriate effects to each actor in range - for (std::map >::iterator apply = toApply.begin(); apply != toApply.end(); ++apply) + for (auto& applyPair : toApply) { MWWorld::Ptr source = caster; // Vanilla-compatible behaviour of never applying the spell to the caster // (could be changed by mods later) - if (apply->first == caster) + if (applyPair.first == caster) continue; - if (apply->first == ignore) + if (applyPair.first == ignore) continue; if (source.isEmpty()) - source = apply->first; + source = applyPair.first; - MWMechanics::CastSpell cast(source, apply->first); + MWMechanics::CastSpell cast(source, applyPair.first); cast.mHitPosition = origin; cast.mId = id; cast.mSourceName = sourceName; cast.mStack = false; ESM::EffectList effectsToApply; - effectsToApply.mList = apply->second; - cast.inflict(apply->first, caster, effectsToApply, rangeType, false, true); + effectsToApply.mList = applyPair.second; + cast.inflict(applyPair.first, caster, effectsToApply, rangeType, false, true); } } @@ -4179,22 +4200,22 @@ namespace MWWorld void World::preloadEffects(const ESM::EffectList *effectList) { - for (std::vector::const_iterator it = effectList->mList.begin(); it != effectList->mList.end(); ++it) + for (const ESM::ENAMstruct& effectInfo : effectList->mList) { - const ESM::MagicEffect *effect = mStore.get().find(it->mEffectID); + const ESM::MagicEffect *effect = mStore.get().find(effectInfo.mEffectID); - if (MWMechanics::isSummoningEffect(it->mEffectID)) + if (MWMechanics::isSummoningEffect(effectInfo.mEffectID)) { preload(mWorldScene.get(), mStore, "VFX_Summon_Start"); - preload(mWorldScene.get(), mStore, MWMechanics::getSummonedCreature(it->mEffectID)); + preload(mWorldScene.get(), mStore, MWMechanics::getSummonedCreature(effectInfo.mEffectID)); } preload(mWorldScene.get(), mStore, effect->mCasting); preload(mWorldScene.get(), mStore, effect->mHit); - if (it->mArea > 0) + if (effectInfo.mArea > 0) preload(mWorldScene.get(), mStore, effect->mArea); - if (it->mRange == ESM::RT_Target) + if (effectInfo.mRange == ESM::RT_Target) preload(mWorldScene.get(), mStore, effect->mBolt); } } @@ -4220,4 +4241,12 @@ namespace MWWorld mRendering->setNavMeshNumber(value); } + osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const + { + if (actor.isInCell() && actor.getCell()->isExterior()) + return mDefaultHalfExtents; // Using default half extents for better performance + else + return getHalfExtents(actor); + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 89bfe802d..c2480e05f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -111,6 +111,9 @@ namespace MWWorld std::string mUserDataPath; + osg::Vec3f mDefaultHalfExtents; + bool mShouldUpdateNavigator = false; + // not implemented World (const World&); World& operator= (const World&); @@ -248,6 +251,7 @@ namespace MWWorld Player& getPlayer() override; MWWorld::Ptr getPlayerPtr() override; + MWWorld::ConstPtr getPlayerConstPtr() const override; const MWWorld::ESMStore& getStore() const override; @@ -876,6 +880,9 @@ namespace MWWorld void removeActorPath(const MWWorld::ConstPtr& actor) const override; void setNavMeshNumberToRender(const std::size_t value) override; + + /// Return physical half extents of the given actor to be used in pathfinding + osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; }; } diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index 8e76b3154..2bf7bf643 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -27,6 +27,7 @@ namespace osg::Vec3f mEnd; std::deque mPath; std::back_insert_iterator> mOut; + float mStepSize; DetourNavigatorNavigatorTest() : mPlayerPosition(0, 0, 0) @@ -34,6 +35,7 @@ namespace , mStart(-215, 215, 1) , mEnd(215, -215, 1) , mOut(mPath) + , mStepSize(28.333332061767578125f) { mSettings.mEnableWriteRecastMeshToFile = false; mSettings.mEnableWriteNavMeshToFile = false; @@ -61,27 +63,28 @@ namespace mSettings.mMaxSmoothPathSize = 1024; mSettings.mTrianglesPerChunk = 256; mSettings.mMaxPolys = 4096; + mSettings.mMaxTilesNumber = 512; mNavigator.reset(new NavigatorImpl(mSettings)); } }; TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty) { - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque()); } TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception) { mNavigator->addAgent(mAgentHalfExtents); - EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException); + EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut), NavigatorException); } TEST_F(DetourNavigatorNavigatorTest, find_path_for_removed_agent_should_return_empty) { mNavigator->addAgent(mAgentHalfExtents); mNavigator->removeAgent(mAgentHalfExtents); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque()); } @@ -90,7 +93,7 @@ namespace mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents); mNavigator->removeAgent(mAgentHalfExtents); - EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut), NavigatorException); + EXPECT_THROW(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut), NavigatorException); } TEST_F(DetourNavigatorNavigatorTest, update_then_find_path_should_return_path) @@ -110,31 +113,31 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; } @@ -160,31 +163,31 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; @@ -193,16 +196,16 @@ namespace mNavigator->wait(); mPath.clear(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ - osg::Vec3f(-215, 215, 1.87827122211456298828125), + osg::Vec3f(-215, 215, 1.87826788425445556640625), osg::Vec3f(-199.7968292236328125, 191.09100341796875, -3.54876613616943359375), - osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847270965576171875), - osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.40817737579345703125), + osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847843170166015625), + osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.408184051513671875), osg::Vec3f(-154.1872711181640625, 119.36397552490234375, -19.837890625), - osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675952911376953125), - osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6972980499267578125), + osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675991058349609375), + osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6973056793212890625), osg::Vec3f(-108.57772064208984375, 47.636936187744140625, -36.12701416015625), osg::Vec3f(-93.3745269775390625, 23.7279262542724609375, -40.754688262939453125), osg::Vec3f(-78.17134857177734375, -0.18108306825160980224609375, -37.128787994384765625), @@ -210,15 +213,15 @@ namespace osg::Vec3f(-47.764972686767578125, -47.999103546142578125, -30.797946929931640625), osg::Vec3f(-23.852447509765625, -63.196765899658203125, -33.97112274169921875), osg::Vec3f(0.0600789971649646759033203125, -78.39443206787109375, -37.14543914794921875), - osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.7740936279296875), - osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.051288604736328125), - osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.62355804443359375), - osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958160400390625), + osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.774089813232421875), + osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.05129241943359375), + osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.6235561370849609375), + osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958255767822265625), osg::Vec3f(119.6226959228515625, -154.382720947265625, -19.7680912017822265625), - osg::Vec3f(143.53521728515625, -169.58038330078125, -14.3403491973876953125), - osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.91261768341064453125), - osg::Vec3f(191.360260009765625, -199.9757080078125, -3.484879016876220703125), - osg::Vec3f(215, -215, 1.87827455997467041015625), + osg::Vec3f(143.53521728515625, -169.58038330078125, -14.34035205841064453125), + osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.9126186370849609375), + osg::Vec3f(191.360260009765625, -199.9757080078125, -3.4848802089691162109375), + osg::Vec3f(215, -215, 1.87826788425445556640625), })) << mPath; } @@ -244,16 +247,16 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, std::back_inserter(mPath)); EXPECT_EQ(mPath, std::deque({ - osg::Vec3f(-215, 215, 1.87827122211456298828125), + osg::Vec3f(-215, 215, 1.87826788425445556640625), osg::Vec3f(-199.7968292236328125, 191.09100341796875, -3.54876613616943359375), - osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847270965576171875), - osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.40817737579345703125), + osg::Vec3f(-184.5936431884765625, 167.1819915771484375, -8.97847843170166015625), + osg::Vec3f(-169.3904571533203125, 143.2729949951171875, -14.408184051513671875), osg::Vec3f(-154.1872711181640625, 119.36397552490234375, -19.837890625), - osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675952911376953125), - osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6972980499267578125), + osg::Vec3f(-138.9840850830078125, 95.45496368408203125, -25.2675991058349609375), + osg::Vec3f(-123.78090667724609375, 71.54595184326171875, -30.6973056793212890625), osg::Vec3f(-108.57772064208984375, 47.636936187744140625, -36.12701416015625), osg::Vec3f(-93.3745269775390625, 23.7279262542724609375, -40.754688262939453125), osg::Vec3f(-78.17134857177734375, -0.18108306825160980224609375, -37.128787994384765625), @@ -261,15 +264,15 @@ namespace osg::Vec3f(-47.764972686767578125, -47.999103546142578125, -30.797946929931640625), osg::Vec3f(-23.852447509765625, -63.196765899658203125, -33.97112274169921875), osg::Vec3f(0.0600789971649646759033203125, -78.39443206787109375, -37.14543914794921875), - osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.7740936279296875), - osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.051288604736328125), - osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.62355804443359375), - osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958160400390625), + osg::Vec3f(23.97260284423828125, -93.5920867919921875, -40.774089813232421875), + osg::Vec3f(47.885128021240234375, -108.78974151611328125, -36.05129241943359375), + osg::Vec3f(71.7976531982421875, -123.98740386962890625, -30.6235561370849609375), + osg::Vec3f(95.71018218994140625, -139.18505859375, -25.1958255767822265625), osg::Vec3f(119.6226959228515625, -154.382720947265625, -19.7680912017822265625), - osg::Vec3f(143.53521728515625, -169.58038330078125, -14.3403491973876953125), - osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.91261768341064453125), - osg::Vec3f(191.360260009765625, -199.9757080078125, -3.484879016876220703125), - osg::Vec3f(215, -215, 1.87827455997467041015625), + osg::Vec3f(143.53521728515625, -169.58038330078125, -14.34035205841064453125), + osg::Vec3f(167.4477386474609375, -184.778045654296875, -8.9126186370849609375), + osg::Vec3f(191.360260009765625, -199.9757080078125, -3.4848802089691162109375), + osg::Vec3f(215, -215, 1.87826788425445556640625), })) << mPath; compoundShape.updateChildTransform(0, btTransform(btMatrix3x3::getIdentity(), btVector3(1000, 0, 0))); @@ -279,31 +282,31 @@ namespace mNavigator->wait(); mPath.clear(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; } @@ -336,31 +339,31 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.96328866481781005859375), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -0.2422157227993011474609375), - osg::Vec3f(-174.930633544921875, 174.930633544921875, -2.44772052764892578125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -4.653223514556884765625), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -6.858728885650634765625), - osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -9.0642337799072265625), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -11.26973724365234375), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -0.242215454578399658203125), + osg::Vec3f(-174.930633544921875, 174.930633544921875, -2.447719097137451171875), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -4.65322399139404296875), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -6.858726978302001953125), + osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -9.06423282623291015625), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -11.26973628997802734375), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -13.26497173309326171875), - osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -15.24860286712646484375), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -17.2322368621826171875), - osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -19.2158660888671875), + osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -15.24860477447509765625), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -17.23223876953125), + osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -19.215869903564453125), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -20.1338443756103515625), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -18.150211334228515625), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -18.1502132415771484375), osg::Vec3f(45.450958251953125, -45.450958251953125, -16.1665802001953125), - osg::Vec3f(65.48564910888671875, -65.48564910888671875, -14.18294811248779296875), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -12.19931507110595703125), - osg::Vec3f(105.55503082275390625, -105.55503082275390625, -10.08488559722900390625), - osg::Vec3f(125.5897216796875, -125.5897216796875, -7.879383563995361328125), - osg::Vec3f(145.6244049072265625, -145.6244049072265625, -5.673877239227294921875), - osg::Vec3f(165.659088134765625, -165.659088134765625, -3.4683735370635986328125), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -1.2628715038299560546875), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, 0.9426348209381103515625), + osg::Vec3f(65.48564910888671875, -65.48564910888671875, -14.18294620513916015625), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -12.199314117431640625), + osg::Vec3f(105.55503082275390625, -105.55503082275390625, -10.08488368988037109375), + osg::Vec3f(125.5897216796875, -125.5897216796875, -7.87938022613525390625), + osg::Vec3f(145.6244049072265625, -145.6244049072265625, -5.673875331878662109375), + osg::Vec3f(165.659088134765625, -165.659088134765625, -3.468370914459228515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -1.26286637783050537109375), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, 0.942641556262969970703125), osg::Vec3f(215, -215, 1.96328866481781005859375), })) << mPath; } @@ -392,33 +395,33 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.9393787384033203125), osg::Vec3f(-200.8159637451171875, 190.47265625, -0.639537751674652099609375), osg::Vec3f(-186.6319427490234375, 165.9453125, -3.2184507846832275390625), osg::Vec3f(-172.447906494140625, 141.41796875, -5.797363758087158203125), - osg::Vec3f(-158.263885498046875, 116.8906097412109375, -8.37627887725830078125), - osg::Vec3f(-144.079864501953125, 92.3632659912109375, -10.95519161224365234375), - osg::Vec3f(-129.89581298828125, 67.83591461181640625, -13.534107208251953125), + osg::Vec3f(-158.263885498046875, 116.8906097412109375, -8.37627696990966796875), + osg::Vec3f(-144.079864501953125, 92.3632659912109375, -10.9551906585693359375), + osg::Vec3f(-129.89581298828125, 67.83591461181640625, -13.53410625457763671875), osg::Vec3f(-115.7117919921875, 43.308563232421875, -16.1130199432373046875), osg::Vec3f(-101.5277557373046875, 18.7812137603759765625, -18.6919345855712890625), osg::Vec3f(-87.34372711181640625, -5.7461376190185546875, -20.4680538177490234375), osg::Vec3f(-67.02922821044921875, -25.4970550537109375, -20.514247894287109375), - osg::Vec3f(-46.714717864990234375, -45.2479705810546875, -20.5604457855224609375), + osg::Vec3f(-46.714717864990234375, -45.2479705810546875, -20.560443878173828125), osg::Vec3f(-26.40021514892578125, -64.99889373779296875, -20.6066417694091796875), osg::Vec3f(-6.085712432861328125, -84.74980926513671875, -20.652835845947265625), - osg::Vec3f(14.22879505157470703125, -104.50072479248046875, -18.151393890380859375), - osg::Vec3f(39.05098724365234375, -118.16222381591796875, -15.6674861907958984375), - osg::Vec3f(63.87317657470703125, -131.82373046875, -13.18357944488525390625), - osg::Vec3f(88.69537353515625, -145.4852142333984375, -10.69967365264892578125), - osg::Vec3f(113.51757049560546875, -159.146697998046875, -8.21576690673828125), - osg::Vec3f(138.3397674560546875, -172.808197021484375, -5.731858730316162109375), - osg::Vec3f(163.1619720458984375, -186.469696044921875, -3.2479503154754638671875), - osg::Vec3f(187.984161376953125, -200.1311798095703125, -0.764044582843780517578125), - osg::Vec3f(212.8063507080078125, -213.7926788330078125, 1.7198636531829833984375), - osg::Vec3f(215, -215, 1.93937528133392333984375), + osg::Vec3f(14.22879505157470703125, -104.50072479248046875, -18.151397705078125), + osg::Vec3f(39.05098724365234375, -118.16222381591796875, -15.66748714447021484375), + osg::Vec3f(63.87317657470703125, -131.82373046875, -13.18358135223388671875), + osg::Vec3f(88.69537353515625, -145.4852142333984375, -10.699672698974609375), + osg::Vec3f(113.51757049560546875, -159.146697998046875, -8.21576786041259765625), + osg::Vec3f(138.3397674560546875, -172.808197021484375, -5.731859683990478515625), + osg::Vec3f(163.1619720458984375, -186.469696044921875, -3.2479507923126220703125), + osg::Vec3f(187.984161376953125, -200.1311798095703125, -0.764044821262359619140625), + osg::Vec3f(212.8063507080078125, -213.7926788330078125, 1.719865322113037109375), + osg::Vec3f(215, -215, 1.9393787384033203125), })) << mPath; } @@ -445,7 +448,7 @@ namespace mEnd.x() = 0; mEnd.z() = 300; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, 185.33331298828125), @@ -491,7 +494,7 @@ namespace mStart.x() = 0; mEnd.x() = 0; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim | Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), @@ -507,10 +510,10 @@ namespace osg::Vec3f(0, -68.33331298828125, -143.3333587646484375), osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875), osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375), - osg::Vec3f(0, -153.33331298828125, -117.5942230224609375), - osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625), - osg::Vec3f(0, -209.999969482421875, -97.79712677001953125), - osg::Vec3f(0, -215, -94.753631591796875), + osg::Vec3f(0, -153.33331298828125, -117.59423065185546875), + osg::Vec3f(0, -181.6666412353515625, -107.73915863037109375), + osg::Vec3f(0, -209.999969482421875, -97.7971343994140625), + osg::Vec3f(0, -215, -94.75363922119140625), })) << mPath; } @@ -537,7 +540,7 @@ namespace mStart.x() = 0; mEnd.x() = 0; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_swim | Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), @@ -553,10 +556,10 @@ namespace osg::Vec3f(0, -68.33331298828125, -143.3333587646484375), osg::Vec3f(0, -96.66664886474609375, -137.3043670654296875), osg::Vec3f(0, -124.99997711181640625, -127.44930267333984375), - osg::Vec3f(0, -153.33331298828125, -117.5942230224609375), - osg::Vec3f(0, -181.6666412353515625, -107.7391510009765625), - osg::Vec3f(0, -209.999969482421875, -97.79712677001953125), - osg::Vec3f(0, -215, -94.753631591796875), + osg::Vec3f(0, -153.33331298828125, -117.59423065185546875), + osg::Vec3f(0, -181.6666412353515625, -107.73915863037109375), + osg::Vec3f(0, -209.999969482421875, -97.7971343994140625), + osg::Vec3f(0, -215, -94.75363922119140625), })) << mPath; } @@ -583,12 +586,12 @@ namespace mStart.x() = 0; mEnd.x() = 0; - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(0, 215, -94.75363922119140625), - osg::Vec3f(9.8083515167236328125, 188.4185333251953125, -105.19994354248046875), - osg::Vec3f(19.6167049407958984375, 161.837066650390625, -114.25496673583984375), + osg::Vec3f(9.8083515167236328125, 188.4185333251953125, -105.199951171875), + osg::Vec3f(19.6167049407958984375, 161.837066650390625, -114.25495147705078125), osg::Vec3f(29.42505645751953125, 135.255615234375, -123.309967041015625), osg::Vec3f(39.23340606689453125, 108.674163818359375, -132.3649749755859375), osg::Vec3f(49.04175567626953125, 82.09270477294921875, -137.2874755859375), @@ -601,9 +604,9 @@ namespace osg::Vec3f(64.8477935791015625, -104.598602294921875, -137.840911865234375), osg::Vec3f(50.497714996337890625, -129.0291748046875, -131.45831298828125), osg::Vec3f(36.147632598876953125, -153.459747314453125, -121.42321014404296875), - osg::Vec3f(21.7975559234619140625, -177.8903350830078125, -111.38809967041015625), - osg::Vec3f(7.44747829437255859375, -202.3209075927734375, -101.1938323974609375), - osg::Vec3f(0, -215, -94.753631591796875), + osg::Vec3f(21.7975559234619140625, -177.8903350830078125, -111.38811492919921875), + osg::Vec3f(7.44747829437255859375, -202.3209075927734375, -101.19382476806640625), + osg::Vec3f(0, -215, -94.75363922119140625), })) << mPath; } @@ -632,31 +635,31 @@ namespace mNavigator->update(mPlayerPosition); mNavigator->wait(); - mNavigator->findPath(mAgentHalfExtents, mStart, mEnd, Flag_walk, mOut); + mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mOut); EXPECT_EQ(mPath, std::deque({ osg::Vec3f(-215, 215, 1.85963428020477294921875), - osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.5760211944580078125), + osg::Vec3f(-194.9653167724609375, 194.9653167724609375, -6.57602214813232421875), osg::Vec3f(-174.930633544921875, 174.930633544921875, -15.01167774200439453125), - osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473323822021484375), - osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829898834228515625), + osg::Vec3f(-154.8959503173828125, 154.8959503173828125, -23.4473361968994140625), + osg::Vec3f(-134.86126708984375, 134.86126708984375, -31.8829936981201171875), osg::Vec3f(-114.82657623291015625, 114.82657623291015625, -40.3186492919921875), - osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.39907073974609375), + osg::Vec3f(-94.7918853759765625, 94.7918853759765625, -47.3990631103515625), osg::Vec3f(-74.75719451904296875, 74.75719451904296875, -53.7258148193359375), osg::Vec3f(-54.722499847412109375, 54.722499847412109375, -60.052555084228515625), - osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37929534912109375), + osg::Vec3f(-34.68780517578125, 34.68780517578125, -66.37931060791015625), osg::Vec3f(-14.6531162261962890625, 14.6531162261962890625, -72.70604705810546875), osg::Vec3f(5.3815765380859375, -5.3815765380859375, -75.35065460205078125), - osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.96945953369140625), - osg::Vec3f(45.450958251953125, -45.450958251953125, -60.58824920654296875), + osg::Vec3f(25.41626739501953125, -25.41626739501953125, -67.9694671630859375), + osg::Vec3f(45.450958251953125, -45.450958251953125, -60.5882568359375), osg::Vec3f(65.48564910888671875, -65.48564910888671875, -53.20705413818359375), - osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.825855255126953125), + osg::Vec3f(85.5203399658203125, -85.5203399658203125, -45.82585906982421875), osg::Vec3f(105.55503082275390625, -105.55503082275390625, -38.44464874267578125), osg::Vec3f(125.5897216796875, -125.5897216796875, -31.063449859619140625), osg::Vec3f(145.6244049072265625, -145.6244049072265625, -23.6822509765625), osg::Vec3f(165.659088134765625, -165.659088134765625, -16.3010540008544921875), - osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985416412353515625), - osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.53864824771881103515625), + osg::Vec3f(185.6937713623046875, -185.6937713623046875, -8.91985321044921875), + osg::Vec3f(205.7284698486328125, -205.7284698486328125, -1.5386486053466796875), osg::Vec3f(215, -215, 1.877177715301513671875), })) << mPath; } diff --git a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp index 17b17b97c..a3a1816ad 100644 --- a/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp +++ b/apps/openmw_test_suite/detournavigator/navmeshtilescache.cpp @@ -34,6 +34,14 @@ namespace const std::vector mOffMeshConnections {}; unsigned char* const mData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); NavMeshData mNavMeshData {mData, 1}; + + const size_t cRecastMeshKeySize = mRecastMesh.getIndices().size() * sizeof(int) + + mRecastMesh.getVertices().size() * sizeof(float) + + mRecastMesh.getAreaTypes().size() * sizeof(AreaType) + + mRecastMesh.getWater().size() * sizeof(RecastMesh::Water) + + mOffMeshConnections.size() * sizeof(OffMeshConnection); + + const size_t cRecastMeshWithWaterKeySize = cRecastMeshKeySize + sizeof(RecastMesh::Water); }; TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_empty_cache_should_return_empty_value) @@ -56,7 +64,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_return_cached_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -69,7 +77,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_existing_element_should_throw_exception) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); const auto anotherData = reinterpret_cast(dtAlloc(1, DT_ALLOC_PERM)); @@ -85,7 +93,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_should_return_cached_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -129,7 +137,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 117; + const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -149,7 +157,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_used_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -167,7 +175,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_set_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 117; + const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); @@ -199,7 +207,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 117; + const std::size_t navMeshKeySize = cRecastMeshWithWaterKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); @@ -243,7 +251,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_cache_max_size) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = 2 * (navMeshDataSize + 2 * navMeshKeySize); NavMeshTilesCache cache(maxSize); @@ -261,8 +269,8 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_size_of_unused_items) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize1 = 49; - const std::size_t navMeshKeySize2 = 117; + const std::size_t navMeshKeySize1 = cRecastMeshKeySize; + const std::size_t navMeshKeySize2 = cRecastMeshWithWaterKeySize; const std::size_t maxSize = 2 * navMeshDataSize + 2 * navMeshKeySize1 + 2 * navMeshKeySize2; NavMeshTilesCache cache(maxSize); @@ -290,7 +298,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_used_after_set_then_used_by_get_item_should_left_this_item_available) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); @@ -313,7 +321,7 @@ namespace TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_twice_used_item_should_left_this_item_available) { const std::size_t navMeshDataSize = 1; - const std::size_t navMeshKeySize = 49; + const std::size_t navMeshKeySize = cRecastMeshKeySize; const std::size_t maxSize = navMeshDataSize + 2 * navMeshKeySize; NavMeshTilesCache cache(maxSize); diff --git a/apps/openmw_test_suite/detournavigator/operators.hpp b/apps/openmw_test_suite/detournavigator/operators.hpp index 16d8f38f5..a473632ba 100644 --- a/apps/openmw_test_suite/detournavigator/operators.hpp +++ b/apps/openmw_test_suite/detournavigator/operators.hpp @@ -29,7 +29,10 @@ namespace testing for (const auto& v : value) { std::ostringstream stream; - stream << v; + stream << "osg::Vec3f(" + << std::setprecision(std::numeric_limits::max_exponent10) << v.x() << ", " + << std::setprecision(std::numeric_limits::max_exponent10) << v.y() << ", " + << std::setprecision(std::numeric_limits::max_exponent10) << v.z() << ")"; (*this) << stream.str() << ",\n"; } return (*this) << "}"; diff --git a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp index 9b30cadd7..a3606f827 100644 --- a/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp +++ b/apps/openmw_test_suite/detournavigator/recastmeshobject.cpp @@ -69,4 +69,11 @@ namespace object.update(mTransform, AreaType_ground); EXPECT_FALSE(object.update(mTransform, AreaType_ground)); } + + TEST_F(DetourNavigatorRecastMeshObjectTest, update_for_changed_local_scaling_should_return_true) + { + RecastMeshObject object(mBoxShape, mTransform, AreaType_ground); + mBoxShape.setLocalScaling(btVector3(2, 2, 2)); + EXPECT_TRUE(object.update(mTransform, AreaType_ground)); + } } diff --git a/apps/openmw_test_suite/esm/test_fixed_string.cpp b/apps/openmw_test_suite/esm/test_fixed_string.cpp index 89a390ff6..dc88a5f63 100644 --- a/apps/openmw_test_suite/esm/test_fixed_string.cpp +++ b/apps/openmw_test_suite/esm/test_fixed_string.cpp @@ -37,6 +37,42 @@ TEST(EsmFixedString, operator__eq_ne) EXPECT_TRUE(name == ss); } } +TEST(EsmFixedString, operator__eq_ne_const) +{ + { + SCOPED_TRACE("asdc == asdc (const)"); + ESM::NAME name; + name.assign("asdc"); + const char s[4] = { 'a', 's', 'd', 'c' }; + std::string ss(s, 4); + + EXPECT_TRUE(name == s); + EXPECT_TRUE(name == ss.c_str()); + EXPECT_TRUE(name == ss); + } + { + SCOPED_TRACE("asdc == asdcx (const)"); + ESM::NAME name; + name.assign("asdc"); + const char s[5] = { 'a', 's', 'd', 'c', 'x' }; + std::string ss(s, 5); + + EXPECT_TRUE(name != s); + EXPECT_TRUE(name != ss.c_str()); + EXPECT_TRUE(name != ss); + } + { + SCOPED_TRACE("asdc == asdc[NULL] (const)"); + ESM::NAME name; + name.assign("asdc"); + const char s[5] = { 'a', 's', 'd', 'c', '\0' }; + std::string ss(s, 5); + + EXPECT_TRUE(name == s); + EXPECT_TRUE(name == ss.c_str()); + EXPECT_TRUE(name == ss); + } +} TEST(EsmFixedString, empty_strings) { diff --git a/appveyor.yml b/appveyor.yml index 5f5657285..90a9cb1bc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,18 +33,18 @@ configuration: clone_depth: 1 cache: - - C:\projects\openmw\deps\Bullet-2.83.7-msvc2015-win32.7z - - C:\projects\openmw\deps\Bullet-2.83.7-msvc2015-win64.7z - - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2015-win64.7z - - C:\projects\openmw\deps\MyGUI-3.2.3-git-msvc2015-win64.7z - - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2015-win64.7z - - C:\projects\openmw\deps\OSG-3.4.0-scrawl-msvc2015-win64.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-dev-win32.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-dev-win64.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-win32.7z - - C:\projects\openmw\deps\ffmpeg-3.0.1-win64.7z - - C:\projects\openmw\deps\OpenAL-Soft-1.17.2.zip - - C:\projects\openmw\deps\SDL2-2.0.4.zip + - C:\projects\openmw\deps\Bullet-2.86-msvc2015-win32.7z + - C:\projects\openmw\deps\Bullet-2.86-msvc2015-win64.7z + - C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win32.7z + - C:\projects\openmw\deps\MyGUI-3.2.2-msvc2015-win64.7z + - C:\projects\openmw\deps\OSG-3.4.1-scrawl-msvc2015-win32.7z + - C:\projects\openmw\deps\OSG-3.4.1-scrawl-msvc2015-win64.7z + - C:\projects\openmw\deps\ffmpeg-3.2.4-dev-win32.zip + - C:\projects\openmw\deps\ffmpeg-3.2.4-dev-win64.zip + - C:\projects\openmw\deps\ffmpeg-3.2.4-win32.zip + - C:\projects\openmw\deps\ffmpeg-3.2.4-win64.zip + - C:\projects\openmw\deps\OpenAL-Soft-1.19.1.zip + - C:\projects\openmw\deps\SDL2-2.0.7.zip clone_folder: C:\projects\openmw diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e9590815a..70b3373b9 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -88,7 +88,7 @@ add_component_dir (esmterrain ) add_component_dir (misc - constants utf8stream stringops resourcehelpers rng messageformatparser weakcache + gcd constants utf8stream stringops resourcehelpers rng messageformatparser weakcache ) add_component_dir (debug diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6b849ec3a..b3fd1e5ae 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -277,10 +277,18 @@ namespace Compiler { if (!mExplicit.empty()) { - if (mMemberOp && handleMemberAccess (name)) - return true; + if (!mRefOp) + { + if (mMemberOp && handleMemberAccess (name)) + return true; - return Parser::parseName (name, loc, scanner); + return Parser::parseName (name, loc, scanner); + } + else + { + mExplicit.clear(); + getErrorHandler().warning ("Ignoring stray explicit reference", loc); + } } mFirst = false; diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 1b5558a3a..fdb670748 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -175,7 +175,7 @@ namespace Compiler { void registerExtensions (Extensions& extensions) { - extensions.registerInstruction ("journal", "cl", opcodeJournal); + extensions.registerInstruction ("journal", "cl", opcodeJournal, opcodeJournalExplicit); extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3f9d2e790..1cfa70f73 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -506,6 +506,13 @@ namespace Compiler return true; } + if (code==Scanner::S_ref && mState==SetPotentialMemberVarState) + { + getErrorHandler().warning ("Ignoring stray explicit reference", loc); + mState = SetState; + return true; + } + if (code==Scanner::S_ref && mState==PotentialExplicitState) { mState = ExplicitState; diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index 768fc077c..2b485abec 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -1,6 +1,5 @@ #include "locals.hpp" -#include #include #include #include diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index a2d8a9467..4aabe3f78 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -150,6 +150,7 @@ namespace Compiler namespace Dialogue { const int opcodeJournal = 0x2000133; + const int opcodeJournalExplicit = 0x200030b; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; const int opcodeAddTopic = 0x200013a; diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index fe019718a..62265d8a1 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -1,9 +1,5 @@ #include "parser.hpp" -#include -#include -#include - #include "errorhandler.hpp" #include "exception.hpp" #include "scanner.hpp" diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index b56dbb95b..c5ef483f3 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "exception.hpp" diff --git a/components/contentselector/view/combobox.cpp b/components/contentselector/view/combobox.cpp index 18cafc2dc..959eca289 100644 --- a/components/contentselector/view/combobox.cpp +++ b/components/contentselector/view/combobox.cpp @@ -1,7 +1,4 @@ -#include -#include #include -#include #include #include "combobox.hpp" diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 4f95b7fe4..89c389556 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -8,10 +8,7 @@ #include #include -#include -#include #include -#include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : QObject(parent) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index f4efc744b..ee3b6d77a 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -1,12 +1,10 @@ -#include "asyncnavmeshupdater.hpp" +#include "asyncnavmeshupdater.hpp" #include "debug.hpp" #include "makenavmesh.hpp" #include "settings.hpp" #include -#include - namespace { using DetourNavigator::ChangeType; @@ -16,16 +14,6 @@ namespace { return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y()); } - - std::tuple makePriority(const TilePosition& position, const ChangeType changeType, - const TilePosition& playerTile) - { - return std::make_tuple( - changeType, - getManhattanDistance(position, playerTile), - getManhattanDistance(position, TilePosition {0, 0}) - ); - } } namespace DetourNavigator @@ -34,14 +22,18 @@ namespace DetourNavigator { switch (value) { - case UpdateNavMeshStatus::ignore: + case UpdateNavMeshStatus::ignored: return stream << "ignore"; case UpdateNavMeshStatus::removed: return stream << "removed"; - case UpdateNavMeshStatus::add: + case UpdateNavMeshStatus::added: return stream << "add"; case UpdateNavMeshStatus::replaced: return stream << "replaced"; + case UpdateNavMeshStatus::failed: + return stream << "failed"; + case UpdateNavMeshStatus::lost: + return stream << "lost"; } return stream << "unknown"; } @@ -83,13 +75,25 @@ namespace DetourNavigator for (const auto& changedTile : changedTiles) { if (mPushed[agentHalfExtents].insert(changedTile.first).second) - mJobs.push(Job {agentHalfExtents, navMeshCacheItem, changedTile.first, - makePriority(changedTile.first, changedTile.second, playerTile)}); + { + Job job; + + job.mAgentHalfExtents = agentHalfExtents; + job.mNavMeshCacheItem = navMeshCacheItem; + job.mChangedTile = changedTile.first; + job.mTryNumber = 0; + job.mChangeType = changedTile.second; + job.mDistanceToPlayer = getManhattanDistance(changedTile.first, playerTile); + job.mDistanceToOrigin = getManhattanDistance(changedTile.first, TilePosition {0, 0}); + + mJobs.push(std::move(job)); + } } log("posted ", mJobs.size(), " jobs"); - mHasJob.notify_all(); + if (!mJobs.empty()) + mHasJob.notify_all(); } void AsyncNavMeshUpdater::wait() @@ -105,8 +109,9 @@ namespace DetourNavigator { try { - if (const auto job = getNextJob()) - processJob(*job); + if (auto job = getNextJob()) + if (!processJob(*job)) + repost(std::move(*job)); } catch (const std::exception& e) { @@ -116,7 +121,7 @@ namespace DetourNavigator log("stop process jobs"); } - void AsyncNavMeshUpdater::processJob(const Job& job) + bool AsyncNavMeshUpdater::processJob(const Job& job) { log("process job for agent=", job.mAgentHalfExtents); @@ -137,12 +142,16 @@ namespace DetourNavigator using FloatMs = std::chrono::duration; - const auto locked = job.mNavMeshCacheItem.lockConst(); - log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, - " generation=", locked->getGeneration(), - " revision=", locked->getNavMeshRevision(), - " time=", std::chrono::duration_cast(finish - start).count(), "ms", - " total_time=", std::chrono::duration_cast(finish - firstStart).count(), "ms"); + { + const auto locked = job.mNavMeshCacheItem.lockConst(); + log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, + " generation=", locked->getGeneration(), + " revision=", locked->getNavMeshRevision(), + " time=", std::chrono::duration_cast(finish - start).count(), "ms", + " total_time=", std::chrono::duration_cast(finish - firstStart).count(), "ms"); + } + + return isSuccess(status); } boost::optional AsyncNavMeshUpdater::getNextJob() @@ -195,4 +204,19 @@ namespace DetourNavigator *locked = value; return *locked.get(); } + + void AsyncNavMeshUpdater::repost(Job&& job) + { + if (mShouldStop || job.mTryNumber > 2) + return; + + const std::lock_guard lock(mMutex); + + if (mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second) + { + ++job.mTryNumber; + mJobs.push(std::move(job)); + mHasJob.notify_all(); + } + } } diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 39898e48e..98359964d 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -50,11 +50,19 @@ namespace DetourNavigator osg::Vec3f mAgentHalfExtents; SharedNavMeshCacheItem mNavMeshCacheItem; TilePosition mChangedTile; - std::tuple mPriority; + unsigned mTryNumber; + ChangeType mChangeType; + int mDistanceToPlayer; + int mDistanceToOrigin; + + std::tuple getPriority() const + { + return std::make_tuple(mTryNumber, mChangeType, mDistanceToPlayer, mDistanceToOrigin); + } friend inline bool operator <(const Job& lhs, const Job& rhs) { - return lhs.mPriority > rhs.mPriority; + return lhs.getPriority() > rhs.getPriority(); } }; @@ -76,13 +84,15 @@ namespace DetourNavigator void process() throw(); - void processJob(const Job& job); + bool processJob(const Job& job); boost::optional getNextJob(); void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const; std::chrono::steady_clock::time_point setFirstStart(const std::chrono::steady_clock::time_point& value); + + void repost(Job&& job); }; } diff --git a/components/detournavigator/findsmoothpath.cpp b/components/detournavigator/findsmoothpath.cpp index e59b80114..ef0341d72 100644 --- a/components/detournavigator/findsmoothpath.cpp +++ b/components/detournavigator/findsmoothpath.cpp @@ -125,7 +125,7 @@ namespace DetourNavigator { // Stop at Off-Mesh link or when point is further than slop away. if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) || - !inRange(makeOsgVec3f(&steerPath[ns * 3]), startPos, minTargetDist, 1000.0f)) + !inRange(Misc::Convert::makeOsgVec3f(&steerPath[ns * 3]), startPos, minTargetDist, 1000.0f)) break; ns++; } diff --git a/components/detournavigator/findsmoothpath.hpp b/components/detournavigator/findsmoothpath.hpp index c02e3315b..e988dedb7 100644 --- a/components/detournavigator/findsmoothpath.hpp +++ b/components/detournavigator/findsmoothpath.hpp @@ -14,6 +14,8 @@ #include +#include + #include #include @@ -26,16 +28,6 @@ namespace DetourNavigator { struct Settings; - inline osg::Vec3f makeOsgVec3f(const float* values) - { - return osg::Vec3f(values[0], values[1], values[2]); - } - - inline osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } - inline bool inRange(const osg::Vec3f& v1, const osg::Vec3f& v2, const float r, const float h) { const auto d = v2 - v1; @@ -174,7 +166,7 @@ namespace DetourNavigator template OutputIterator makeSmoothPath(const dtNavMesh& navMesh, const dtNavMeshQuery& navMeshQuery, - const dtQueryFilter& filter, const osg::Vec3f& start, const osg::Vec3f& end, + const dtQueryFilter& filter, const osg::Vec3f& start, const osg::Vec3f& end, const float stepSize, std::vector polygonPath, std::size_t maxSmoothPathSize, OutputIterator out) { // Iterate over the path to find smooth path on the detail mesh surface. @@ -184,7 +176,6 @@ namespace DetourNavigator osg::Vec3f targetPos; navMeshQuery.closestPointOnPoly(polygonPath.back(), end.ptr(), targetPos.ptr(), 0); - const float STEP_SIZE = 0.5f; const float SLOP = 0.01f; *out++ = iterPos; @@ -208,10 +199,10 @@ namespace DetourNavigator const osg::Vec3f delta = steerTarget->steerPos - iterPos; float len = delta.length(); // If the steer target is end of path or off-mesh link, do not move past the location. - if ((endOfPath || offMeshConnection) && len < STEP_SIZE) + if ((endOfPath || offMeshConnection) && len < stepSize) len = 1; else - len = STEP_SIZE / len; + len = stepSize / len; const osg::Vec3f moveTgt = iterPos + delta * len; const auto result = moveAlongSurface(navMeshQuery, polygonPath.front(), iterPos, moveTgt, filter, 16); @@ -281,7 +272,7 @@ namespace DetourNavigator } template - OutputIterator findSmoothPath(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, + OutputIterator findSmoothPath(const dtNavMesh& navMesh, const osg::Vec3f& halfExtents, const float stepSize, const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const Settings& settings, OutputIterator out) { @@ -323,7 +314,7 @@ namespace DetourNavigator if (polygonPath.empty() || polygonPath.back() != endRef) return out; - makeSmoothPath(navMesh, navMeshQuery, queryFilter, start, end, std::move(polygonPath), + makeSmoothPath(navMesh, navMeshQuery, queryFilter, start, end, stepSize, std::move(polygonPath), settings.mMaxSmoothPathSize, OutputTransformIterator(out, settings)); return out; diff --git a/components/detournavigator/gettilespositions.hpp b/components/detournavigator/gettilespositions.hpp index 86ce77402..e233795e6 100644 --- a/components/detournavigator/gettilespositions.hpp +++ b/components/detournavigator/gettilespositions.hpp @@ -5,17 +5,14 @@ #include "settingsutils.hpp" #include "tileposition.hpp" +#include + #include #include namespace DetourNavigator { - inline osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } - template void getTilesPositions(const osg::Vec3f& aabbMin, const osg::Vec3f& aabbMax, const Settings& settings, Callback&& callback) @@ -49,7 +46,7 @@ namespace DetourNavigator btVector3 aabbMax; shape.getAabb(transform, aabbMin, aabbMax); - getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward(callback)); + getTilesPositions(Misc::Convert::makeOsgVec3f(aabbMin), Misc::Convert::makeOsgVec3f(aabbMax), settings, std::forward(callback)); } template @@ -66,7 +63,7 @@ namespace DetourNavigator aabbMax.setX(std::max(aabbMin.x(), aabbMax.x())); aabbMax.setY(std::max(aabbMin.y(), aabbMax.y())); - getTilesPositions(makeOsgVec3f(aabbMin), makeOsgVec3f(aabbMax), settings, std::forward(callback)); + getTilesPositions(Misc::Convert::makeOsgVec3f(aabbMin), Misc::Convert::makeOsgVec3f(aabbMax), settings, std::forward(callback)); } } diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 26f86da32..5ac28127e 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -7,10 +7,11 @@ #include "settings.hpp" #include "settingsutils.hpp" #include "sharednavmesh.hpp" -#include "settingsutils.hpp" #include "flags.hpp" #include "navmeshtilescache.hpp" +#include + #include #include #include @@ -45,11 +46,6 @@ namespace using PolyMeshDetailStackPtr = std::unique_ptr; - osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } - struct WaterBounds { osg::Vec3f mMin; @@ -62,8 +58,8 @@ namespace if (water.mCellSize == std::numeric_limits::max()) { const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z()); - const auto min = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-1, -1, 0)))); - const auto max = toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(1, 1, 0)))); + const auto min = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-1, -1, 0)))); + const auto max = toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(1, 1, 0)))); return WaterBounds { osg::Vec3f(-std::numeric_limits::max(), min.y(), -std::numeric_limits::max()), osg::Vec3f(std::numeric_limits::max(), max.y(), std::numeric_limits::max()) @@ -74,8 +70,8 @@ namespace const auto transform = getSwimLevelTransform(settings, water.mTransform, agentHalfExtents.z()); const auto halfCellSize = water.mCellSize / 2.0f; return WaterBounds { - toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), - toNavMeshCoordinates(settings, makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) + toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(-halfCellSize, -halfCellSize, 0)))), + toNavMeshCoordinates(settings, Misc::Convert::makeOsgVec3f(transform(btVector3(halfCellSize, halfCellSize, 0)))) }; } } @@ -445,17 +441,56 @@ namespace return NavMeshData(navMeshData, navMeshDataSize); } - UpdateNavMeshStatus makeUpdateNavMeshStatus(bool removed, bool add) + class UpdateNavMeshStatusBuilder { - if (removed && add) - return UpdateNavMeshStatus::replaced; - else if (removed) - return UpdateNavMeshStatus::removed; - else if (add) - return UpdateNavMeshStatus::add; - else - return UpdateNavMeshStatus::ignore; - } + public: + UpdateNavMeshStatusBuilder() = default; + + UpdateNavMeshStatusBuilder removed(bool value) + { + if (value) + set(UpdateNavMeshStatus::removed); + else + unset(UpdateNavMeshStatus::removed); + return *this; + } + + UpdateNavMeshStatusBuilder added(bool value) + { + if (value) + set(UpdateNavMeshStatus::added); + else + unset(UpdateNavMeshStatus::added); + return *this; + } + + UpdateNavMeshStatusBuilder failed(bool value) + { + if (value) + set(UpdateNavMeshStatus::failed); + else + unset(UpdateNavMeshStatus::failed); + return *this; + } + + UpdateNavMeshStatus getResult() const + { + return mResult; + } + + private: + UpdateNavMeshStatus mResult = UpdateNavMeshStatus::ignored; + + void set(UpdateNavMeshStatus value) + { + mResult = static_cast(static_cast(mResult) | static_cast(value)); + } + + void unset(UpdateNavMeshStatus value) + { + mResult = static_cast(static_cast(mResult) & ~static_cast(value)); + } + }; template unsigned long getMinValuableBitsNumber(const T value) @@ -465,6 +500,49 @@ namespace ++power; return power; } + + dtStatus addTile(dtNavMesh& navMesh, const NavMeshData& navMeshData) + { + const dtTileRef lastRef = 0; + dtTileRef* const result = nullptr; + return navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize, + doNotTransferOwnership, lastRef, result); + } + + dtStatus addTile(dtNavMesh& navMesh, const NavMeshTilesCache::Value& cachedNavMeshData) + { + const dtTileRef lastRef = 0; + dtTileRef* const result = nullptr; + return navMesh.addTile(cachedNavMeshData.get().mValue, cachedNavMeshData.get().mSize, + doNotTransferOwnership, lastRef, result); + } + + template + UpdateNavMeshStatus replaceTile(const SharedNavMeshCacheItem& navMeshCacheItem, + const TilePosition& changedTile, T&& navMeshData) + { + const auto locked = navMeshCacheItem.lock(); + auto& navMesh = locked->getValue(); + const int layer = 0; + const auto tileRef = navMesh.getTileRefAt(changedTile.x(), changedTile.y(), layer); + unsigned char** const data = nullptr; + int* const dataSize = nullptr; + const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, data, dataSize)); + const auto addStatus = addTile(navMesh, navMeshData); + + if (dtStatusSucceed(addStatus)) + { + locked->setUsedTile(changedTile, std::forward(navMeshData)); + return UpdateNavMeshStatusBuilder().added(true).removed(removed).getResult(); + } + else + { + if (removed) + locked->removeUsedTile(changedTile); + log("failed to add tile with status=", WriteDtStatus {addStatus}); + return UpdateNavMeshStatusBuilder().removed(removed).failed((addStatus & DT_OUT_OF_MEMORY) != 0).getResult(); + } + } } namespace DetourNavigator @@ -526,7 +604,7 @@ namespace DetourNavigator const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); if (removed) locked->removeUsedTile(changedTile); - return makeUpdateNavMeshStatus(removed, false); + return UpdateNavMeshStatusBuilder().removed(removed).getResult(); }; if (!recastMesh) @@ -550,7 +628,7 @@ namespace DetourNavigator return removeTile(); } - if (!shouldAddTile(changedTile, playerTile, params.maxTiles)) + if (!shouldAddTile(changedTile, playerTile, std::min(settings.mMaxTilesNumber, params.maxTiles))) { log("ignore add tile: too far from player"); return removeTile(); @@ -587,47 +665,10 @@ namespace DetourNavigator if (!cachedNavMeshData) { log("cache overflow"); - - const auto locked = navMeshCacheItem.lock(); - auto& navMesh = locked->getValue(); - const auto tileRef = navMesh.getTileRefAt(x, y, 0); - const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); - const auto addStatus = navMesh.addTile(navMeshData.mValue.get(), navMeshData.mSize, - doNotTransferOwnership, 0, 0); - - if (dtStatusSucceed(addStatus)) - { - locked->setUsedTile(changedTile, std::move(navMeshData)); - return makeUpdateNavMeshStatus(removed, true); - } - else - { - if (removed) - locked->removeUsedTile(changedTile); - log("failed to add tile with status=", WriteDtStatus {addStatus}); - return makeUpdateNavMeshStatus(removed, false); - } + return replaceTile(navMeshCacheItem, changedTile, std::move(navMeshData)); } } - const auto locked = navMeshCacheItem.lock(); - auto& navMesh = locked->getValue(); - const auto tileRef = navMesh.getTileRefAt(x, y, 0); - const auto removed = dtStatusSucceed(navMesh.removeTile(tileRef, nullptr, nullptr)); - const auto addStatus = navMesh.addTile(cachedNavMeshData.get().mValue, cachedNavMeshData.get().mSize, - doNotTransferOwnership, 0, 0); - - if (dtStatusSucceed(addStatus)) - { - locked->setUsedTile(changedTile, std::move(cachedNavMeshData)); - return makeUpdateNavMeshStatus(removed, true); - } - else - { - if (removed) - locked->removeUsedTile(changedTile); - log("failed to add tile with status=", WriteDtStatus {addStatus}); - return makeUpdateNavMeshStatus(removed, false); - } + return replaceTile(navMeshCacheItem, changedTile, std::move(cachedNavMeshData)); } } diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 55d3e261c..1dfa242ee 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -20,14 +20,21 @@ namespace DetourNavigator class RecastMesh; struct Settings; - enum class UpdateNavMeshStatus + enum class UpdateNavMeshStatus : unsigned { - ignore, - removed, - add, - replaced + ignored = 0, + removed = 1 << 0, + added = 1 << 1, + replaced = removed | added, + failed = 1 << 2, + lost = removed | failed, }; + inline bool isSuccess(UpdateNavMeshStatus value) + { + return (static_cast(value) & static_cast(UpdateNavMeshStatus::failed)) == 0; + } + inline float getLength(const osg::Vec2i& value) { return std::sqrt(float(osg::square(value.x()) + osg::square(value.y()))); @@ -41,7 +48,7 @@ namespace DetourNavigator inline bool shouldAddTile(const TilePosition& changedTile, const TilePosition& playerTile, int maxTiles) { const auto expectedTilesCount = std::ceil(osg::PI * osg::square(getDistance(changedTile, playerTile))); - return expectedTilesCount * 3 <= maxTiles; + return expectedTilesCount <= maxTiles; } NavMeshPtr makeEmptyNavMesh(const Settings& settings); diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index a06d97c56..a146fe0fb 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -160,7 +160,7 @@ namespace DetourNavigator * @throws InvalidArgument if there is no navmesh for given agentHalfExtents. */ template - OutputIterator findPath(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start, + OutputIterator findPath(const osg::Vec3f& agentHalfExtents, const float stepSize, const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, OutputIterator out) const { static_assert( @@ -175,8 +175,8 @@ namespace DetourNavigator return out; const auto settings = getSettings(); return findSmoothPath(navMesh.lock()->getValue(), toNavMeshCoordinates(settings, agentHalfExtents), - toNavMeshCoordinates(settings, start), toNavMeshCoordinates(settings, end), includeFlags, - settings, out); + toNavMeshCoordinates(settings, stepSize), toNavMeshCoordinates(settings, start), + toNavMeshCoordinates(settings, end), includeFlags, settings, out); } /** diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index aa2d62184..217c17e41 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -5,14 +5,9 @@ #include "makenavmesh.hpp" #include "navmeshcacheitem.hpp" #include "settings.hpp" -#include "sharednavmesh.hpp" #include -#include - -#include - namespace { using DetourNavigator::ChangeType; @@ -162,7 +157,7 @@ namespace DetourNavigator if (changedTiles->second.empty()) mChangedTiles.erase(changedTiles); } - const auto maxTiles = navMesh.getParams()->maxTiles; + const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles); mRecastMeshManager.forEachTilePosition([&] (const TilePosition& tile) { if (tilesToPost.count(tile)) diff --git a/components/detournavigator/navmeshtilescache.cpp b/components/detournavigator/navmeshtilescache.cpp index 6bfbfb395..418e69e82 100644 --- a/components/detournavigator/navmeshtilescache.cpp +++ b/components/detournavigator/navmeshtilescache.cpp @@ -1,8 +1,6 @@ #include "navmeshtilescache.hpp" #include "exceptions.hpp" -#include - namespace DetourNavigator { namespace @@ -64,8 +62,8 @@ namespace DetourNavigator return Value(); // TODO: use different function to make key to avoid unnecessary std::string allocation - const auto tile = tileValues->second.Map.find(makeNavMeshKey(recastMesh, offMeshConnections)); - if (tile == tileValues->second.Map.end()) + const auto tile = tileValues->second.mMap.find(makeNavMeshKey(recastMesh, offMeshConnections)); + if (tile == tileValues->second.mMap.end()) return Value(); acquireItemUnsafe(tile->second); @@ -98,7 +96,7 @@ namespace DetourNavigator const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, navMeshKey); // TODO: use std::string_view or some alternative to avoid navMeshKey copy into both mFreeItems and mValues - const auto emplaced = mValues[agentHalfExtents][changedTile].Map.emplace(navMeshKey, iterator); + const auto emplaced = mValues[agentHalfExtents][changedTile].mMap.emplace(navMeshKey, iterator); if (!emplaced.second) { @@ -127,16 +125,16 @@ namespace DetourNavigator if (tileValues == agentValues->second.end()) return; - const auto value = tileValues->second.Map.find(item.mNavMeshKey); - if (value == tileValues->second.Map.end()) + const auto value = tileValues->second.mMap.find(item.mNavMeshKey); + if (value == tileValues->second.mMap.end()) return; mUsedNavMeshDataSize -= getSize(item); mFreeNavMeshDataSize -= getSize(item); mFreeItems.pop_back(); - tileValues->second.Map.erase(value); - if (!tileValues->second.Map.empty()) + tileValues->second.mMap.erase(value); + if (!tileValues->second.mMap.empty()) return; agentValues->second.erase(tileValues); diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 7418c4d3a..e244cda9d 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -108,7 +108,7 @@ namespace DetourNavigator struct TileMap { - std::map Map; + std::map mMap; }; std::mutex mMutex; diff --git a/components/detournavigator/recastmeshbuilder.cpp b/components/detournavigator/recastmeshbuilder.cpp index e325b7eaf..71c4f0405 100644 --- a/components/detournavigator/recastmeshbuilder.cpp +++ b/components/detournavigator/recastmeshbuilder.cpp @@ -6,6 +6,7 @@ #include "exceptions.hpp" #include +#include #include #include @@ -15,14 +16,6 @@ #include -namespace -{ - osg::Vec3f makeOsgVec3f(const btVector3& value) - { - return osg::Vec3f(value.x(), value.y(), value.z()); - } -} - namespace DetourNavigator { using BulletHelpers::makeProcessTriangleCallback; @@ -175,7 +168,7 @@ namespace DetourNavigator void RecastMeshBuilder::addVertex(const btVector3& worldPosition) { - const auto navMeshPosition = toNavMeshCoordinates(mSettings, makeOsgVec3f(worldPosition)); + const auto navMeshPosition = toNavMeshCoordinates(mSettings, Misc::Convert::makeOsgVec3f(worldPosition)); mVertices.push_back(navMeshPosition.x()); mVertices.push_back(navMeshPosition.y()); mVertices.push_back(navMeshPosition.z()); diff --git a/components/detournavigator/recastmeshmanager.cpp b/components/detournavigator/recastmeshmanager.cpp index 1c3a72b59..39afdf56e 100644 --- a/components/detournavigator/recastmeshmanager.cpp +++ b/components/detournavigator/recastmeshmanager.cpp @@ -1,6 +1,5 @@ #include "recastmeshmanager.hpp" -#include #include namespace DetourNavigator diff --git a/components/detournavigator/recastmeshobject.cpp b/components/detournavigator/recastmeshobject.cpp index acaf398c1..aac0b4c3c 100644 --- a/components/detournavigator/recastmeshobject.cpp +++ b/components/detournavigator/recastmeshobject.cpp @@ -5,7 +5,6 @@ #include #include -#include namespace DetourNavigator { @@ -14,6 +13,7 @@ namespace DetourNavigator : mShape(shape) , mTransform(transform) , mAreaType(areaType) + , mLocalScaling(shape.getLocalScaling()) , mChildren(makeChildrenObjects(shape, mAreaType)) { } @@ -31,6 +31,11 @@ namespace DetourNavigator mAreaType = areaType; result = true; } + if (!(mLocalScaling == mShape.get().getLocalScaling())) + { + mLocalScaling = mShape.get().getLocalScaling(); + result = true; + } if (mShape.get().isCompound()) result = updateCompoundObject(static_cast(mShape.get()), mAreaType, mChildren) || result; diff --git a/components/detournavigator/recastmeshobject.hpp b/components/detournavigator/recastmeshobject.hpp index aff468122..f25647ae5 100644 --- a/components/detournavigator/recastmeshobject.hpp +++ b/components/detournavigator/recastmeshobject.hpp @@ -39,6 +39,7 @@ namespace DetourNavigator std::reference_wrapper mShape; btTransform mTransform; AreaType mAreaType; + btVector3 mLocalScaling; std::vector mChildren; static bool updateCompoundObject(const btCompoundShape& shape, const AreaType areaType, diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index f584e48f9..735194dba 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -2,8 +2,6 @@ #include -#include - namespace DetourNavigator { boost::optional makeSettingsFromSettingsManager() @@ -26,6 +24,7 @@ namespace DetourNavigator navigatorSettings.mMaxEdgeLen = ::Settings::Manager::getInt("max edge len", "Navigator"); navigatorSettings.mMaxNavMeshQueryNodes = ::Settings::Manager::getInt("max nav mesh query nodes", "Navigator"); navigatorSettings.mMaxPolys = ::Settings::Manager::getInt("max polygons per tile", "Navigator"); + navigatorSettings.mMaxTilesNumber = ::Settings::Manager::getInt("max tiles number", "Navigator"); navigatorSettings.mMaxVertsPerPoly = ::Settings::Manager::getInt("max verts per poly", "Navigator"); navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator"); navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min size", "Navigator"); diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index 0316092a0..dc0e5dc5a 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -26,6 +26,7 @@ namespace DetourNavigator int mMaxEdgeLen = 0; int mMaxNavMeshQueryNodes = 0; int mMaxPolys = 0; + int mMaxTilesNumber = 0; int mMaxVertsPerPoly = 0; int mRegionMergeSize = 0; int mRegionMinSize = 0; diff --git a/components/detournavigator/settingsutils.hpp b/components/detournavigator/settingsutils.hpp index d96ea53cc..a22205b2a 100644 --- a/components/detournavigator/settingsutils.hpp +++ b/components/detournavigator/settingsutils.hpp @@ -31,6 +31,11 @@ namespace DetourNavigator return agentHalfExtents.x() * settings.mRecastScaleFactor; } + inline float toNavMeshCoordinates(const Settings& settings, float value) + { + return value * settings.mRecastScaleFactor; + } + inline osg::Vec3f toNavMeshCoordinates(const Settings& settings, osg::Vec3f position) { std::swap(position.y(), position.z()); diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index efcd6651e..abbd2c62c 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -7,7 +7,7 @@ namespace ESM { void AIData::blank() { - mHello = mU1 = mFight = mFlee = mAlarm = mU2 = mU3 = mU4 = 0; + mHello = mFight = mFlee = mAlarm = mU1 = mU2 = mU3 = 0; mServices = 0; } diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 5e08806c8..026e65dd8 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -16,10 +16,9 @@ namespace ESM struct AIData { - unsigned char mHello; - char mU1; + unsigned short mHello; // This is the base value for greeting distance [0, 65535] unsigned char mFight, mFlee, mAlarm; // These are probabilities [0, 100] - char mU2, mU3, mU4; // Unknown values + char mU1, mU2, mU3; // Unknown values int mServices; // See the Services enum void blank(); diff --git a/components/esm/aisequence.cpp b/components/esm/aisequence.cpp index 6e41ba302..7891299e3 100644 --- a/components/esm/aisequence.cpp +++ b/components/esm/aisequence.cpp @@ -3,8 +3,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include "defs.hpp" - #include namespace ESM diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d635ba6df..97ce88556 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -35,7 +35,10 @@ public: return false; return std::strncmp(self()->ro_data(), str, size) == 0; } - bool operator==(const char* const str) const + + //this operator will not be used for char[N], only for char* + template::value>::type> + bool operator==(const T* const& str) const { char const* const data = self()->ro_data(); for(size_t i = 0; i < size; ++i) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index a6b947dd3..2f4f4917c 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -27,6 +27,7 @@ ESMReader::ESMReader() , mEncoder(nullptr) , mFileSize(0) { + clearCtx(); } int ESMReader::getFormat() const @@ -50,16 +51,21 @@ void ESMReader::restoreContext(const ESM_Context &rc) void ESMReader::close() { mEsm.reset(); - mCtx.filename.clear(); - mCtx.leftFile = 0; - mCtx.leftRec = 0; - mCtx.leftSub = 0; - mCtx.subCached = false; - mCtx.recName.clear(); - mCtx.subName.clear(); + clearCtx(); mHeader.blank(); } +void ESMReader::clearCtx() +{ + mCtx.filename.clear(); + mCtx.leftFile = 0; + mCtx.leftRec = 0; + mCtx.leftSub = 0; + mCtx.subCached = false; + mCtx.recName.clear(); + mCtx.subName.clear(); +} + void ESMReader::openRaw(Files::IStreamPtr _esm, const std::string& name) { close(); diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6e84fa7d4..72a7b4790 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -1,8 +1,7 @@ #ifndef OPENMW_ESM_READER_H #define OPENMW_ESM_READER_H -#include -#include +#include #include #include #include @@ -269,6 +268,8 @@ public: size_t getFileSize() const { return mFileSize; } private: + void clearCtx(); + Files::IStreamPtr mEsm; ESM_Context mCtx; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index f04439041..17f03c69b 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -22,8 +22,9 @@ namespace ESM { mTransport.mList.clear(); mScale = 1.f; - mHasAI = false; mAiData.blank(); + mAiData.mFight = 90; + mAiData.mFlee = 20; bool hasName = false; bool hasNpdt = false; @@ -68,7 +69,6 @@ namespace ESM { break; case ESM::FourCC<'A','I','D','T'>::value: esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; break; case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','N','A','M'>::value: @@ -128,14 +128,7 @@ namespace ESM { mInventory.save(esm); mSpells.save(esm); - if (mAiData.mHello != 0 - || mAiData.mFight != 0 - || mAiData.mFlee != 0 - || mAiData.mAlarm != 0 - || mAiData.mServices != 0) - { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); mTransport.save(esm); mAiPackage.save(esm); } @@ -159,8 +152,9 @@ namespace ESM { mOriginal.clear(); mInventory.mList.clear(); mSpells.mList.clear(); - mHasAI = false; mAiData.blank(); + mAiData.mFight = 90; + mAiData.mFlee = 20; mAiPackage.mList.clear(); mTransport.mList.clear(); } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index a5147619c..be6a72b8d 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -91,7 +91,6 @@ struct Creature InventoryList mInventory; SpellList mSpells; - bool mHasAI; AIData mAiData; AIPackageList mAiPackage; Transport mTransport; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6e7ba66c5..db6b6d31b 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -19,7 +19,7 @@ namespace ESM mTransport.mList.clear(); mAiPackage.mList.clear(); mAiData.blank(); - mHasAI = false; + mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30; bool hasName = false; bool hasNpdt = false; @@ -96,7 +96,6 @@ namespace ESM break; case ESM::FourCC<'A','I','D','T'>::value: esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI= true; break; case ESM::FourCC<'D','O','D','T'>::value: case ESM::FourCC<'D','N','A','M'>::value: @@ -165,14 +164,7 @@ namespace ESM mInventory.save(esm); mSpells.save(esm); - if (mAiData.mHello != 0 - || mAiData.mFight != 0 - || mAiData.mFlee != 0 - || mAiData.mAlarm != 0 - || mAiData.mServices != 0) - { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); - } + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); mTransport.save(esm); @@ -198,7 +190,7 @@ namespace ESM mInventory.mList.clear(); mSpells.mList.clear(); mAiData.blank(); - mHasAI = false; + mAiData.mHello = mAiData.mFight = mAiData.mFlee = 30; mTransport.mList.clear(); mAiPackage.mList.clear(); mName.clear(); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index fbe1dca1f..746913008 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -122,7 +122,6 @@ struct NPC SpellList mSpells; AIData mAiData; - bool mHasAI; Transport mTransport; diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index 36204c940..61cca7d0d 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -2,8 +2,6 @@ #include -#include - #include "esmreader.hpp" #include "esmwriter.hpp" #include "defs.hpp" @@ -97,7 +95,7 @@ namespace ESM "stealth_speechcraft.dds", "stealth_handtohand.dds", }; - const boost::array Skill::sSkillIds = {{ + const std::array Skill::sSkillIds = {{ Block, Armorer, MediumArmor, diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 5430b422d..099264fab 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -1,10 +1,9 @@ #ifndef OPENMW_ESM_SKIL_H #define OPENMW_ESM_SKIL_H +#include #include -#include - #include "defs.hpp" namespace ESM { @@ -76,7 +75,7 @@ struct Skill static const std::string sSkillNames[Length]; static const std::string sSkillNameIds[Length]; static const std::string sIconNames[Length]; - static const boost::array sSkillIds; + static const std::array sSkillIds; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index dfdc9718d..567d93bbd 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -1,7 +1,6 @@ #include "storage.hpp" #include -#include #include diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index c58130f96..3df6faf62 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include /** * \namespace Files diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 0378e294e..dae83a1f9 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -3,7 +3,6 @@ #include #include -#include #include diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 77e5a0079..29d1c063b 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -1,7 +1,6 @@ #ifndef INTERPRETER_MISCOPCODES_H_INCLUDED #define INTERPRETER_MISCOPCODES_H_INCLUDED -#include #include #include #include diff --git a/apps/openmw/mwphysics/convert.hpp b/components/misc/convert.hpp similarity index 59% rename from apps/openmw/mwphysics/convert.hpp rename to components/misc/convert.hpp index c5075a2c3..c5671f016 100644 --- a/apps/openmw/mwphysics/convert.hpp +++ b/components/misc/convert.hpp @@ -1,14 +1,25 @@ -#ifndef OPENMW_MWPHYSICS_CONVERT_H -#define OPENMW_MWPHYSICS_CONVERT_H +#ifndef OPENMW_COMPONENTS_MISC_CONVERT_H +#define OPENMW_COMPONENTS_MISC_CONVERT_H +#include #include #include - #include #include -namespace MWPhysics +namespace Misc +{ +namespace Convert { + inline osg::Vec3f makeOsgVec3f(const float* values) + { + return osg::Vec3f(values[0], values[1], values[2]); + } + + inline osg::Vec3f makeOsgVec3f(const btVector3& value) + { + return osg::Vec3f(value.x(), value.y(), value.z()); + } inline btVector3 toBullet(const osg::Vec3f& vec) { @@ -29,7 +40,7 @@ namespace MWPhysics { return osg::Quat(quat.x(), quat.y(), quat.z(), quat.w()); } - +} } -#endif +#endif \ No newline at end of file diff --git a/components/misc/gcd.hpp b/components/misc/gcd.hpp new file mode 100644 index 000000000..fd9e972e7 --- /dev/null +++ b/components/misc/gcd.hpp @@ -0,0 +1,13 @@ +#ifndef MISC_GCD_H +#define MISC_GCD_H + +namespace Misc +{ + // TODO: replace to the std::gcd() when the C++17 will be available. + int gcd(int a, int b) + { + return b == 0 ? a : gcd(b, a % b); + } +} + +#endif diff --git a/components/misc/rng.cpp b/components/misc/rng.cpp index e402f0b79..09279e85e 100644 --- a/components/misc/rng.cpp +++ b/components/misc/rng.cpp @@ -8,9 +8,9 @@ namespace Misc std::mt19937 Rng::generator = std::mt19937(); - void Rng::init() + void Rng::init(unsigned int seed) { - generator.seed(static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count())); + generator.seed(seed); } float Rng::rollProbability() @@ -28,4 +28,8 @@ namespace Misc return max > 0 ? std::uniform_int_distribution(0, max - 1)(generator) : 0; } + unsigned int Rng::generateDefaultSeed() + { + return static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + } } diff --git a/components/misc/rng.hpp b/components/misc/rng.hpp index ff56906d9..65a554cf2 100644 --- a/components/misc/rng.hpp +++ b/components/misc/rng.hpp @@ -18,7 +18,7 @@ public: static std::mt19937 generator; /// seed the RNG - static void init(); + static void init(unsigned int seed = generateDefaultSeed()); /// return value in range [0.0f, 1.0f) <- note open upper range. static float rollProbability(); @@ -31,6 +31,9 @@ public: /// return value in range [0, 99] static int roll0to99() { return rollDice(100); } + + /// returns default seed for RNG + static unsigned int generateDefaultSeed(); }; } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 79fa36d1e..f0b488f28 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,7 +1,6 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H -#include #include #include #include @@ -26,36 +25,7 @@ public: /// Don't use tolower(int) because that depends on global locale. static char toLower(char c) { - switch(c) - { - case 'A':return 'a'; - case 'B':return 'b'; - case 'C':return 'c'; - case 'D':return 'd'; - case 'E':return 'e'; - case 'F':return 'f'; - case 'G':return 'g'; - case 'H':return 'h'; - case 'I':return 'i'; - case 'J':return 'j'; - case 'K':return 'k'; - case 'L':return 'l'; - case 'M':return 'm'; - case 'N':return 'n'; - case 'O':return 'o'; - case 'P':return 'p'; - case 'Q':return 'q'; - case 'R':return 'r'; - case 'S':return 's'; - case 'T':return 't'; - case 'U':return 'u'; - case 'V':return 'v'; - case 'W':return 'w'; - case 'X':return 'x'; - case 'Y':return 'y'; - case 'Z':return 'z'; - default:return c; - }; + return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c; } static Utf8Stream::UnicodeChar toLowerUtf8(Utf8Stream::UnicodeChar ch) @@ -241,6 +211,32 @@ public: } return str; } + + /** @brief Replaces the first occurrence of a string in another string. + * + * @param str The string to operate on. + * @param what The string to replace. + * @param with The replacement string. + * @param whatLen The length of the string to replace. + * @param withLen The length of the replacement string. + * + * @return A reference to the string passed in @p str. + */ + static std::string &replace(std::string &str, const char *what, const char *with, + std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) + { + if (whatLen == std::string::npos) + whatLen = strlen(what); + + if (withLen == std::string::npos) + withLen = strlen(with); + + std::size_t found; + if ((found = str.find(what)) != std::string::npos) + str.replace(found, whatLen, with, withLen); + + return str; + } }; } diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index a3f7f76a2..33cc31e2e 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -1,7 +1,5 @@ #include "myguirendermanager.hpp" -#include - #include #include diff --git a/components/myguiplatform/myguitexture.cpp b/components/myguiplatform/myguitexture.cpp index 756893974..598f5a14e 100644 --- a/components/myguiplatform/myguitexture.cpp +++ b/components/myguiplatform/myguitexture.cpp @@ -1,7 +1,6 @@ #include "myguitexture.hpp" #include -#include #include diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 26c3f43f0..6de720b52 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -173,6 +173,18 @@ namespace Nif data.post(nif); } + void NiRollController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiRollController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + void NiGeomMorpherController::read(NIFStream *nif) { Controller::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 7a05b0715..113a7becd 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -136,6 +136,15 @@ public: void post(NIFFile *nif); }; +class NiRollController : public Controller +{ +public: + NiFloatDataPtr data; + + void read(NIFStream *nif); + void post(NIFFile *nif); +}; + class NiGeomMorpherController : public Controller { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 66bbfdb65..0519e0cc6 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -73,6 +73,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiGeomMorpherController", &construct , RC_NiGeomMorpherController )); newFactory.insert(makeEntry("NiKeyframeController", &construct , RC_NiKeyframeController )); newFactory.insert(makeEntry("NiAlphaController", &construct , RC_NiAlphaController )); + newFactory.insert(makeEntry("NiRollController", &construct , RC_NiRollController )); newFactory.insert(makeEntry("NiUVController", &construct , RC_NiUVController )); newFactory.insert(makeEntry("NiPathController", &construct , RC_NiPathController )); newFactory.insert(makeEntry("NiMaterialColorController", &construct , RC_NiMaterialColorController )); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index ee4d508ab..4a044ac47 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiGeomMorpherController, RC_NiKeyframeController, RC_NiAlphaController, + RC_NiRollController, RC_NiUVController, RC_NiPathController, RC_NiMaterialColorController, diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 1a526c63b..72933fc32 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -1,9 +1,6 @@ #include "bulletnifloader.hpp" -#include #include -#include -#include #include #include @@ -15,8 +12,6 @@ #include #include -#include -#include #include namespace diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 83841e0e5..934b3b914 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -309,6 +309,46 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } +RollController::RollController(const Nif::NiFloatData *data) + : mData(data->mKeyList, 1.f) +{ +} + +RollController::RollController() +{ +} + +RollController::RollController(const RollController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mData(copy.mData) + , mStartingTime(0) +{ +} + +void RollController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + traverse(node, nv); + + if (hasInput()) + { + double newTime = nv->getFrameStamp()->getSimulationTime(); + double duration = newTime - mStartingTime; + mStartingTime = newTime; + + float value = mData.interpKey(getInputValue(nv)); + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + + // Rotate around "roll" axis. + // Note: in original game rotation speed is the framerate-dependent in a very tricky way. + // Do not replicate this behaviour until we will really need it. + // For now consider controller's current value as an angular speed in radians per 1/60 seconds. + matrix = osg::Matrix::rotate(value * duration * 60.f, 0, 0, 1) * matrix; + transform->setMatrix(matrix); + } +} + AlphaController::AlphaController(const Nif::NiFloatData *data) : mData(data->mKeyList, 1.f) { diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0e87af44f..36217f31a 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -246,6 +246,22 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; + class RollController : public osg::NodeCallback, public SceneUtil::Controller + { + private: + FloatInterpolator mData; + double mStartingTime; + + public: + RollController(const Nif::NiFloatData *data); + RollController(); + RollController(const RollController& copy, const osg::CopyOp& copyop); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + + META_Object(NifOsg, RollController) + }; + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a2dad247d..a1aa74cab 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -245,10 +244,8 @@ namespace NifOsg osg::ref_ptr callback(new NifOsg::KeyframeController(key->data.getPtr())); callback->setFunction(std::shared_ptr(new NifOsg::ControllerFunction(key))); - if (target.mKeyframeControllers.find(strdata->string) != target.mKeyframeControllers.end()) + if (!target.mKeyframeControllers.emplace(strdata->string, callback).second) Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; - else - target.mKeyframeControllers[strdata->string] = callback; } } @@ -697,6 +694,10 @@ namespace NifOsg { handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); } + else if (ctrl->recType == Nif::RC_NiRollController) + { + handleRollController(static_cast(ctrl.getPtr()), transformNode, animflags); + } else Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } @@ -709,6 +710,13 @@ namespace NifOsg node->addUpdateCallback(callback); } + void handleRollController(const Nif::NiRollController* rollctrl, osg::Node* node, int animflags) + { + osg::ref_ptr callback(new RollController(rollctrl->data.getPtr())); + setupController(rollctrl, callback, animflags); + node->addUpdateCallback(callback); + } + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index c1f6a2819..eeb6777ce 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "userdata.hpp" diff --git a/components/process/processinvoker.cpp b/components/process/processinvoker.cpp index cc842fd61..78cf70038 100644 --- a/components/process/processinvoker.cpp +++ b/components/process/processinvoker.cpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index e3f6b22b4..7dd0964e8 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index e8c082f91..ffe150c74 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -75,10 +75,11 @@ void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double r itr!=_objectCache.end(); ++itr) { - // if ref count is greater the 1 the object has an external reference. - if (itr->second.first->referenceCount()>1) + // If ref count is greater than 1, the object has an external reference. + // If the timestamp is yet to be initialized, it needs to be updated too. + if (itr->second.first->referenceCount()>1 || itr->second.second == 0.0) { - // so update it time stamp. + // So update it. itr->second.second = referenceTime; } } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 328a10cd1..d371a8ce4 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -218,7 +218,6 @@ namespace Resource , mShaderManager(new Shader::ShaderManager) , mForceShaders(false) , mClampLighting(true) - , mForcePerPixelLighting(false) , mAutoUseNormalMaps(false) , mAutoUseSpecularMaps(false) , mInstanceCache(new MultiObjectCache) @@ -260,16 +259,6 @@ namespace Resource return mClampLighting; } - void SceneManager::setForcePerPixelLighting(bool force) - { - mForcePerPixelLighting = force; - } - - bool SceneManager::getForcePerPixelLighting() const - { - return mForcePerPixelLighting; - } - void SceneManager::setAutoUseNormalMaps(bool use) { mAutoUseNormalMaps = use; @@ -729,6 +718,7 @@ namespace Resource void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const { + if (mIncrementalCompileOperation) { OpenThreads::ScopedLock lock(*mIncrementalCompileOperation->getToCompiledMutex()); stats->setAttribute(frameNumber, "Compiling", mIncrementalCompileOperation->getToCompile().size()); @@ -748,8 +738,6 @@ namespace Resource { Shader::ShaderVisitor* shaderVisitor = new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl"); shaderVisitor->setForceShaders(mForceShaders); - shaderVisitor->setClampLighting(mClampLighting); - shaderVisitor->setForcePerPixelLighting(mForcePerPixelLighting); shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps); shaderVisitor->setNormalMapPattern(mNormalMapPattern); shaderVisitor->setNormalHeightMapPattern(mNormalHeightMapPattern); diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 4f1523ece..1c1c60a58 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -56,14 +56,9 @@ namespace Resource void setForceShaders(bool force); bool getForceShaders() const; - /// @see ShaderVisitor::setClampLighting void setClampLighting(bool clamp); bool getClampLighting() const; - /// @see ShaderVisitor::setForcePerPixelLighting - void setForcePerPixelLighting(bool force); - bool getForcePerPixelLighting() const; - /// @see ShaderVisitor::setAutoUseNormalMaps void setAutoUseNormalMaps(bool use); @@ -155,7 +150,6 @@ namespace Resource std::unique_ptr mShaderManager; bool mForceShaders; bool mClampLighting; - bool mForcePerPixelLighting; bool mAutoUseNormalMaps; std::string mNormalMapPattern; std::string mNormalHeightMapPattern; diff --git a/components/sceneutil/agentpath.cpp b/components/sceneutil/agentpath.cpp index aaee4dd1e..abe332f75 100644 --- a/components/sceneutil/agentpath.cpp +++ b/components/sceneutil/agentpath.cpp @@ -2,7 +2,6 @@ #include "detourdebugdraw.hpp" #include -#include #include diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index f143d19a8..5126a3776 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -1,7 +1,6 @@ #include "attach.hpp" #include -#include #include #include diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 99dd7bad3..d1cca5b31 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -1,12 +1,10 @@ #include "clone.hpp" #include -#include #include #include #include -#include #include diff --git a/components/sceneutil/detourdebugdraw.hpp b/components/sceneutil/detourdebugdraw.hpp index bb170e7ba..9b6a28ace 100644 --- a/components/sceneutil/detourdebugdraw.hpp +++ b/components/sceneutil/detourdebugdraw.hpp @@ -1,3 +1,6 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_DETOURDEBUGDRAW_H +#define OPENMW_COMPONENTS_SCENEUTIL_DETOURDEBUGDRAW_H + #include #include @@ -48,3 +51,5 @@ namespace SceneUtil void addColor(osg::Vec4f&& value); }; } + +#endif \ No newline at end of file diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index cb6a12c87..f0fd0ef9f 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -234,6 +234,7 @@ namespace SceneUtil { osg::ref_ptr stateset = new osg::StateSet; std::vector > lights; + lights.reserve(lightList.size()); for (unsigned int i=0; imLightSource->getLight(frameNum)); diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 64c2e6e55..4125ebe7d 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -25,6 +25,8 @@ #include +namespace { + using namespace osgShadow; using namespace SceneUtil; @@ -331,6 +333,8 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) _projectionMatrix = cv->getProjectionMatrix(); } +} // namespace + MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) { diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 621066799..74c8661b9 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -101,6 +101,8 @@ namespace SceneUtil { void apply(osg::Camera&); + using osg::NodeVisitor::apply; + void updateBound(const osg::BoundingBox& bb); void update(const osg::Vec3& v); diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index 25ad03fba..aaff38797 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -36,7 +35,6 @@ #include #include #include -#include #include diff --git a/components/sceneutil/pathgridutil.cpp b/components/sceneutil/pathgridutil.cpp index 1497beb2b..58c5d8ad2 100644 --- a/components/sceneutil/pathgridutil.cpp +++ b/components/sceneutil/pathgridutil.cpp @@ -2,7 +2,6 @@ #include -#include #include namespace SceneUtil diff --git a/components/sceneutil/positionattitudetransform.cpp b/components/sceneutil/positionattitudetransform.cpp index 5f6b57e97..6129c33b4 100644 --- a/components/sceneutil/positionattitudetransform.cpp +++ b/components/sceneutil/positionattitudetransform.cpp @@ -1,7 +1,5 @@ #include "positionattitudetransform.hpp" -#include - namespace SceneUtil { diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index f1acf33e9..0c8198055 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -1,8 +1,5 @@ #include "riggeometry.hpp" -#include -#include - #include #include diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 3c3559a08..876ea920f 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -61,10 +61,7 @@ namespace SceneUtil { // Take transformation for first found node in file const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName()); - if (mMap.find(nodeName) == mMap.end()) - { - mMap[nodeName] = &trans; - } + mMap.emplace(nodeName, &trans); traverse(trans); } diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index 6d2117575..82854cb2f 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 0f4dc2e73..97fc79562 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -1,7 +1,6 @@ #include "shadermanager.hpp" #include -#include #include #include diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 3080e1318..63c676118 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -1,7 +1,5 @@ #include "shadervisitor.hpp" -#include - #include #include #include @@ -39,8 +37,6 @@ namespace Shader ShaderVisitor::ShaderVisitor(ShaderManager& shaderManager, Resource::ImageManager& imageManager, const std::string &defaultVsTemplate, const std::string &defaultFsTemplate) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mForceShaders(false) - , mClampLighting(true) - , mForcePerPixelLighting(false) , mAllowedToModifyStateSets(true) , mAutoUseNormalMaps(false) , mAutoUseSpecularMaps(false) @@ -57,16 +53,6 @@ namespace Shader mForceShaders = force; } - void ShaderVisitor::setClampLighting(bool clamp) - { - mClampLighting = clamp; - } - - void ShaderVisitor::setForcePerPixelLighting(bool force) - { - mForcePerPixelLighting = force; - } - void ShaderVisitor::apply(osg::Node& node) { if (node.getStateSet()) @@ -299,9 +285,6 @@ namespace Shader defineMap[texIt->second + std::string("UV")] = std::to_string(texIt->first); } - defineMap["forcePPL"] = mForcePerPixelLighting ? "1" : "0"; - defineMap["clamp"] = mClampLighting ? "1" : "0"; - defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 8737baf59..ac0ecc699 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -23,13 +23,6 @@ namespace Shader /// Setting force = true will cause all objects to render using shaders, regardless of having a bump map. void setForceShaders(bool force); - /// Set whether lighting is clamped for visual compatibility with the fixed function pipeline. - void setClampLighting(bool clamp); - - /// By default, only bump mapped objects use per-pixel lighting. - /// Setting force = true will cause all shaders to use per-pixel lighting, regardless of having a bump map. - void setForcePerPixelLighting(bool force); - /// Set if we are allowed to modify StateSets encountered in the graph (default true). /// @par If set to false, then instead of modifying, the StateSet will be cloned and this new StateSet will be assigned to the node. /// @par This option is useful when the ShaderVisitor is run on a "live" subgraph that may have already been submitted for rendering. @@ -57,8 +50,6 @@ namespace Shader private: bool mForceShaders; - bool mClampLighting; - bool mForcePerPixelLighting; bool mAllowedToModifyStateSets; bool mAutoUseNormalMaps; diff --git a/components/terrain/cellborder.cpp b/components/terrain/cellborder.cpp index d9e6d52fc..64434727e 100644 --- a/components/terrain/cellborder.cpp +++ b/components/terrain/cellborder.cpp @@ -7,7 +7,7 @@ #include "world.hpp" #include "../esm/loadland.hpp" -namespace MWRender +namespace Terrain { CellBorder::CellBorder(Terrain::World *world, osg::Group *root, int borderMask): diff --git a/components/terrain/cellborder.hpp b/components/terrain/cellborder.hpp index 530ea31ca..908cdea09 100644 --- a/components/terrain/cellborder.hpp +++ b/components/terrain/cellborder.hpp @@ -7,10 +7,7 @@ namespace Terrain { class World; -} -namespace MWRender -{ /** * @Brief Handles the debug cell borders. */ diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index b23b0b76c..80f414541 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -28,6 +28,8 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T , mTextureManager(textureManager) , mCompositeMapRenderer(renderer) , mCompositeMapSize(512) + , mCompositeMapLevel(1.f) + , mMaxCompGeometrySize(1.f) , mCullingActive(true) { @@ -68,11 +70,6 @@ void ChunkManager::releaseGLObjects(osg::State *state) mBufferCache.releaseGLObjects(state); } -void ChunkManager::setCullingActive(bool active) -{ - mCullingActive = active; -} - osg::ref_ptr ChunkManager::createCompositeMapRTT() { osg::ref_ptr texture = new osg::Texture2D; @@ -89,7 +86,7 @@ osg::ref_ptr ChunkManager::createCompositeMapRTT() void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap) { - if (chunkSize > 1.f) + if (chunkSize > mMaxCompGeometrySize) { createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); @@ -164,8 +161,7 @@ std::vector > ChunkManager::createPasses(float chunk float blendmapScale = mStorage->getBlendmapScale(chunkSize); - return ::Terrain::createPasses(useShaders, mSceneManager->getForcePerPixelLighting(), - mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); + return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); } osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, int lod, unsigned int lodFlags) @@ -199,7 +195,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve geometry->addPrimitiveSet(mBufferCache.getIndexBuffer(numVerts, lodFlags)); - bool useCompositeMap = chunkSize >= 1.f; + bool useCompositeMap = chunkSize >= mCompositeMapLevel; unsigned int numUvSets = useCompositeMap ? 1 : 2; for (unsigned int i=0; i ChunkManager::createChunk(float chunkSize, const osg::Ve layer.mDiffuseMap = compositeMap->mTexture; layer.mParallax = false; layer.mSpecular = false; - geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager->getForcePerPixelLighting(), - mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector(1, layer), std::vector >(), 1.f, 1.f)); + geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector(1, layer), std::vector >(), 1.f, 1.f)); } else { diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index d8c4fd084..27201864f 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -32,14 +32,17 @@ namespace Terrain osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); + void setCullingActive(bool active) { mCullingActive = active; } + void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; } + void setCompositeMapLevel(float level) { mCompositeMapLevel = level; } + void setMaxCompositeGeometrySize(float maxCompGeometrySize) { mMaxCompGeometrySize = maxCompGeometrySize; } + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; void clearCache() override; void releaseGLObjects(osg::State* state) override; - void setCullingActive(bool active); - private: osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); @@ -56,6 +59,8 @@ namespace Terrain BufferCache mBufferCache; unsigned int mCompositeMapSize; + float mCompositeMapLevel; + float mMaxCompGeometrySize; bool mCullingActive; }; diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 3dc0aa41c..0ef649197 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -122,6 +122,8 @@ void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo & ++compositeMap.mCompiled; + compositeMap.mDrawables[i] = nullptr; + if (timeLeft) { *timeLeft -= timer.time_s(); @@ -131,6 +133,8 @@ void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo & break; } } + if (compositeMap.mCompiled == compositeMap.mDrawables.size()) + compositeMap.mDrawables = std::vector>(); state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT); diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 83684b5c9..1c989cc2a 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -1,13 +1,10 @@ #include "material.hpp" -#include - #include #include #include #include #include -#include #include #include @@ -156,7 +153,7 @@ namespace namespace Terrain { - std::vector > createPasses(bool useShaders, bool forcePerPixelLighting, bool clampLighting, Shader::ShaderManager* shaderManager, const std::vector &layers, + std::vector > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector &layers, const std::vector > &blendmaps, int blendmapScale, float layerTileSize) { std::vector > passes; @@ -214,8 +211,6 @@ namespace Terrain } Shader::ShaderManager::DefineMap defineMap; - defineMap["forcePPL"] = forcePerPixelLighting ? "1" : "0"; - defineMap["clamp"] = clampLighting ? "1" : "0"; defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; defineMap["blendMap"] = !firstLayer ? "1" : "0"; defineMap["specularMap"] = it->mSpecular ? "1" : "0"; @@ -226,7 +221,7 @@ namespace Terrain if (!vertexShader || !fragmentShader) { // Try again without shader. Error already logged by above - return createPasses(false, forcePerPixelLighting, clampLighting, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); + return createPasses(false, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index 25aa69540..5f78af6a0 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -26,7 +26,7 @@ namespace Terrain bool mSpecular; }; - std::vector > createPasses(bool useShaders, bool forcePerPixelLighting, bool clampLighting, Shader::ShaderManager* shaderManager, + std::vector > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector& layers, const std::vector >& blendmaps, int blendmapScale, float layerTileSize); diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 4b4df4365..f8237306e 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -71,16 +71,6 @@ QuadTreeNode::~QuadTreeNode() { } -QuadTreeNode* QuadTreeNode::getParent() -{ - return mParent; -} - -QuadTreeNode *QuadTreeNode::getChild(unsigned int i) -{ - return static_cast(Group::getChild(i)); -} - QuadTreeNode *QuadTreeNode::getNeighbour(Direction dir) { return mNeighbours[dir]; diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 30e998119..618429c5c 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -35,10 +35,19 @@ namespace Terrain QuadTreeNode(QuadTreeNode* parent, ChildDirection dir, float size, const osg::Vec2f& center); virtual ~QuadTreeNode(); - QuadTreeNode* getParent(); - - QuadTreeNode* getChild(unsigned int i); - using osg::Group::getNumChildren; + inline QuadTreeNode* getParent() { return mParent; } + inline QuadTreeNode* getChild(unsigned int i) { return static_cast(Group::getChild(i)); } + inline unsigned int getNumChildren() const { return _children.size(); } + + // osg::Group::addChild() does a lot of unrelated stuff, but we just really want to add a child node. + void addChildNode(QuadTreeNode* child) + { + // QuadTree node should not contain more than 4 child nodes. + // Reserve enough space if this node is supposed to have child nodes. + _children.reserve(4); + _children.push_back(child); + child->addParent(this); + }; /// Returns our direction relative to the parent node, or Root if we are the root node. ChildDirection getDirection() { return mDirection; } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 6ec89721a..8d54f62ce 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -75,8 +75,9 @@ namespace Terrain class DefaultLodCallback : public LodCallback { public: - DefaultLodCallback(float minSize) - : mMinSize(minSize) + DefaultLodCallback(float factor, float minSize) + : mFactor(factor) + , mMinSize(minSize) { } @@ -84,12 +85,13 @@ public: { float dist = distanceToBox(node->getBoundingBox(), eyePoint); int nativeLodLevel = Log2(static_cast(node->getSize()/mMinSize)); - int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize))); + int lodLevel = Log2(static_cast(dist/(Constants::CellSizeInUnits*mMinSize*mFactor))); return nativeLodLevel <= lodLevel; } private: + float mFactor; float mMinSize; }; @@ -123,8 +125,9 @@ private: class QuadTreeBuilder { public: - QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float minSize) + QuadTreeBuilder(Terrain::Storage* storage, ViewDataMap* viewDataMap, float lodFactor, float minSize) : mStorage(storage) + , mLodFactor(lodFactor) , mMinX(0.f), mMaxX(0.f), mMinY(0.f), mMaxY(0.f) , mMinSize(minSize) , mViewDataMap(viewDataMap) @@ -146,7 +149,7 @@ public: mRootNode = new RootNode(size, osg::Vec2f(centerX, centerY)); mRootNode->setViewDataMap(mViewDataMap); - mRootNode->setLodCallback(new DefaultLodCallback(mMinSize)); + mRootNode->setLodCallback(new DefaultLodCallback(mLodFactor, mMinSize)); addChildren(mRootNode); mRootNode->initNeighbours(); @@ -158,30 +161,37 @@ public: osg::BoundingBox boundingBox; for (unsigned int i=0; i<4; ++i) { - QuadTreeNode* child = addChild(parent, static_cast(i), halfSize); + osg::ref_ptr child = addChild(parent, static_cast(i), halfSize); if (child) + { boundingBox.expandBy(child->getBoundingBox()); + parent->addChildNode(child); + } } - parent->setBoundingBox(boundingBox); + if (!boundingBox.valid()) + parent->removeChildren(0, 4); + else + parent->setBoundingBox(boundingBox); } - QuadTreeNode* addChild(QuadTreeNode* parent, ChildDirection direction, float size) + osg::ref_ptr addChild(QuadTreeNode* parent, ChildDirection direction, float size) { + float halfSize = size/2.f; osg::Vec2f center; switch (direction) { case SW: - center = parent->getCenter() + osg::Vec2f(-size/2.f,-size/2.f); + center = parent->getCenter() + osg::Vec2f(-halfSize,-halfSize); break; case SE: - center = parent->getCenter() + osg::Vec2f(size/2.f, -size/2.f); + center = parent->getCenter() + osg::Vec2f(halfSize, -halfSize); break; case NW: - center = parent->getCenter() + osg::Vec2f(-size/2.f, size/2.f); + center = parent->getCenter() + osg::Vec2f(-halfSize, halfSize); break; case NE: - center = parent->getCenter() + osg::Vec2f(size/2.f, size/2.f); + center = parent->getCenter() + osg::Vec2f(halfSize, halfSize); break; default: break; @@ -190,7 +200,6 @@ public: osg::ref_ptr node = new QuadTreeNode(parent, direction, size, center); node->setLodCallback(parent->getLodCallback()); node->setViewDataMap(mViewDataMap); - parent->addChild(node); if (node->getSize() > mMinSize) { @@ -203,8 +212,8 @@ public: mStorage->getMinMaxHeights(size, center, minZ, maxZ); float cellWorldSize = mStorage->getCellWorldSize(); - osg::BoundingBox boundingBox(osg::Vec3f((center.x()-size)*cellWorldSize, (center.y()-size)*cellWorldSize, minZ), - osg::Vec3f((center.x()+size)*cellWorldSize, (center.y()+size)*cellWorldSize, maxZ)); + osg::BoundingBox boundingBox(osg::Vec3f((center.x()-halfSize)*cellWorldSize, (center.y()-halfSize)*cellWorldSize, minZ), + osg::Vec3f((center.x()+halfSize)*cellWorldSize, (center.y()+halfSize)*cellWorldSize, maxZ)); node->setBoundingBox(boundingBox); return node; @@ -218,6 +227,7 @@ public: private: Terrain::Storage* mStorage; + float mLodFactor; float mMinX, mMaxX, mMinY, mMaxY; float mMinSize; ViewDataMap* mViewDataMap; @@ -225,13 +235,19 @@ private: osg::ref_ptr mRootNode; }; -QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask) +QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resource::ResourceSystem *resourceSystem, Storage *storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float compMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize) : World(parent, compileRoot, resourceSystem, storage, nodeMask, preCompileMask, borderMask) , mViewDataMap(new ViewDataMap) , mQuadTreeBuilt(false) + , mLodFactor(lodFactor) + , mVertexLodMod(vertexLodMod) { // No need for culling on the Drawable / Transform level as the quad tree performs the culling already. mChunkManager->setCullingActive(false); + + mChunkManager->setCompositeMapSize(compMapResolution); + mChunkManager->setCompositeMapLevel(compMapLevel); + mChunkManager->setMaxCompositeGeometrySize(maxCompGeometrySize); } QuadTreeWorld::~QuadTreeWorld() @@ -281,7 +297,30 @@ void traverseToCell(QuadTreeNode* node, ViewData* vd, int cellX, int cellY) } } -unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) +/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the data set. +unsigned int getVertexLod(QuadTreeNode* node, int vertexLodMod) +{ + int lod = Log2(int(node->getSize())); + if (vertexLodMod > 0) + { + lod = std::max(0, lod-vertexLodMod); + } + else if (vertexLodMod < 0) + { + float size = node->getSize(); + // Stop to simplify at this level since with size = 1 the node already covers the whole cell and has getCellVertices() vertices. + while (size < 1) + { + size *= 2; + vertexLodMod = std::min(0, vertexLodMod+1); + } + lod += std::abs(vertexLodMod); + } + return lod; +} + +/// get the flags to use for stitching in the index buffer so that chunks of different LOD connect seamlessly +unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, ViewData* vd) { unsigned int lodFlags = 0; for (unsigned int i=0; i<4; ++i) @@ -296,7 +335,7 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) neighbour = neighbour->getParent(); int lod = 0; if (neighbour) - lod = Log2(int(neighbour->getSize())); + lod = getVertexLod(neighbour, vertexLodMod); if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are - lod = 0; // neighbours with more detail will do the stitching themselves @@ -309,13 +348,17 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, ViewData* vd) return lodFlags; } -void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunkManager) +void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, ChunkManager* chunkManager) { + if (!vd->hasChanged() && entry.mRenderingNode) + return; + + int ourLod = getVertexLod(entry.mNode, vertexLodMod); + if (vd->hasChanged()) { // have to recompute the lodFlags in case a neighbour has changed LOD. - int ourLod = Log2(int(entry.mNode->getSize())); - unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vd); + unsigned int lodFlags = getLodFlags(entry.mNode, ourLod, vertexLodMod, vd); if (lodFlags != entry.mLodFlags) { entry.mRenderingNode = nullptr; @@ -324,10 +367,7 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, ChunkManager* chunk } if (!entry.mRenderingNode) - { - int ourLod = Log2(int(entry.mNode->getSize())); entry.mRenderingNode = chunkManager->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags); - } } void QuadTreeWorld::accept(osg::NodeVisitor &nv) @@ -372,7 +412,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); if (entry.mVisible) { @@ -398,7 +438,7 @@ void QuadTreeWorld::ensureQuadTreeBuilt() return; const float minSize = 1/8.f; - QuadTreeBuilder builder(mStorage, mViewDataMap.get(), minSize); + QuadTreeBuilder builder(mStorage, mViewDataMap.get(), mLodFactor, minSize); builder.build(); mRootNode = builder.getRootNode(); @@ -429,7 +469,7 @@ void QuadTreeWorld::cacheCell(View *view, int x, int y) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); } } @@ -448,7 +488,7 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mChunkManager.get()); + loadRenderingNode(entry, vd, mVertexLodMod, mChunkManager.get()); } } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index c166a9cb1..f724c44b1 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -19,7 +19,8 @@ namespace Terrain class QuadTreeWorld : public Terrain::World { public: - QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask=~0, int borderMask=0); + QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, int nodeMask, int preCompileMask, int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize); + ~QuadTreeWorld(); void accept(osg::NodeVisitor& nv); @@ -44,6 +45,8 @@ namespace Terrain OpenThreads::Mutex mQuadTreeMutex; bool mQuadTreeBuilt; + float mLodFactor; + int mVertexLodMod; }; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index dbc1429da..1888a02b3 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -84,7 +84,7 @@ void TerrainGrid::loadCell(int x, int y) void TerrainGrid::unloadCell(int x, int y) { - MWRender::CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x,y)); + CellBorder::CellGrid::iterator it = mGrid.find(std::make_pair(x,y)); if (it == mGrid.end()) return; diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index 87e3b432c..eb30fb97d 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -33,7 +33,7 @@ namespace Terrain // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks unsigned int mNumSplits; - MWRender::CellBorder::CellGrid mGrid; + CellBorder::CellGrid mGrid; }; } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index cc81dbef8..6a8322bb5 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -47,7 +47,7 @@ World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSyst mTextureManager.reset(new TextureManager(mResourceSystem->getSceneManager())); mChunkManager.reset(new ChunkManager(mStorage, mResourceSystem->getSceneManager(), mTextureManager.get(), mCompositeMapRenderer)); - mCellBorder.reset(new MWRender::CellBorder(this,mTerrainRoot.get(),borderMask)); + mCellBorder.reset(new CellBorder(this,mTerrainRoot.get(),borderMask)); mResourceSystem->addResourceManager(mChunkManager.get()); mResourceSystem->addResourceManager(mTextureManager.get()); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index da1004783..4fb724ebb 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -116,7 +116,7 @@ namespace Terrain std::unique_ptr mTextureManager; std::unique_ptr mChunkManager; - std::unique_ptr mCellBorder; + std::unique_ptr mCellBorder; bool mBorderVisible; diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index d4ab00381..bcb174b7b 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 4f3994bac..c19882381 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -1,6 +1,5 @@ #include "manager.hpp" -#include #include #include diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 9318e32ed..73e01675a 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -3,7 +3,6 @@ #include #include #include -#include namespace Gui { diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 6af0118de..2497b9e2f 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -211,3 +211,16 @@ disposition change of merchants caused by trading will be permanent and won't be This imitates the option that Morrowind Code Patch offers. This setting can be toggled in Advanced tab of the launcher. + +only appropriate ammunition bypasses resistance +----------------------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +If this setting is true, you will have to use the appropriate ammunition to bypass normal weapon resistance (or weakness). +An enchanted bow with chitin arrows will no longer be enough for the purpose, while a steel longbow with glass arrows will still work. +This was previously the default engine behavior that diverged from Morrowind design. + +This setting can be toggled in Advanced tab of the launcher. diff --git a/docs/source/reference/modding/settings/index.rst b/docs/source/reference/modding/settings/index.rst index b4bf1d2d3..53b097a54 100644 --- a/docs/source/reference/modding/settings/index.rst +++ b/docs/source/reference/modding/settings/index.rst @@ -55,3 +55,4 @@ The ranges included with each setting are the physically possible ranges, not re video water windows + navigator diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst new file mode 100644 index 000000000..d9ddf5381 --- /dev/null +++ b/docs/source/reference/modding/settings/navigator.rst @@ -0,0 +1,374 @@ +Navigator Settings +################ + +Main settings +************* + +This section is for players. + +enable +------ + +:Type: boolean +:Range: True/False +:Default: True + +Enable navigator. +When enabled background threads are started to build nav mesh for world geometry. +Pathfinding system uses nav mesh to build paths. +When disabled only pathgrid is used to build paths. +Single-core CPU systems may have big performance impact on exiting interior location and moving across exterior world. +May slightly affect performance on multi-core CPU systems. +Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. +Moving across external world, entering/exiting location produce nav mesh update. +NPC and creatures may not be able to find path before nav mesh is built around them. +Try to disable this if you want to have old fashioned AI which doesn't know where to go when you stand behind that stone and casting a firebolt. + +max tiles number +---------------- + +:Type: integer +:Range: >= 0 +:Default: 512 + +Number of tiles at nav mesh. +Nav mesh covers circle area around player. +This option allows to set an explicit limit for nav mesh size, how many tiles should fit into circle. +If actor is inside this area it able to find path over nav mesh. +Increasing this value may decrease performance. + +.. note:: + Don't expect infinite nav mesh size increasing. + This condition is always true: ``max tiles number * max polygons per tile <= 4194304``. + It's a limitation of `Recastnavigation `_ library. + +Advanced settings +***************** + +This section is for advanced PC uses who understands concepts of OS thread and memory. + +async nav mesh updater threads +------------------------------ + +:Type: integer +:Range: >= 1 +:Default: 1 + +Number of background threads to update nav mesh. +Increasing this value may decrease performance, but also may decrease or increase nav mesh update latency depending on number of CPU cores. +On systems with not less than 4 CPU cores latency dependens approximately like 1/log(n) from number of threads. +Don't expect twice better latency by doubling this value. + +max nav mesh tiles cache size +----------------------------- + +:Type: integer +:Range: >= 0 +:Default: 268435456 + +Maximum total cached size of all nav mesh tiles in bytes. +Setting greater than zero value will reduce nav mesh update latency for previously visited locations. +Increasing this value may increase total memory consumption, but potentially will reduce latency for recently visited locations. +Limit this value by total available physical memory minus base game memory consumption and other applications. +Game will not eat all memory at once. +Memory will be consumed in approximately linear dependency from number of nav mesh updates. +But only for new locations or already dropped from cache. + +Developer's settings +******************** + +This section is for developers or anyone who wants to investigate how nav mesh system works in OpenMW. + +enable log +---------- + +:Type: boolean +:Range: True/False +:Default: False + +Enable debug log. +Detournavigator module will write own debug log into separate file. +Potentially decreases performance. + +log path +-------- + +:Type: string +:Range: file system path +:Default: detournavigator.log + +Write debug log to this file. +Try use tmpfs or any other in-memory file system to reduce performance impact. + +enable write recast mesh to file +-------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write recast mesh to file in .obj format for each use to update nav mesh. +Option is used to find out what world geometry is used to build nav mesh. +Potentially decreases performance. + +enable write nav mesh to file +----------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write nav mesh to file to be able to open by RecastDemo application. +Usually it is more usefull to have both enable write recast mesh to file and this options enabled. +RecastDemo supports .obj files. +Potentially decreases performance. + +enable recast mesh file name revision +------------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write each recast mesh file with revision in name. +Otherwise will rewrite same file. +If it is unclear when geometry is changed use this option to dump multiple files for each state. + +enable nav mesh file name revision +---------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Write each nav mesh file with revision in name. +Otherwise will rewrite same file. +If it is unclear when nav mesh is changed use this option to dump multiple files for each state. + +recast mesh path prefix +----------------------- + +:Type: string +:Range: file system path +:Default: "" + +Write recast mesh file at path with this prefix. + +nav mesh path prefix +-------------------- + +:Type: string +:Range: file system path +:Default: "" + +Write nav mesh file at path with this prefix. + +enable nav mesh render +---------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Render nav mesh. +Allows to do in-game debug. +Every nav mesh is visible and every update is noticable. +Potentially decreases performance. + +enable agents paths render +------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Render agents paths. +Make visible all NPC's and creaure's plans where they are going. +Works even if Navigator is disabled. +Potentially decreases performance. + +Expert settings +*************** + +This section is for developers who wants to go deeper into Detournavigator component logic. + +recast scale factor +------------------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.017647058823529415 + +Scale of nav mesh coordinates to world coordinates. Recastnavigation builds voxels for world geometry. +Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size +"recast scale factor" / "cell size". Default value calculates by this equation: +sStepSizeUp * "recast scale factor" / "cell size" = 3 (max climb height should be equal to 3 voxels). +Changing this value will change generated nav mesh. Some locations may become unavailable for NPC and creatures. +Pay attention to slopes and roofs when change it. Increasing this value will reduce nav mesh update latency. + +max polygon path size +--------------------- + +:Type: integer +:Range: > 0 +:Default: 1024 + +Maximum size of path over polygons. + +max smooth path size +-------------------- + +:Type: integer +:Range: > 0 +:Default: 1024 + +Maximum size of smoothed path. + +triangles per chunk +------------------- + +:Type: integer +:Range: > 0 +:Default: 256 + +Maximum number of triangles in each node of mesh AABB tree. + +Expert Recastnavigation related settings +**************************************** + +This section is for OpenMW developers who knows about `Recastnavigation `_ library and understands how it works. + +cell height +----------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.2 + +The z-axis cell size to use for fields. +Defines voxel/grid/cell size. So their values have significant +side effects on all parameters defined in voxel units. +The minimum value for this parameter depends on the platform's floating point +accuracy, with the practical minimum usually around 0.05. +Same default value is used in RecastDemo. + +cell size +--------- + +:Type: floating point +:Range: > 0.0 +:Default: 0.2 + +The xy-plane cell size to use for fields. +Defines voxel/grid/cell size. So their values have significant +side effects on all parameters defined in voxel units. +The minimum value for this parameter depends on the platform's floating point +accuracy, with the practical minimum usually around 0.05. +Same default value is used in RecastDemo. + +detail sample dist +------------------ + +:Type: floating point +:Range: = 0.0 or >= 0.9 +:Default: 6.0 + +Sets the sampling distance to use when generating the detail mesh. + +detail sample max error +----------------------- + +:Type: floating point +:Range: >= 0.0 +:Default: 1.0 + +The maximum distance the detail mesh surface should deviate from heightfield data. + +max simplification error +------------------------ + +:Type: floating point +:Range: >= 0.0 +:Default: 1.3 + +The maximum distance a simplfied contour's border edges should deviate the original raw contour. + +tile size +--------- + +:Type: integer +:Range: > 0 +:Default: 64 + +The width and height of each tile. + +border size +----------- + +:Type: integer +:Range: >= 0 +:Default: 16 + +The size of the non-navigable border around the heightfield. + +max edge len +------------ + +:Type: integer +:Range: >= 0 +:Default: 12 + +The maximum allowed length for contour edges along the border of the mesh. + +max nav mesh query nodes +------------------------ + +:Type: integer +:Range: 0 < value <= 65535 +:Default: 2048 + +Maximum number of search nodes. + +max polygons per tile +--------------------- + +:Type: integer +:Range: 2^n, 0 < n < 22 +:Default: 4096 + +Maximum number of polygons per nav mesh tile. Maximum number of nav mesh tiles depends on +this value. 22 bits is a limit to store both tile identifier and polygon identifier (tiles = 2^(22 - log2(polygons))). +See `recastnavigation `_ for more details. + +.. Warning:: + Lower value may lead to ignored world geometry on nav mesh. + Greater value will reduce number of nav mesh tiles. + This condition is always true: ``max tiles number * max polygons per tile <= 4194304``. + It's a limitation of `Recastnavigation `_ library. + +max verts per poly +------------------ + +:Type: integer +:Range: >= 3 +:Default: 6 + +The maximum number of vertices allowed for polygons generated during the contour to polygon conversion process. + +region merge size +----------------- + +:Type: integer +:Range: >= 0 +:Default: 20 + +Any regions with a span count smaller than this value will, if possible, be merged with larger regions. + +region min size +--------------- + +:Type: integer +:Range: >= 0 +:Default: 8 + +The minimum number of cells allowed to form isolated island areas. diff --git a/docs/source/reference/modding/settings/shaders.rst b/docs/source/reference/modding/settings/shaders.rst index b8a3b45b9..b36f64285 100644 --- a/docs/source/reference/modding/settings/shaders.rst +++ b/docs/source/reference/modding/settings/shaders.rst @@ -1,7 +1,6 @@ Shaders Settings ################ -.. _force-shaders-label: force shaders ------------- diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index c8d3250a0..9b207c448 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -13,7 +13,7 @@ enable shadows Enable or disable the rendering of shadows. Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can have a performance impact, but has more realistic results. -Bear in mind that this will force OpenMW to use shaders as if :ref:`force-shaders-label` was enabled. +Bear in mind that this will force OpenMW to use shaders as if :ref:`force shaders` was enabled. A keen developer may be able to implement compatibility with fixed-function mode using the advice of `this post `_, but it may be more difficult than it seems. @@ -163,6 +163,17 @@ Used as the units parameter for the polygon offset used for shadow map rendering Higher values reduce shadow flicker, but risk increasing Peter Panning. See `the OpenGL documentation for glPolygonOffset `_ for details. +normal offset distance +---------------------- + +:Type: float +:Range: Theoretically the whole range of 32-bit floating point, but values between 0 and 2 are most sensible. +:Default: 1.0 + +How far along the surface normal to project shadow coordinates. +Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. +This value is in in-game units, so 1.0 is roughly 1.4 cm. + use front face culling ---------------------- diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index 687f55e5e..e15a0035d 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -12,7 +12,7 @@ Controls whether the engine will use paging and LOD algorithms to load the terra Otherwise, only the terrain of the surrounding cells is loaded. .. note:: - When enabling distant terrain, make sure the 'viewing distance' in the camera section is set to a larger value so + When enabling distant terrain, make sure the 'viewing distance' in the camera section is set to a larger value so that you can actually see the additional terrain. To avoid frame drops as the player moves around, nearby terrain pages are always preloaded in the background, @@ -23,3 +23,81 @@ will still be controlled by cell preloading settings. The distant terrain engine is currently considered experimental and may receive updates and/or further configuration options in the future. The glaring omission of non-terrain objects in the distance somewhat limits this setting's usefulness. + +vertex lod mod +-------------- + +:Type: integer +:Range: any +:Default: 0 + +Controls only the Vertex LOD of the terrain. The amount of terrain chunks and the detail of composite maps is left unchanged. + +Must be changed in increments of 1. Each increment will double (for positive values) or halve (for negative values) the number of vertices rendered. +For example: -2 means 4x reduced detail, +3 means 8x increased detail. + +Note this setting will typically not affect near terrain. When set to increase detail, the detail of near terrain can not be increased +because the detail is simply not there in the data files, and when set to reduce detail, +the detail of near terrain will not be reduced because it was already less detailed than the far terrain (in view relative terms) to begin with. + +lod factor +---------- + +:Type: float +:Range: >0 +:Default: 1.0 + +Controls the level of detail if distant terrain is enabled. +Higher values increase detail at the cost of performance, lower values reduce detail but increase performance. + +Note: it also changes how the Quad Tree is split. +Increasing detail with this setting results in the visible terrain being divided into more chunks, +where as reducing detail with this setting would reduce the number of chunks. + +Fewer terrain chunks is faster for rendering, but on the other hand a larger proportion of the entire terrain +must be rebuilt when LOD levels change as the camera moves. +This could result in frame drops if moving across the map at high speed. + +For this reason, it is not recommended to change this setting if you want to change the LOD. +If you want to do that, first try using the 'vertex lod mod' setting to configure the detail of the terrain outlines +to your liking and then use 'composite map resolution' to configure the texture detail to your liking. +But these settings can only be changed in multiples of two, so you may want to adjust 'lod factor' afterwards for even more fine-tuning. + +composite map level +------------------- + +:Type: integer +:Range: >= -3 +:Default: 0 + +Controls at which minimum size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures. +With value -3 composite maps are used everywhere. + +A composite map is a pre-rendered texture that contains all the texture layers combined. +Note that resolution of composite maps is currently always fixed at 'composite map resolution', +regardless of the resolution of the underlying terrain textures. +If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value. + +composite map resolution +------------------------ + +:Type: integer +:Range: >0 +:Default: 512 + +Controls the resolution of composite maps. Larger values result in increased detail, +but may take longer to prepare and thus could result in longer loading times and an increased chance of frame drops during play. +As with most other texture resolution settings, it's most efficient to use values that are powers of two. + +An easy way to observe changes to loading time is to load a save in an interior next to an exterior door +(so it will start preloding terrain) and watch how long it takes for the 'Composite' counter on the F4 panel to fall to zero. + +max composite geometry size +--------------------------- + +:Type: float +:Range: >=1.0 +:Default: 4.0 + +Controls the maximum size of simple composite geometry chunk in cell units. With small values there will more draw calls and small textures, +but higher values create more overdraw (not every texture layer is used everywhere). diff --git a/docs/source/reference/modding/settings/water.rst b/docs/source/reference/modding/settings/water.rst index bd0741da9..3581efb99 100644 --- a/docs/source/reference/modding/settings/water.rst +++ b/docs/source/reference/modding/settings/water.rst @@ -58,17 +58,23 @@ This setting has no effect if the shader setting is false. This setting can be toggled with the 'Refraction' button in the Water tab of the Video panel of the Options menu. -reflect actors +reflection detail -------------- -:Type: boolean -:Range: True/False -:Default: False +:Type: integer +:Range: 0, 1, 2, 3, 4 +:Default: 2 + +Controls what kinds of things are rendered in water reflections. -This setting controls whether or not NPCs and creatures are drawn in water reflections. -Setting this to true will enable actors in reflections and increase realism with a likely decrease in performance. +0: only sky is reflected +1: terrain is also reflected +2: statics, activators, and doors are also reflected +3: items, containers, and particles are also reflected +4: actors are also reflected -This setting can be toggled with the 'Reflect actors' button in the Water tab of the Video panel of the Options menu. +In interiors the lowest level is 2. +This setting can be changed ingame with the "Reflection shader detail" dropdown under the Water tab of the Video panel in the Options menu. small feature culling pixel size -------------------------------- diff --git a/extern/recastnavigation/.travis.yml b/extern/recastnavigation/.travis.yml index 6044cd6b5..0e63abad1 100644 --- a/extern/recastnavigation/.travis.yml +++ b/extern/recastnavigation/.travis.yml @@ -1,36 +1,72 @@ -sudo: false - language: cpp +branches: + only: + - master + - coverity_scan + - /recast-.*$/ -# Build with gcc and clang. -compiler: - - gcc - - clang - -# Build both debug and release configurations, through use of an environment variable in the build matrix. -env: - - BUILD_TYPE=debug CMAKE_BUILD_TYPE=Debug - - BUILD_TYPE=release CMAKE_BUILD_TYPE=Release +sudo: false addons: apt: - packages: - - libsdl2-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-7 + packages: [ cmake, clang-7, clang-tools-7, gcc-8, g++-8, libsdl2-dev ] -install: - - wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake.tar.gz - - tar -xf premake.tar.gz - - rm premake.tar.gz +matrix: + include: + - name: Recastnavigation (all) on MacOS xcode9.4 + os: osx + osx_image: xcode9.4 + before_install: + - brew update + - brew install sdl2 + if: branch != coverity_scan + - name: Recastnavigation on Ubuntu Xenial GCC-5 + os: linux + dist: xenial + sudo: required + if: branch != coverity_scan + - name: Recastnavigation on Ubuntu Xenial GCC-8 + os: linux + dist: xenial + sudo: required + env: + - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" + if: branch != coverity_scan + - name: Recastnavigation on Ubuntu Xenial GCC-5 using Premake5 + os: linux + dist: xenial + sudo: required + if: branch != coverity_scan + before_install: + - wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake.tar.gz + - tar -xf premake.tar.gz + env: + - PREMAKE=1 + - name: Recastnavigation on Ubuntu Xenial Clang-7 with Static Analysis + os: linux + dist: xenial + sudo: required + env: + - MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" + - ANALYZE="scan-build-7 --force-analyze-debug-code --use-cc clang-7 --use-c++ clang++-7" + if: branch != coverity_scan + compiler: clang + - name: Recastnavigation Coverity Scan + os: linux + dist: xenial + sudo: required + if: branch = coverity_scan -# Run premake to generate makefiles. -# Have to cd into directory and back out since premake5 doesn't appear to accept a directory argument. before_script: - - cd RecastDemo && ../premake5 gmake && cd .. - - mkdir build && cd build && cmake -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} .. && cd .. + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then eval "${MATRIX_EVAL}"; fi + - if [ "${PREMAKE}" = "1" ]; then cd RecastDemo && ../premake5 gmake && cd ..; fi + - if [ "${PREMAKE}" != "1" ]; then mkdir -p build && cd build && ${ANALYZE} cmake ../ && cd ..; fi -# Run make in the directory containing generated makefiles, on the configuration specified by the environment variable. -script: - - make -C RecastDemo/Build/gmake -j$(nproc) config=${BUILD_TYPE} - - RecastDemo/Bin/Tests - - make -C build -j$(nproc) - - cd build && ctest +script: # 2 CPUs on Travis-CI + 1 extra for IO bound process + - if [ "${PREMAKE}" = "1" ]; then make -C RecastDemo/Build/gmake -j3; fi + - if [ "${PREMAKE}" != "1" ]; then make -C build -j3; fi + - if [ "${PREMAKE}" = "1" ]; then RecastDemo/Bin/Tests; fi + - if [ "${PREMAKE}" != "1" ]; then cd build && ctest; fi diff --git a/extern/recastnavigation/Detour/Include/DetourCommon.h b/extern/recastnavigation/Detour/Include/DetourCommon.h index 739858cd9..113e8c336 100644 --- a/extern/recastnavigation/Detour/Include/DetourCommon.h +++ b/extern/recastnavigation/Detour/Include/DetourCommon.h @@ -283,6 +283,28 @@ inline bool dtVequal(const float* p0, const float* p1) return d < thr; } +/// Checks that the specified vector's components are all finite. +/// @param[in] v A point. [(x, y, z)] +/// @return True if all of the point's components are finite, i.e. not NaN +/// or any of the infinities. +inline bool dtVisfinite(const float* v) +{ + bool result = + dtMathIsfinite(v[0]) && + dtMathIsfinite(v[1]) && + dtMathIsfinite(v[2]); + + return result; +} + +/// Checks that the specified vector's 2D components are finite. +/// @param[in] v A point. [(x, y, z)] +inline bool dtVisfinite2D(const float* v) +{ + bool result = dtMathIsfinite(v[0]) && dtMathIsfinite(v[2]); + return result; +} + /// Derives the dot product of two vectors on the xz-plane. (@p u . @p v) /// @param[in] u A vector [(x, y, z)] /// @param[in] v A vector [(x, y, z)] diff --git a/extern/recastnavigation/Detour/Include/DetourMath.h b/extern/recastnavigation/Detour/Include/DetourMath.h index 95e14f884..54af8af09 100644 --- a/extern/recastnavigation/Detour/Include/DetourMath.h +++ b/extern/recastnavigation/Detour/Include/DetourMath.h @@ -8,6 +8,9 @@ Members in this module are wrappers around the standard math library #define DETOURMATH_H #include +// This include is required because libstdc++ has problems with isfinite +// if cmath is included before math.h. +#include inline float dtMathFabsf(float x) { return fabsf(x); } inline float dtMathSqrtf(float x) { return sqrtf(x); } @@ -16,5 +19,6 @@ inline float dtMathCeilf(float x) { return ceilf(x); } inline float dtMathCosf(float x) { return cosf(x); } inline float dtMathSinf(float x) { return sinf(x); } inline float dtMathAtan2f(float y, float x) { return atan2f(y, x); } +inline bool dtMathIsfinite(float x) { return std::isfinite(x); } #endif diff --git a/extern/recastnavigation/Detour/Source/DetourCommon.cpp b/extern/recastnavigation/Detour/Source/DetourCommon.cpp index 41d0d7bd3..3886f14b0 100644 --- a/extern/recastnavigation/Detour/Source/DetourCommon.cpp +++ b/extern/recastnavigation/Detour/Source/DetourCommon.cpp @@ -204,32 +204,31 @@ void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const floa bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h) { float v0[3], v1[3], v2[3]; + dtVsub(v0, c,a); dtVsub(v1, b,a); dtVsub(v2, p,a); - - const float dot00 = dtVdot2D(v0, v0); - const float dot01 = dtVdot2D(v0, v1); - const float dot02 = dtVdot2D(v0, v2); - const float dot11 = dtVdot2D(v1, v1); - const float dot12 = dtVdot2D(v1, v2); - - // Compute barycentric coordinates - const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); - const float u = (dot11 * dot02 - dot01 * dot12) * invDenom; - const float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // Compute scaled barycentric coordinates + float denom = v0[0] * v1[2] - v0[2] * v1[0]; + float u = v1[2] * v2[0] - v1[0] * v2[2]; + float v = v0[0] * v2[2] - v0[2] * v2[0]; + + if (denom < 0) { + denom = -denom; + u = -u; + v = -v; + } // The (sloppy) epsilon is needed to allow to get height of points which // are interpolated along the edges of the triangles. - static const float EPS = 1e-4f; - + float epsilon = - 1e-4f * denom; + // If point lies inside the triangle, return interpolated ycoord. - if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS) - { - h = a[1] + v0[1]*u + v1[1]*v; + if (u >= epsilon && v >= epsilon && (u+v) <= denom - epsilon) { + h = a[1] + (v0[1]*u + v1[1]*v) / denom; return true; } - return false; } diff --git a/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp b/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp index 90999f2f6..c5ef385f9 100644 --- a/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp +++ b/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp @@ -222,7 +222,10 @@ dtStatus dtNavMeshQuery::findRandomPoint(const dtQueryFilter* filter, float (*fr dtPolyRef* randomRef, float* randomPt) const { dtAssert(m_nav); - + + if (!filter || !frand || !randomRef || !randomPt) + return DT_FAILURE | DT_INVALID_PARAM; + // Randomly pick one tile. Assume that all tiles cover roughly the same area. const dtMeshTile* tile = 0; float tsum = 0.0f; @@ -319,8 +322,13 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const f dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + maxRadius < 0 || !dtMathIsfinite(maxRadius) || + !filter || !frand || !randomRef || !randomPt) + { return DT_FAILURE | DT_INVALID_PARAM; + } const dtMeshTile* startTile = 0; const dtPoly* startPoly = 0; @@ -512,6 +520,9 @@ dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, flo return DT_FAILURE | DT_INVALID_PARAM; if (!tile) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite(pos) || !closest) + return DT_FAILURE | DT_INVALID_PARAM; // Off-mesh connections don't have detail polygons. if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) @@ -607,6 +618,9 @@ dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite(pos) || !closest) + return DT_FAILURE | DT_INVALID_PARAM; // Collect vertices. float verts[DT_VERTS_PER_POLYGON*3]; @@ -659,6 +673,9 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite2D(pos)) + return DT_FAILURE | DT_INVALID_PARAM; if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) { @@ -767,6 +784,8 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* halfE if (!nearestRef) return DT_FAILURE | DT_INVALID_PARAM; + + // queryPolygons below will check rest of params dtFindNearestPolyQuery query(this, center); @@ -972,8 +991,12 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* halfExt { dtAssert(m_nav); - if (!center || !halfExtents || !filter || !query) + if (!center || !dtVisfinite(center) || + !halfExtents || !dtVisfinite(halfExtents) || + !filter || !query) + { return DT_FAILURE | DT_INVALID_PARAM; + } float bmin[3], bmax[3]; dtVsub(bmin, center, halfExtents); @@ -1021,14 +1044,20 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, dtAssert(m_nav); dtAssert(m_nodePool); dtAssert(m_openList); - - if (pathCount) - *pathCount = 0; + + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + + *pathCount = 0; // Validate input if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) || - !startPos || !endPos || !filter || maxPath <= 0 || !path || !pathCount) + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || !path || maxPath <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } if (startRef == endRef) { @@ -1263,18 +1292,21 @@ dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef m_query.status = DT_FAILURE; m_query.startRef = startRef; m_query.endRef = endRef; - dtVcopy(m_query.startPos, startPos); - dtVcopy(m_query.endPos, endPos); + if (startPos) + dtVcopy(m_query.startPos, startPos); + if (endPos) + dtVcopy(m_query.endPos, endPos); m_query.filter = filter; m_query.options = options; m_query.raycastLimitSqr = FLT_MAX; - if (!startRef || !endRef) - return DT_FAILURE | DT_INVALID_PARAM; - // Validate input - if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef)) + if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || !filter) + { return DT_FAILURE | DT_INVALID_PARAM; + } // trade quality with performance? if (options & DT_FINDPATH_ANY_ANGLE) @@ -1530,7 +1562,13 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath) { + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *pathCount = 0; + + if (!path || maxPath <= 0) + return DT_FAILURE | DT_INVALID_PARAM; if (dtStatusFailed(m_query.status)) { @@ -1615,12 +1653,13 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize, dtPolyRef* path, int* pathCount, const int maxPath) { + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *pathCount = 0; - - if (existingSize == 0) - { - return DT_FAILURE; - } + + if (!existing || existingSize <= 0 || !path || !pathCount || maxPath <= 0) + return DT_FAILURE | DT_INVALID_PARAM; if (dtStatusFailed(m_query.status)) { @@ -1823,14 +1862,19 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en int* straightPathCount, const int maxStraightPath, const int options) const { dtAssert(m_nav); - - *straightPathCount = 0; - - if (!maxStraightPath) + + if (!straightPathCount) return DT_FAILURE | DT_INVALID_PARAM; - - if (!path[0]) + + *straightPathCount = 0; + + if (!startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !path || pathSize <= 0 || !path[0] || + maxStraightPath <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } dtStatus stat = 0; @@ -2070,13 +2114,19 @@ dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* start dtAssert(m_nav); dtAssert(m_tinyNodePool); - *visitedCount = 0; - - // Validate input - if (!startRef) + if (!visitedCount) return DT_FAILURE | DT_INVALID_PARAM; - if (!m_nav->isValidPolyRef(startRef)) + + *visitedCount = 0; + + if (!m_nav->isValidPolyRef(startRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || !resultPos || !visited || + maxVisitedSize <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } dtStatus status = DT_SUCCESS; @@ -2484,16 +2534,23 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons dtRaycastHit* hit, dtPolyRef prevRef) const { dtAssert(m_nav); - + + if (!hit) + return DT_FAILURE | DT_INVALID_PARAM; + hit->t = 0; hit->pathCount = 0; hit->pathCost = 0; // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; - if (prevRef && !m_nav->isValidPolyRef(prevRef)) + if (!m_nav->isValidPolyRef(startRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || + (prevRef && !m_nav->isValidPolyRef(prevRef))) + { return DT_FAILURE | DT_INVALID_PARAM; + } float dir[3], curPos[3], lastPos[3]; float verts[DT_VERTS_PER_POLYGON*3+3]; @@ -2735,11 +2792,18 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* dtAssert(m_nodePool); dtAssert(m_openList); + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; - - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + radius < 0 || !dtMathIsfinite(radius) || + !filter || maxResult < 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } m_nodePool->clear(); m_openList->clear(); @@ -2901,8 +2965,18 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v dtAssert(m_nav); dtAssert(m_nodePool); dtAssert(m_openList); - + + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; + + if (!m_nav->isValidPolyRef(startRef) || + !verts || nverts < 3 || + !filter || maxResult < 0) + { + return DT_FAILURE | DT_INVALID_PARAM; + } // Validate input if (!startRef || !m_nav->isValidPolyRef(startRef)) @@ -3088,13 +3162,20 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* { dtAssert(m_nav); dtAssert(m_tinyNodePool); - + + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + radius < 0 || !dtMathIsfinite(radius) || + !filter || maxResult < 0) + { return DT_FAILURE | DT_INVALID_PARAM; - + } + static const int MAX_STACK = 48; dtNode* stack[MAX_STACK]; int nstack = 0; @@ -3301,13 +3382,19 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* const int maxSegments) const { dtAssert(m_nav); + + if (!segmentCount) + return DT_FAILURE | DT_INVALID_PARAM; *segmentCount = 0; - + const dtMeshTile* tile = 0; const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!filter || !segmentVerts || maxSegments < 0) + return DT_FAILURE | DT_INVALID_PARAM; int n = 0; static const int MAX_INTERVAL = 16; @@ -3455,8 +3542,13 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + maxRadius < 0 || !dtMathIsfinite(maxRadius) || + !filter || !hitDist || !hitPos || !hitNormal) + { return DT_FAILURE | DT_INVALID_PARAM; + } m_nodePool->clear(); m_openList->clear(); diff --git a/extern/recastnavigation/RecastDemo/CMakeLists.txt b/extern/recastnavigation/RecastDemo/CMakeLists.txt index ffeac6a4b..a6a1a7333 100644 --- a/extern/recastnavigation/RecastDemo/CMakeLists.txt +++ b/extern/recastnavigation/RecastDemo/CMakeLists.txt @@ -38,11 +38,13 @@ endif() add_dependencies(RecastDemo DebugUtils Detour DetourCrowd DetourTileCache Recast) target_link_libraries(RecastDemo ${OPENGL_LIBRARIES} SDL2::SDL2main DebugUtils Detour DetourCrowd DetourTileCache Recast) -install(TARGETS RecastDemo RUNTIME DESTINATION bin) +install(TARGETS RecastDemo + RUNTIME DESTINATION bin + BUNDLE DESTINATION bin) install(DIRECTORY Bin/Meshes DESTINATION bin) install(DIRECTORY Bin/TestCases DESTINATION bin) install(FILES Bin/DroidSans.ttf DESTINATION bin) if (WIN32) install(FILES "${SDL2_RUNTIME_LIBRARY}" DESTINATION bin) -endif() +endif() \ No newline at end of file diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2d9c13bc9..58be98cca 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -213,7 +213,7 @@ - + @@ -428,13 +428,15 @@ - - - - + + + + + + - - + + diff --git a/files/opencs/qt.png b/files/opencs/qt.png new file mode 100644 index 000000000..381cb2251 Binary files /dev/null and b/files/opencs/qt.png differ diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 5fd9860e1..6987544d7 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -68,6 +68,7 @@ object.png pathgrid.png potion.png + qt.png race.png random-item.png random.png diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a6616ecc1..e95646602 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -90,6 +90,22 @@ pointers cache size = 40 # If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells distant terrain = false +# Controls how the Quad Tree is split. This affects Vertex LOD, Texture LOD and load times. Values > 1 increase detail, values < 1 reduce detail. +lod factor = 1.0 + +# Controls only the Vertex LOD. Change in increments of 1, each change doubles (or halves) the number of vertices. Values > 0 increase detail, values < 0 reduce detail. +vertex lod mod = 0 + +# Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3. +# Higher value is more detailed textures. +composite map level = 0 + +# Controls the resolution of composite maps. +composite map resolution = 512 + +# Controls the maximum size of composite geometry, should be >= 1.0. With low values there will be many small chunks, with high values - lesser count of bigger chunks. +max composite geometry size = 4.0 + [Fog] # If true, use extended fog parameters for distant terrain not controlled by @@ -236,12 +252,15 @@ barter disposition change is permanent = false # Uses the MCP formula (damage * (strength / 40)) to factor Strength into hand-to-hand combat. # (0 means it does not factor it in, 1 means it factors into werewolves damage calculation and -# 2 means werewolves are ignored) +# 2 means werewolves are ignored) strength influences hand to hand = 0 # Render holstered weapons (with quivers and scabbards), requires modded assets weapon sheathing = false +# Allow non-standard ammunition solely to bypass normal weapon resistance or weakness +only appropriate ammunition bypasses resistance = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). @@ -443,8 +462,8 @@ rtt size = 512 # Enable refraction which affects visibility through water plane. refraction = false -# Draw NPCs and creatures on water reflections. -reflect actors = false +# Draw objects on water reflections. +reflection detail = 2 # Overrides the value in '[Camera] small feature culling pixel size' specifically for water reflection/refraction textures. small feature culling pixel size = 20.0 @@ -651,6 +670,9 @@ enable nav mesh render = false # Render agents paths (true, false) enable agents paths render = false +# Max number of navmesh tiles (value >= 0) +max tiles number = 512 + [Shadows] # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 0793345c8..23c860f89 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -96,6 +96,16 @@ + + + + <html><head/><body><p>Allow non-standard ammunition solely to bypass normal weapon resistance or weakness.</p></body></html> + + + Only appropriate ammunition bypasses normal weapon resistance + + +