From 13517e723af13cabdadcba4cc0172923b91dd20b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Apr 2017 10:05:57 +0200 Subject: [PATCH 001/521] increased version number --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b4e9ad4b..ec7e2577c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ endif() message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) -set(OPENMW_VERSION_MINOR 41) +set(OPENMW_VERSION_MINOR 42) set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") diff --git a/README.md b/README.md index d38dfaeb2..1ed377936 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. -* Version: 0.41.0 +* Version: 0.42.0 * License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net From 59a9a7aafb458b382cd2f7573ee0d4f083069c0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Apr 2017 10:28:08 +0200 Subject: [PATCH 002/521] updated changelog --- CHANGELOG.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87d826753..b390169c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,82 @@ +0.42.0 +------ + + Bug #1956: Duplicate objects after loading the game, when a mod was edited + Bug #2100: Falling leaves in Vurt's Leafy West Gash II not rendered correctly + Bug #2116: Cant fit through some doorways pressed against staircases + Bug #2289: Some modal dialogs are not centered on the screen when the window resizes + Bug #2409: Softlock when pressing weapon/magic switch keys during chargen, afterwards switches weapons even though a text field is selected + Bug #2483: Previous/Next Weapon hotkeys triggered while typing the name of game save + Bug #2629: centeroncell, coc causes death / fall damage time to time when teleporting from high + Bug #2645: Cycling weapons is possible while console/pause menu is open + Bug #2678: Combat with water creatures do not end upon exiting water + Bug #2759: Light Problems in Therana's Chamber in Tel Branora + Bug #2771: unhandled sdl event of type 0x302 + Bug #2777: (constant/on cast) disintegrate armor/weapon on self is seemingly not working + Bug #2838: Editor: '.' in a record name should be allowed + Bug #2909: NPCs appear floating when standing on a slope + Bug #3093: Controller movement cannot be used while mouse is moving + Bug #3134: Crash possible when using console with open container + Bug #3254: AI enemies hit between them. + Bug #3344: Editor: Verification results sorting by Type is not alphabetical. + Bug #3345: Editor: Cloned and added pathgrids are lost after reopen of saved omwgame file + Bug #3355: [MGSO] Physics maxing out in south cornerclub Balmora + Bug #3484: Editor: camera position is not set when changing cell via drag&drop + Bug #3508: Slowfall kills Jump momentum + Bug #3580: Crash: Error ElementBufferObject::remove BufferData<0> out of range + Bug #3581: NPCs wander too much + Bug #3601: Menu Titles not centered vertically + Bug #3607: [Mac OS] Beginning of NPC speech cut off (same issue as closed bug #3453) + Bug #3613: Can not map "next weapon" or "next spell" to controller + Bug #3617: Enchanted arrows don't explode when hitting the ground + Bug #3645: Unable to use steps in Vivec, Palace of Vivec + Bug #3650: Tamriel Rebuilt 16.09.1 – Hist Cuirass GND nif is rendered inside a Pink Box + Bug #3652: Item icon shadows get stuck in the alchemy GUI + Bug #3653: Incorrect swish sounds + Bug #3666: NPC collision should not be disabled until death animation has finished + Bug #3669: Editor: Text field was missing from book object editing dialogue + Bug #3670: Unhandled SDL event of type 0x304 + Bug #3671: Incorrect local variable value after picking up bittercup + Bug #3686: Travelling followers doesn't increase travel fee + Bug #3689: Problematic greetings from Antares Big Mod that override the appropriate ones. + Bug #3690: Certain summoned creatures do not engage in combat with underwater creatures + Bug #3691: Enemies do not initiate combat with player followers on sight + Bug #3695: [Regression] Dispel does not always dispel spell effects in 0.41 + Bug #3699: Crash on MWWorld::ProjectileManager::moveMagicBolts + Bug #3700: Climbing on rocks and mountains + Bug #3704: Creatures don't auto-equip their shields on creation + Bug #3705: AI combat engagement logic differs from vanilla + Bug #3707: Animation playing does some very odd things if pc comes in contact with the animated mesh + Bug #3712: [Mod] Freeze upon entering Adanumuran with mod Adanumuran Reclaimed + Bug #3713: [Regression] Cancelling dialogue or using travel with creatures throws a (possibly game-breaking) exception + Bug #3719: Dropped identification papers can't be picked up again + Bug #3722: Command spell doesn't bring enemies out of combat + Bug #3727: Using "Activate" mid-script-execution invalidates interpreter context + Bug #3746: Editor: Book records show attribute IDs instead of skill IDs for teached skills entry. + Bug #3755: Followers stop following after loading from savegame + Bug #3772: ModStat lowers attribute to 100 if it was greater + Bug #3781: Guns in Clean Hunter Rifles mod use crossbow sounds + Bug #3797: NPC and creature names don't show up in combat when RMB windows are displayed + Bug #3800: Wrong tooltip maximum width + Bug #3801: Drowning widget is bugged + Bug #3802: BarterOffer shouldn't limit pcMercantile + Bug #3813: Some fatal error + Bug #3816: Expression parser thinks the -> token is unexpected when a given explicit refID clashes with a journal ID + Bug #3822: Custom added creatures are not animated + Feature #451: Water sounds + Feature #2691: Light particles sometimes not shown in inventory character preview + Feature #3523: Light source on magic projectiles + Feature #3644: Nif NiSphericalCollider Unknown Record Type + Feature #3675: ess-Importer: convert mark location + Feature #3693: ess-Importer: convert last known exterior cell + Feature #3748: Editor: Replace "Scroll" check box in Book records with "Book Type" combo box. + Feature #3751: Editor: Replace "Xyz Blood" check boxes in NPC and Creature records with "Blood Type" combo box + Feature #3752: Editor: Replace emitter check boxes in Light records with "Emitter Type" combo box + Feature #3756: Editor: Replace "Female" check box in NPC records with "Gender" combo box + Feature #3757: Editor: Replace "Female" check box in BodyPart records with "Gender" combo box + Task #3092: const version of ContainerStoreIterator + Task #3795: /deps folder not in .gitignore + 0.41.0 ------ From fe4fb82646102a78d443c96708b8111ad744dbe4 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 13 Apr 2017 01:01:50 +0900 Subject: [PATCH 003/521] Cache allies found while iterating engageCombat (Fixes #3814) --- apps/openmw/mwmechanics/actors.cpp | 47 ++++++++++++++++++++++++------ apps/openmw/mwmechanics/actors.hpp | 4 ++- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0b398a046..89cff3fa1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -280,7 +280,7 @@ namespace MWMechanics } } - void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) + void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer) { CreatureStats& creatureStats1 = actor1.getClass().getCreatureStats(actor1); if (creatureStats1.getAiSequence().isInCombat(actor2)) @@ -306,7 +306,8 @@ namespace MWMechanics // Get actors allied with actor1. Includes those following or escorting actor1, actors following or escorting those actors, (recursive) // and any actor currently being followed or escorted by actor1 std::set allies1; - getActorsSidingWith(actor1, allies1); + + getActorsSidingWith(actor1, allies1, cachedAllies); // If an ally of actor1 has been attacked by actor2 or has attacked actor2, start combat between actor1 and actor2 for (std::set::const_iterator it = allies1.begin(); it != allies1.end(); ++it) @@ -328,10 +329,10 @@ namespace MWMechanics aggressive = true; } - std::set playerFollowersAndEscorters; - getActorsSidingWith(MWMechanics::getPlayer(), playerFollowersAndEscorters); + std::set playerAllies; + getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies); - bool isPlayerFollowerOrEscorter = std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) != playerFollowersAndEscorters.end(); + bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end(); // If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them // Doesn't apply for player followers/escorters @@ -341,7 +342,9 @@ namespace MWMechanics if (actor2.getClass().getCreatureStats(actor2).getAiSequence().isInCombat(actor1)) { std::set allies2; - getActorsSidingWith(actor2, allies2); + + getActorsSidingWith(actor2, allies2, cachedAllies); + // Check that an ally of actor2 is also in combat with actor1 for (std::set::const_iterator it = allies2.begin(); it != allies2.end(); ++it) { @@ -383,11 +386,11 @@ namespace MWMechanics // Do aggression check if actor2 is the player or a player follower or escorter if (!aggressive) { - if (againstPlayer || std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor2) != playerFollowersAndEscorters.end()) + if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end()) { // Player followers and escorters with high fight should not initiate combat with the player or with // other player followers or escorters - if (std::find(playerFollowersAndEscorters.begin(), playerFollowersAndEscorters.end(), actor1) == playerFollowersAndEscorters.end()) + if (std::find(playerAllies.begin(), playerAllies.end(), actor1) == playerAllies.end()) aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } @@ -1072,6 +1075,8 @@ namespace MWMechanics /// \todo move update logic to Actor class where appropriate + std::map > cachedAllies; // will be filled as engageCombat iterates + // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { @@ -1123,7 +1128,7 @@ namespace MWMechanics { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; - engageCombat(iter->first, it->first, it->first == player); + engageCombat(iter->first, it->first, cachedAllies, it->first == player); } } if (timerUpdateHeadTrack == 0) @@ -1588,6 +1593,30 @@ namespace MWMechanics getActorsSidingWith(*it, out); } + void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies) { + std::list followers = getActorsSidingWith(actor); + + // If we have already found actor's allies, use the cache + std::map >::const_iterator search = cachedAllies.find(actor); + if (search != cachedAllies.end()) + out = search->second; + else + { + for (std::list::iterator it = followers.begin(); it != followers.end(); ++it) + if (out.insert(*it).second) + getActorsSidingWith(*it, out); + + // Cache ptrs and their sets of allies + cachedAllies.insert(std::make_pair(actor, out)); + for (std::set::const_iterator it = out.begin(); it != out.end(); ++it) + { + search = cachedAllies.find(*it); + if (search == cachedAllies.end()) + cachedAllies.insert(std::make_pair(*it, out)); + } + } + } + std::list Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor) { std::list list; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 20aef4c17..362c2f126 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -88,7 +88,7 @@ namespace MWMechanics @Notes: If againstPlayer = true then actor2 should be the Player. If one of the combatants is creature it should be actor1. */ - void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer); + void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, std::map >& cachedAllies, bool againstPlayer); void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); @@ -127,6 +127,8 @@ namespace MWMechanics void getActorsFollowing(const MWWorld::Ptr &actor, std::set& out); /// Recursive version of getActorsSidingWith void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out); + /// Recursive version of getActorsSidingWith that takes, adds to and returns a cache of actors mapped to their allies + void getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies); /// Get the list of AiFollow::mFollowIndex for all actors following this target std::list getActorsFollowingIndices(const MWWorld::Ptr& actor); From 56dfa615e1e11539842350e4794f4247f7308135 Mon Sep 17 00:00:00 2001 From: Allofich Date: Thu, 13 Apr 2017 03:57:59 +0900 Subject: [PATCH 004/521] Minor changes to getActorsSidingWith --- apps/openmw/mwmechanics/actors.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 89cff3fa1..80564de9f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1594,17 +1594,16 @@ namespace MWMechanics } void Actors::getActorsSidingWith(const MWWorld::Ptr &actor, std::set& out, std::map >& cachedAllies) { - std::list followers = getActorsSidingWith(actor); - // If we have already found actor's allies, use the cache std::map >::const_iterator search = cachedAllies.find(actor); if (search != cachedAllies.end()) - out = search->second; + out.insert(search->second.begin(), search->second.end()); else { + std::list followers = getActorsSidingWith(actor); for (std::list::iterator it = followers.begin(); it != followers.end(); ++it) if (out.insert(*it).second) - getActorsSidingWith(*it, out); + getActorsSidingWith(*it, out, cachedAllies); // Cache ptrs and their sets of allies cachedAllies.insert(std::make_pair(actor, out)); From 1c5c82dd9f27688e053ebe8f70f37ed56cd0afda Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 23 Apr 2017 18:05:41 +0200 Subject: [PATCH 005/521] Fix wrong incrementation in InventoryStore::visitEffectSources (Fixes #3838) --- apps/openmw/mwworld/inventorystore.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index df3f30bea..d251e824c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -823,7 +823,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito int i=0; for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); - effectIt!=enchantment.mEffects.mList.end(); ++effectIt) + effectIt!=enchantment.mEffects.mList.end(); ++effectIt, ++i) { // Don't get spell icon display information for enchantments that weren't actually applied if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0) @@ -833,8 +833,6 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito magnitude *= params.mMultiplier; if (magnitude > 0) visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), (**iter).getCellRef().getRefId(), -1, magnitude); - - ++i; } } } From 7704dcfcce3b43b7a20b4f0452e601b094267ee9 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sun, 28 May 2017 17:30:01 +0200 Subject: [PATCH 006/521] Fix build with osg >= 3.5.6 --- components/resource/bulletshapemanager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index ef35b31ef..010917572 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -42,7 +43,11 @@ struct GetTriangleFunctor return btVector3(vec.x(), vec.y(), vec.z()); } +#if OSG_MIN_VERSION_REQUIRED(3,5,6) + void inline operator()( const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3 ) +#else void inline operator()( const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3, bool _temp ) +#endif { if (mTriMesh) mTriMesh->addTriangle( toBullet(mMatrix.preMult(v1)), toBullet(mMatrix.preMult(v2)), toBullet(mMatrix.preMult(v3))); From ec458ef385cb49b24f39b916f4e45d92e22b9acb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 25 Jun 2017 13:08:55 +0200 Subject: [PATCH 007/521] Don't reset idle time when there is no camera movement (Fixes #3902) --- apps/openmw/mwinput/inputmanagerimp.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 234a17cc3..9979bd5d6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -417,18 +417,21 @@ namespace MWInput { float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f; float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; - resetIdleTime(); + if (xAxis != 0 || yAxis != 0) + { + resetIdleTime(); - float rot[3]; - rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; - rot[1] = 0.0f; - rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); + float rot[3]; + rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + rot[1] = 0.0f; + rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); - // Only actually turn player when we're not in vanity mode - if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) - { - mPlayer->yaw(rot[2]); - mPlayer->pitch(rot[0]); + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer->yaw(rot[2]); + mPlayer->pitch(rot[0]); + } } } From 9c94244b284562fcd7e152cf0c35abcb99cc6eb1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 30 Jun 2017 00:51:26 +0200 Subject: [PATCH 008/521] Fix crash introduced by commit 1d8a9ff62243cb6b8e218840d839e6d554f3e8d9 (Fixes #3940) --- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a22075abd..7fbf2965a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -378,8 +378,11 @@ namespace MWWorld return; case ESM::REC_PLAY: mPlayer->readRecord(reader, type); - mWorldScene->preloadCell(getPlayerPtr().getCell(), true); - mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); + if (getPlayerPtr().isInCell()) + { + mWorldScene->preloadCell(getPlayerPtr().getCell(), true); + mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3()); + } break; default: if (!mStore.readRecord (reader, type) && From cf6f3685604cab05e552ad7e73543f1fab8cdd5a Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Sat, 29 Jul 2017 11:52:13 +0200 Subject: [PATCH 009/521] rtd backport fix --- CMakeLists.txt | 2 +- docs/requirements.txt | 1 - docs/source/conf.py | 40 +-- docs/source/index.rst | 11 +- docs/source/source/index.rst | 8 - docs/source/source/opencs/index.rst | 11 - docs/source/source/opencs/model/index.rst | 358 ---------------------- docs/source/source/opencs/view/index.rst | 340 -------------------- docs/source/source/openmw/index.rst | 24 -- docs/source/source/openmw/mwbase.rst | 32 -- docs/source/source/openmw/mwclass.rst | 68 ---- docs/source/source/openmw/mwdialogue.rst | 32 -- docs/source/source/openmw/mwgui.rst | 227 -------------- docs/source/source/openmw/mwinput.rst | 5 - docs/source/source/openmw/mwmechanics.rst | 137 --------- docs/source/source/openmw/mwphysics.rst | 15 - docs/source/source/openmw/mwrender.rst | 77 ----- docs/source/source/openmw/mwscript.rst | 65 ---- docs/source/source/openmw/mwsound.rst | 29 -- docs/source/source/openmw/mwstate.rst | 11 - docs/source/source/openmw/mwworld.rst | 132 -------- 21 files changed, 3 insertions(+), 1622 deletions(-) delete mode 100644 docs/source/source/index.rst delete mode 100644 docs/source/source/opencs/index.rst delete mode 100644 docs/source/source/opencs/model/index.rst delete mode 100644 docs/source/source/opencs/view/index.rst delete mode 100644 docs/source/source/openmw/index.rst delete mode 100644 docs/source/source/openmw/mwbase.rst delete mode 100644 docs/source/source/openmw/mwclass.rst delete mode 100644 docs/source/source/openmw/mwdialogue.rst delete mode 100644 docs/source/source/openmw/mwgui.rst delete mode 100644 docs/source/source/openmw/mwinput.rst delete mode 100644 docs/source/source/openmw/mwmechanics.rst delete mode 100644 docs/source/source/openmw/mwphysics.rst delete mode 100644 docs/source/source/openmw/mwrender.rst delete mode 100644 docs/source/source/openmw/mwscript.rst delete mode 100644 docs/source/source/openmw/mwsound.rst delete mode 100644 docs/source/source/openmw/mwstate.rst delete mode 100644 docs/source/source/openmw/mwworld.rst diff --git a/CMakeLists.txt b/CMakeLists.txt index ec7e2577c..7a2ac34c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -407,7 +407,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.png" DESTINATION "${ICONDIR}" COMPONENT "openmw") - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/appdata" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.appdata.xml" DESTINATION "${DATAROOTDIR}/metainfo" COMPONENT "openmw") IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "opencs") INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/opencs/openmw-cs.png" DESTINATION "${ICONDIR}" COMPONENT "opencs") diff --git a/docs/requirements.txt b/docs/requirements.txt index 6ee8d6987..72c2aaa12 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,2 @@ -breathe parse_cmake sphinx diff --git a/docs/source/conf.py b/docs/source/conf.py index 273b2f7d5..b18b40c50 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -11,7 +11,6 @@ # # All configuration values have a default; values that are commented out # serve to show the default. -import glob import os import sys @@ -21,12 +20,6 @@ import sys project_root = os.path.abspath('../../') sys.path.insert(0, project_root) - -def insensitive_glob(pattern): - def either(c): - return '[%s%s]' % (c.lower(), c.upper()) if c.isalpha() else c - return glob.glob(''.join(map(either, pattern))) - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -43,37 +36,6 @@ extensions = [ 'sphinx.ext.viewcode', ] -try: - import breathe - extensions.append('breathe') -except ImportError: - print("WARNING: Unable to import breathe, code documentation won't be generated.") - -# Where breathe can find the source files -openmw_path = os.path.join(project_root, "apps", "openmw") -openmw_sub_dirs = os.walk(openmw_path).next()[1] -openmw_headers = insensitive_glob(os.path.join(openmw_path, "*.hpp")) -for dir in openmw_sub_dirs: - openmw_headers += insensitive_glob(os.path.join(openmw_path, dir, "*.hpp")) -# massage the headers to get the relative path needed -openmw_headers = [os.path.relpath(x, openmw_path) for x in openmw_headers] - -opencs_path = os.path.join(project_root, "apps", "opencs") -opencs_sub_dirs = os.walk(opencs_path).next()[1] -opencs_headers = insensitive_glob(os.path.join(opencs_path, "*.hpp")) -opencs_sub_sub_dirs = [] -for dir in opencs_sub_dirs: - opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, "*.hpp")) - opencs_sub_sub_dirs += os.walk(os.path.join(opencs_path, dir)).next()[1] - for sub_dir in opencs_sub_sub_dirs: - opencs_headers += insensitive_glob(os.path.join(opencs_path, dir, sub_dir, "*.hpp")) -opencs_headers = [os.path.relpath(x, opencs_path) for x in opencs_headers] - -breathe_projects_source = { - "openmw": (openmw_path, openmw_headers), - "opencs": (opencs_path, opencs_headers), -} - # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -88,7 +50,7 @@ master_doc = 'index' # General information about the project. project = u'OpenMW' -copyright = u'2016, OpenMW Team' +copyright = u'2017, OpenMW Team' # The version info for the project you're documenting, acts as replacement for diff --git a/docs/source/index.rst b/docs/source/index.rst index f51cda909..3781733cb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -5,16 +5,7 @@ Sections -------- .. toctree:: - :maxdepth: 2 + :maxdepth: 3 manuals/index reference/index - source/index - - -Indices and Tables -================== - -* :ref:`genindex` -* :ref:`search` - diff --git a/docs/source/source/index.rst b/docs/source/source/index.rst deleted file mode 100644 index b58bf2b37..000000000 --- a/docs/source/source/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Project Source Documentation -============================ - -.. toctree:: - :maxdepth: 2 - - openmw/index - opencs/index \ No newline at end of file diff --git a/docs/source/source/opencs/index.rst b/docs/source/source/opencs/index.rst deleted file mode 100644 index b648bc49c..000000000 --- a/docs/source/source/opencs/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -OpenMW-CS Source Documentation -############################## - -.. toctree:: - :maxdepth: 2 - - model/index - view/index - -.. autodoxygenfile:: editor.hpp - :project: opencs \ No newline at end of file diff --git a/docs/source/source/opencs/model/index.rst b/docs/source/source/opencs/model/index.rst deleted file mode 100644 index 38ca0c31c..000000000 --- a/docs/source/source/opencs/model/index.rst +++ /dev/null @@ -1,358 +0,0 @@ -./opencs/model -############## - -doc ---- - .. autodoxygenfile:: model/doc/blacklist.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/document.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/documentmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/loader.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/messages.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/operationholder.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/operation.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/runner.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/saving.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/savingstages.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/savingstate.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/stage.hpp - :project: opencs - - .. autodoxygenfile:: model/doc/state.hpp - :project: opencs - -filter ------- - .. autodoxygenfile:: model/filter/andnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/booleannode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/leafnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/narynode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/node.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/notnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/ornode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/parser.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/textnode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/unarynode.hpp - :project: opencs - - .. autodoxygenfile:: model/filter/valuenode.hpp - :project: opencs - -prefs ------ - .. autodoxygenfile:: model/prefs/boolsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/category.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/coloursetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/doublesetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/enumsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/intsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/modifiersetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/setting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcuteventhandler.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcut.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcutmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/shortcutsetting.hpp - :project: opencs - - .. autodoxygenfile:: model/prefs/state.hpp - :project: opencs - -tools ------ - .. autodoxygenfile:: model/tools/birthsigncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/bodypartcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/classcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/factioncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/gmstcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/journalcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/magiceffectcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mandatoryid.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergeoperation.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergestages.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/mergestate.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/pathgridcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/racecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/referenceablecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/referencecheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/regioncheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/reportmodel.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/scriptcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/search.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/searchoperation.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/searchstage.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/skillcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/soundcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/soundgencheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/spellcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/startscriptcheck.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/tools.hpp - :project: opencs - - .. autodoxygenfile:: model/tools/topicinfocheck.hpp - :project: opencs - -world ------ - .. autodoxygenfile:: model/world/cellcoordinates.hpp - :project: opencs - - .. autodoxygenfile:: model/world/cell.hpp - :project: opencs - - .. autodoxygenfile:: model/world/cellselection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/collectionbase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/collection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columnbase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columnimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/columns.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commanddispatcher.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commandmacro.hpp - :project: opencs - - .. autodoxygenfile:: model/world/commands.hpp - :project: opencs - - .. autodoxygenfile:: model/world/data.hpp - :project: opencs - - .. autodoxygenfile:: model/world/defaultgmsts.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idcompletionmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtablebase.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtable.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/idtree.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infocollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/info.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infoselectwrapper.hpp - :project: opencs - - .. autodoxygenfile:: model/world/infotableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/land.hpp - :project: opencs - - .. autodoxygenfile:: model/world/landtexture.hpp - :project: opencs - - .. autodoxygenfile:: model/world/metadata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcoladapterimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedcolumnadapter.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedidcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedinfocollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedtableproxymodel.hpp - :project: opencs - - .. autodoxygenfile:: model/world/nestedtablewrapper.hpp - :project: opencs - - .. autodoxygenfile:: model/world/pathgrid.hpp - :project: opencs - - .. autodoxygenfile:: model/world/record.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/ref.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidadapter.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidadapterimp.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refidcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/refiddata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/regionmap.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resources.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resourcesmanager.hpp - :project: opencs - - .. autodoxygenfile:: model/world/resourcetable.hpp - :project: opencs - - .. autodoxygenfile:: model/world/scope.hpp - :project: opencs - - .. autodoxygenfile:: model/world/scriptcontext.hpp - :project: opencs - - .. autodoxygenfile:: model/world/subcellcollection.hpp - :project: opencs - - .. autodoxygenfile:: model/world/tablemimedata.hpp - :project: opencs - - .. autodoxygenfile:: model/world/universalid.hpp - :project: opencs - diff --git a/docs/source/source/opencs/view/index.rst b/docs/source/source/opencs/view/index.rst deleted file mode 100644 index 54d00ccc0..000000000 --- a/docs/source/source/opencs/view/index.rst +++ /dev/null @@ -1,340 +0,0 @@ -./opencs/view -############# - -doc ---- - .. autodoxygenfile:: view/doc/adjusterwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/filedialog.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/filewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/globaldebugprofilemenu.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/loader.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/newgame.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/operation.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/operations.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/runlogsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/sizehint.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/startup.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subviewfactory.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subviewfactoryimp.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/subview.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/view.hpp - :project: opencs - - .. autodoxygenfile:: view/doc/viewmanager.hpp - :project: opencs - -filter ------- - .. autodoxygenfile:: view/filter/editwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/filter/filterbox.hpp - :project: opencs - - .. autodoxygenfile:: view/filter/recordfilterbox.hpp - :project: opencs - -prefs ------ - .. autodoxygenfile:: view/prefs/dialogue.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/keybindingpage.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/pagebase.hpp - :project: opencs - - .. autodoxygenfile:: view/prefs/page.hpp - :project: opencs - -render ------- - .. autodoxygenfile:: view/render/cameracontroller.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellarrow.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellborder.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cell.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellmarker.hpp - :project: opencs - - .. autodoxygenfile:: view/render/cellwater.hpp - :project: opencs - - .. autodoxygenfile:: view/render/editmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instancemode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instancemovemode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/instanceselectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingbright.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingday.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lighting.hpp - :project: opencs - - .. autodoxygenfile:: view/render/lightingnight.hpp - :project: opencs - - .. autodoxygenfile:: view/render/mask.hpp - :project: opencs - - .. autodoxygenfile:: view/render/object.hpp - :project: opencs - - .. autodoxygenfile:: view/render/orbitcameramode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pagedworldspacewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgrid.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgridmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/pathgridselectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/previewwidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/scenewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/selectionmode.hpp - :project: opencs - - .. autodoxygenfile:: view/render/tagbase.hpp - :project: opencs - - .. autodoxygenfile:: view/render/terrainstorage.hpp - :project: opencs - - .. autodoxygenfile:: view/render/unpagedworldspacewidget.hpp - :project: opencs - - .. autodoxygenfile:: view/render/worldspacewidget.hpp - :project: opencs - -tools ------ - .. autodoxygenfile:: view/tools/merge.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/reportsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/reporttable.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/searchbox.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/searchsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/tools/subviews.hpp - :project: opencs - -widget ------- - .. autodoxygenfile:: view/widget/coloreditor.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/colorpickerpopup.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/completerpopup.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/droplineedit.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/modebutton.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/pushbutton.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolbar.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetool.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolmode.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetoolrun.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetooltoggle2.hpp - :project: opencs - - .. autodoxygenfile:: view/widget/scenetooltoggle.hpp - :project: opencs - -world ------ - .. autodoxygenfile:: view/world/cellcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/colordelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/creator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/datadisplaydelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguespinbox.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dialoguesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dragdroputils.hpp - :project: opencs - - .. autodoxygenfile:: view/world/dragrecordtable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/enumdelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/extendedcommandconfigurator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/genericcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/globalcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idcompletiondelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idtypedelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/idvalidator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/infocreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/nestedtable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/pathgridcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/previewsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/recordbuttonbar.hpp - :project: opencs - - .. autodoxygenfile:: view/world/recordstatusdelegate.hpp - :project: opencs - - .. autodoxygenfile:: view/world/referenceablecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/referencecreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/regionmap.hpp - :project: opencs - - .. autodoxygenfile:: view/world/regionmapsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scenesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scriptedit.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scripterrortable.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scripthighlighter.hpp - :project: opencs - - .. autodoxygenfile:: view/world/scriptsubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/startscriptcreator.hpp - :project: opencs - - .. autodoxygenfile:: view/world/subviews.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tablebottombox.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tableeditidaction.hpp - :project: opencs - - .. autodoxygenfile:: view/world/table.hpp - :project: opencs - - .. autodoxygenfile:: view/world/tablesubview.hpp - :project: opencs - - .. autodoxygenfile:: view/world/util.hpp - :project: opencs - - .. autodoxygenfile:: view/world/vartypedelegate.hpp - :project: opencs diff --git a/docs/source/source/openmw/index.rst b/docs/source/source/openmw/index.rst deleted file mode 100644 index 5367995de..000000000 --- a/docs/source/source/openmw/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -OpenMW Source Documentation -########################### - -.. toctree:: - :maxdepth: 2 - - mwbase - mwclass - mwdialogue - mwgui - mwinput - mwmechanics - mwphysics - mwrender - mwscript - mwsound - mwstate - mwworld - -.. autodoxygenfile:: engine.hpp - :project: openmw - -.. autodoxygenfile:: doc.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwbase.rst b/docs/source/source/openmw/mwbase.rst deleted file mode 100644 index 8fd7ffc1e..000000000 --- a/docs/source/source/openmw/mwbase.rst +++ /dev/null @@ -1,32 +0,0 @@ -./mwbase -######## - -.. autodoxygenfile:: mwbase/dialoguemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/environment.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/inputmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/journal.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/mechanicsmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/scriptmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/soundmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/statemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/windowmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwbase/world.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwclass.rst b/docs/source/source/openmw/mwclass.rst deleted file mode 100644 index 3365d2582..000000000 --- a/docs/source/source/openmw/mwclass.rst +++ /dev/null @@ -1,68 +0,0 @@ -./mwclass -######### - -.. autodoxygenfile:: mwclass/activator.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/apparatus.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/armor.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/bodypart.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/book.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/classes.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/clothing.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/container.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/creature.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/creaturelevlist.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/ingredient.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/itemlevlist.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/light.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/lockpick.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/misc.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/npc.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/potion.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/probe.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/static.hpp - :project: openmw - -.. autodoxygenfile:: mwclass/weapon.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwdialogue.rst b/docs/source/source/openmw/mwdialogue.rst deleted file mode 100644 index 1f3522f2c..000000000 --- a/docs/source/source/openmw/mwdialogue.rst +++ /dev/null @@ -1,32 +0,0 @@ -./mwdialogue -############ - -.. autodoxygenfile:: mwdialogue/dialoguemanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/filter.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/hypertextparser.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/journalentry.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/journalimp.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/keywordsearch.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/quest.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/scripttest.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/selectwrapper.hpp - :project: openmw - -.. autodoxygenfile:: mwdialogue/topic.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwgui.rst b/docs/source/source/openmw/mwgui.rst deleted file mode 100644 index 0e3726832..000000000 --- a/docs/source/source/openmw/mwgui.rst +++ /dev/null @@ -1,227 +0,0 @@ -./mwgui -####### - -.. autodoxygenfile:: mwgui/alchemywindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/backgroundimage.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/birth.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/bookpage.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/bookwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/charactercreation.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/class.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/companionitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/companionwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/confirmationdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/console.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/container.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/containeritemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/controllers.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/countdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/cursor.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/debugwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/dialogue.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/draganddrop.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/enchantingdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/exposedwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/formatting.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/hud.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/inventoryitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/inventorywindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemchargeview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemselection.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/itemwidget.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/jailscreen.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalbooks.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalviewmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/journalwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/layout.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/levelupdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/loadingscreen.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mainmenu.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mapwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/merchantrepair.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/messagebox.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/mode.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/pickpocketitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/quickkeysmenu.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/race.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/recharge.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/referenceinterface.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/review.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/savegamedialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/screenfader.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/scrollwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/settingswindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/sortfilteritemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/soulgemdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellbuyingwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellcreationdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellicons.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellview.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/spellwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/statswindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/textinput.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/timeadvancer.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tooltips.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tradeitemmodel.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/tradewindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/trainingwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/travelwindow.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/videowidget.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/waitdialog.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/widgets.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowbase.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwgui/windowpinnablebase.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwinput.rst b/docs/source/source/openmw/mwinput.rst deleted file mode 100644 index b24d8dfdb..000000000 --- a/docs/source/source/openmw/mwinput.rst +++ /dev/null @@ -1,5 +0,0 @@ -./mwinput -######### - -.. autodoxygenfile:: mwinput/inputmanagerimp.hpp - :project: openmw \ No newline at end of file diff --git a/docs/source/source/openmw/mwmechanics.rst b/docs/source/source/openmw/mwmechanics.rst deleted file mode 100644 index 3427b712a..000000000 --- a/docs/source/source/openmw/mwmechanics.rst +++ /dev/null @@ -1,137 +0,0 @@ -./mwmechanics -############# - -.. autodoxygenfile:: mwmechanics/activespells.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actors.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/actorutil.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiactivate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiavoiddoor.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aicombataction.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aicombat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiescort.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiface.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aifollow.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aipackage.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aipursue.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aisequence.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aistate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aitravel.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/aiwander.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/alchemy.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/autocalcspell.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/character.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/combat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/coordinateconverter.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/creaturestats.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/difficultyscaling.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/disease.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/drawstate.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/enchanting.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/levelledlist.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/magiceffects.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/mechanicsmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/movement.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/npcstats.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/objects.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/obstacle.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pathfinding.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pathgrid.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/pickpocket.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/repair.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/security.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/spellcasting.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/spells.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/stat.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/steering.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/summoning.hpp - :project: openmw - -.. autodoxygenfile:: mwmechanics/trading.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwphysics.rst b/docs/source/source/openmw/mwphysics.rst deleted file mode 100644 index 6eebab4d9..000000000 --- a/docs/source/source/openmw/mwphysics.rst +++ /dev/null @@ -1,15 +0,0 @@ -./mwphysics -########### - -.. autodoxygenfile:: mwphysics/actor.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/collisiontype.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/convert.hpp - :project: openmw - -.. autodoxygenfile:: mwphysics/physicssystem.hpp - :project: openmw - diff --git a/docs/source/source/openmw/mwrender.rst b/docs/source/source/openmw/mwrender.rst deleted file mode 100644 index d284f6586..000000000 --- a/docs/source/source/openmw/mwrender.rst +++ /dev/null @@ -1,77 +0,0 @@ -./mwrender -########## - -.. autodoxygenfile:: mwrender/actoranimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/animation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/bulletdebugdraw.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/camera.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/cell.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/characterpreview.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/creatureanimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/effectmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/globalmap.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/localmap.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/npcanimation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/objects.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/pathgrid.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderbin.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderinginterface.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/renderingmanager.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/rendermode.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/ripplesimulation.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/rotatecontroller.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/sky.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/terrainstorage.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/util.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/vismask.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/water.hpp - :project: openmw - -.. autodoxygenfile:: mwrender/weaponanimation.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwscript.rst b/docs/source/source/openmw/mwscript.rst deleted file mode 100644 index 8db8f40e2..000000000 --- a/docs/source/source/openmw/mwscript.rst +++ /dev/null @@ -1,65 +0,0 @@ -./mwscript -########## - -.. autodoxygenfile:: mwscript/aiextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/animationextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/cellextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/compilercontext.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/consoleextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/containerextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/controlextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/dialogueextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/extensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/globalscripts.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/guiextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/interpretercontext.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/locals.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/miscextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/ref.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/scriptmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/skyextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/soundextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/statsextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/transformationextensions.hpp - :project: openmw - -.. autodoxygenfile:: mwscript/userextensions.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwsound.rst b/docs/source/source/openmw/mwsound.rst deleted file mode 100644 index d4fcb0e6b..000000000 --- a/docs/source/source/openmw/mwsound.rst +++ /dev/null @@ -1,29 +0,0 @@ -./mwsound -######### - -.. autodoxygenfile:: mwsound/ffmpeg_decoder.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/loudness.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/movieaudiofactory.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/openal_output.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_buffer.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_decoder.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/soundmanagerimp.hpp - :project: openmw - -.. autodoxygenfile:: mwsound/sound_output.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwstate.rst b/docs/source/source/openmw/mwstate.rst deleted file mode 100644 index 2618c6ff0..000000000 --- a/docs/source/source/openmw/mwstate.rst +++ /dev/null @@ -1,11 +0,0 @@ -./mwstate -######### - -.. autodoxygenfile:: mwstate/character.hpp - :project: openmw - -.. autodoxygenfile:: mwstate/charactermanager.hpp - :project: openmw - -.. autodoxygenfile:: mwstate/statemanagerimp.hpp - :project: openmw diff --git a/docs/source/source/openmw/mwworld.rst b/docs/source/source/openmw/mwworld.rst deleted file mode 100644 index 21026b3e2..000000000 --- a/docs/source/source/openmw/mwworld.rst +++ /dev/null @@ -1,132 +0,0 @@ -./mwworld -######### - -.. autodoxygenfile:: mwworld/actionalchemy.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionapply.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiondoor.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actioneat.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionequip.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/action.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionopen.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionread.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionrepair.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionsoulgem.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontake.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontalk.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actionteleport.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/actiontrap.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellpreloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellreflist.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cells.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/cellvisitors.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/class.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/containerstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/contentloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/customdata.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/esmloader.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/esmstore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/failedaction.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/globals.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/inventorystore.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/livecellref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/localscripts.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/manualref.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/nullaction.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/player.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/projectilemanager.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/ptr.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/recordcmp.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/refdata.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/scene.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/store.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/timestamp.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/weather.hpp - :project: openmw - -.. autodoxygenfile:: mwworld/worldimp.hpp - :project: openmw - From b7cfb1aaf42312bfcd51375c0d29604b21e34bf0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 31 Jul 2017 23:05:19 +0400 Subject: [PATCH 010/521] Fixed DamageHealth and AbsorbHealth effects applying --- apps/openmw/mwmechanics/spellcasting.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 7fde66ebe..a6ae5ca65 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1131,6 +1131,9 @@ namespace MWMechanics receivedMagicDamage = true; adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); } + + break; + case ESM::MagicEffect::DamageMagicka: case ESM::MagicEffect::DamageFatigue: if (!godmode) @@ -1147,6 +1150,9 @@ namespace MWMechanics receivedMagicDamage = true; adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); } + + break; + case ESM::MagicEffect::AbsorbMagicka: case ESM::MagicEffect::AbsorbFatigue: if (!godmode) From d24286273b68c0d1d3cd3d79bbfbc0e17dceff67 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Wed, 28 Jun 2017 22:40:13 +0200 Subject: [PATCH 011/521] Prevent respawned references from being added to the scene twice in certain cases (Fixes #3864) --- apps/openmw/mwrender/objects.cpp | 16 +++++++++------- apps/openmw/mwworld/scene.cpp | 6 ++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d4cbf25fe..f0a3d2e38 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -38,6 +38,8 @@ Objects::~Objects() void Objects::insertBegin(const MWWorld::Ptr& ptr) { + assert(mObjects.find(ptr) == mObjects.end()); + osg::ref_ptr cellnode; CellMap::iterator found = mCellSceneNodes.find(ptr.getCell()); @@ -90,9 +92,8 @@ void Objects::insertCreature(const MWWorld::Ptr &ptr, const std::string &mesh, b else anim = new CreatureAnimation(ptr, mesh, mResourceSystem); - ptr.getClass().getContainerStore(ptr).setContListener(static_cast(anim.get())); - - mObjects.insert(std::make_pair(ptr, anim)); + if (mObjects.insert(std::make_pair(ptr, anim)).second) + ptr.getClass().getContainerStore(ptr).setContListener(static_cast(anim.get())); } void Objects::insertNPC(const MWWorld::Ptr &ptr) @@ -102,10 +103,11 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr) osg::ref_ptr anim (new NpcAnimation(ptr, osg::ref_ptr(ptr.getRefData().getBaseNode()), mResourceSystem)); - ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr); - ptr.getClass().getInventoryStore(ptr).setContListener(anim.get()); - - mObjects.insert(std::make_pair(ptr, anim)); + if (mObjects.insert(std::make_pair(ptr, anim)).second) + { + ptr.getClass().getInventoryStore(ptr).setInvListener(anim.get(), ptr); + ptr.getClass().getInventoryStore(ptr).setContListener(anim.get()); + } } bool Objects::removeObject (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 8da01cc4b..c83165239 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -54,6 +54,12 @@ namespace void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { + if (ptr.getRefData().getBaseNode() || physics.getActor(ptr)) + { + std::cerr << "Warning: Tried to add " << ptr.getCellRef().getRefId() << " to the scene twice" << std::endl; + return; + } + bool useAnim = ptr.getClass().useAnim(); std::string model = ptr.getClass().getModel(ptr); if (useAnim) From 604f9ee32396387677b021d0a8981fa8c09c0057 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 1 Aug 2017 09:05:35 +0400 Subject: [PATCH 012/521] Split weapons and spells rating code from combat actions --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aicombataction.cpp | 683 +-------------------- apps/openmw/mwmechanics/aicombataction.hpp | 15 - apps/openmw/mwmechanics/spellpriority.cpp | 545 ++++++++++++++++ apps/openmw/mwmechanics/spellpriority.hpp | 32 + apps/openmw/mwmechanics/weaponpriority.cpp | 146 +++++ apps/openmw/mwmechanics/weaponpriority.hpp | 14 + 7 files changed, 749 insertions(+), 688 deletions(-) create mode 100644 apps/openmw/mwmechanics/spellpriority.cpp create mode 100644 apps/openmw/mwmechanics/spellpriority.hpp create mode 100644 apps/openmw/mwmechanics/weaponpriority.cpp create mode 100644 apps/openmw/mwmechanics/weaponpriority.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1aa311fd2..89b94ce12 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -84,7 +84,7 @@ add_openmw_dir (mwmechanics drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning - character actors objects aistate coordinateconverter trading aiface + character actors objects aistate coordinateconverter trading aiface weaponpriority spellpriority ) add_openmw_dir (mwstate diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 3e61b7463..1bfeff074 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -16,624 +16,25 @@ #include "npcstats.hpp" #include "spellcasting.hpp" #include "combat.hpp" - -namespace -{ - -// RangeTypes using bitflags to allow multiple range types, as can be the case with spells having multiple effects. -enum RangeTypes -{ - Self = 0x1, - Touch = 0x10, - Target = 0x100 -}; - -int getRangeTypes (const ESM::EffectList& effects) -{ - int types = 0; - for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) - { - if (it->mRange == ESM::RT_Self) - types |= Self; - else if (it->mRange == ESM::RT_Touch) - types |= Touch; - else if (it->mRange == ESM::RT_Target) - types |= Target; - } - return types; -} - -float suggestCombatRange(int rangeTypes) -{ - static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); - static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); - - // This distance is a possible distance of melee attack - static float distance = fCombatDistance * std::max(2.f, fHandToHandReach); - - if (rangeTypes & Touch) - { - return fCombatDistance; - } - - return distance * 4; -} - -int numEffectsToDispel (const MWWorld::Ptr& actor, int effectFilter=-1, bool negative = true) -{ - int toCure=0; - const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); - for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) - { - const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; - for (std::vector::const_iterator effectIt = params.mEffects.begin(); - effectIt != params.mEffects.end(); ++effectIt) - { - int effectId = effectIt->mEffectId; - if (effectFilter != -1 && effectId != effectFilter) - continue; - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectId); - - if (effectIt->mDuration <= 3) // Don't attempt to dispel if effect runs out shortly anyway - continue; - - if (negative && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - ++toCure; - - if (!negative && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) - ++toCure; - } - } - return toCure; -} - -} +#include "weaponpriority.hpp" +#include "spellpriority.hpp" namespace MWMechanics { - - float ratePotion (const MWWorld::Ptr &item, const MWWorld::Ptr& actor) - { - if (item.getTypeName() != typeid(ESM::Potion).name()) - return 0.f; - - const ESM::Potion* potion = item.get()->mBase; - return rateEffects(potion->mEffects, actor, MWWorld::Ptr()); - } - - float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type, - float arrowRating, float boltRating) - { - if (item.getTypeName() != typeid(ESM::Weapon).name()) - return 0.f; - - const ESM::Weapon* weapon = item.get()->mBase; - - if (type != -1 && weapon->mData.mType != type) - return 0.f; - - float rating=0.f; - float bonus=0.f; - - if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown) - { - // Range weapon is useless under water - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) - return 0.f; - - if (enemy.isEmpty()) - return 0.f; - - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) - return 0.f; - - bonus+=1.5f; - } - - if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) - { - rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f; - - if (weapon->mData.mType >= ESM::Weapon::MarksmanThrown) - MWMechanics::resistNormalWeapon(enemy, actor, item, rating); - } - else - { - for (int i=0; i<2; ++i) - { - rating += weapon->mData.mSlash[i]; - rating += weapon->mData.mThrust[i]; - rating += weapon->mData.mChop[i]; - } - rating /= 6.f; - - MWMechanics::resistNormalWeapon(enemy, actor, item, rating); - } - - if (item.getClass().hasItemHealth(item)) - { - if (item.getClass().getItemHealth(item) == 0) - return 0.f; - rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item)); - } - - if (weapon->mData.mType == ESM::Weapon::MarksmanBow) - { - if (arrowRating <= 0.f) - rating = 0.f; - else - rating += arrowRating; - } - else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - if (boltRating <= 0.f) - rating = 0.f; - else - rating += boltRating; - } - - if (!weapon->mEnchant.empty()) - { - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes - && (item.getCellRef().getEnchantmentCharge() == -1 - || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) - rating += rateEffects(enchantment->mEffects, actor, enemy); - } - - int skill = item.getClass().getEquipmentSkill(item); - if (skill != -1) - rating *= actor.getClass().getSkill(actor, skill) / 100.f; - - // There is no need to apply bonus if weapon rating == 0 - if (rating == 0.f) - return 0.f; - - return rating + bonus; - } - - float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) - { - const CreatureStats& stats = actor.getClass().getCreatureStats(actor); - - float successChance = MWMechanics::getSpellSuccessChance(spell, actor); - if (successChance == 0.f) - return 0.f; - - if (spell->mData.mType != ESM::Spell::ST_Spell) - return 0.f; - - // Don't make use of racial bonus spells, like MW. Can be made optional later - if (actor.getClass().isNpc()) - { - std::string raceid = actor.get()->mBase->mRace; - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); - if (race->mPowers.exists(spell->mId)) - return 0.f; - } - - if (spell->mData.mCost > stats.getMagicka().getCurrent()) - return 0.f; - - // Spells don't stack, so early out if the spell is still active on the target - int types = getRangeTypes(spell->mEffects); - if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId)) - return 0.f; - if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId)) - return 0.f; - - return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f); - } - - float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) - { - if (ptr.getClass().getEnchantment(ptr).empty()) - return 0.f; - - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(ptr.getClass().getEnchantment(ptr)); - - if (enchantment->mData.mType == ESM::Enchantment::CastOnce) - { - return rateEffects(enchantment->mEffects, actor, enemy); - } - else - { - //if (!ptr.getClass().canBeEquipped(ptr, actor)) - return 0.f; - } - } - - float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) + float suggestCombatRange(int rangeTypes) { - // NOTE: enemy may be empty - - float rating = 1; - switch (effect.mEffectID) - { - case ESM::MagicEffect::Soultrap: - case ESM::MagicEffect::AlmsiviIntervention: - case ESM::MagicEffect::DivineIntervention: - case ESM::MagicEffect::CalmHumanoid: - case ESM::MagicEffect::CalmCreature: - case ESM::MagicEffect::FrenzyHumanoid: - case ESM::MagicEffect::FrenzyCreature: - case ESM::MagicEffect::DemoralizeHumanoid: - case ESM::MagicEffect::DemoralizeCreature: - case ESM::MagicEffect::RallyHumanoid: - case ESM::MagicEffect::RallyCreature: - case ESM::MagicEffect::Charm: - case ESM::MagicEffect::DetectAnimal: - case ESM::MagicEffect::DetectEnchantment: - case ESM::MagicEffect::DetectKey: - case ESM::MagicEffect::Telekinesis: - case ESM::MagicEffect::Mark: - case ESM::MagicEffect::Recall: - case ESM::MagicEffect::Jump: - case ESM::MagicEffect::WaterBreathing: - case ESM::MagicEffect::SwiftSwim: - case ESM::MagicEffect::WaterWalking: - case ESM::MagicEffect::SlowFall: - case ESM::MagicEffect::Light: - case ESM::MagicEffect::Lock: - case ESM::MagicEffect::Open: - case ESM::MagicEffect::TurnUndead: - case ESM::MagicEffect::WeaknessToCommonDisease: - case ESM::MagicEffect::WeaknessToBlightDisease: - case ESM::MagicEffect::WeaknessToCorprusDisease: - case ESM::MagicEffect::CureCommonDisease: - case ESM::MagicEffect::CureBlightDisease: - case ESM::MagicEffect::CureCorprusDisease: - case ESM::MagicEffect::ResistBlightDisease: - case ESM::MagicEffect::ResistCommonDisease: - case ESM::MagicEffect::ResistCorprusDisease: - case ESM::MagicEffect::Invisibility: - case ESM::MagicEffect::Chameleon: - case ESM::MagicEffect::NightEye: - case ESM::MagicEffect::Vampirism: - case ESM::MagicEffect::StuntedMagicka: - case ESM::MagicEffect::ExtraSpell: - case ESM::MagicEffect::RemoveCurse: - case ESM::MagicEffect::CommandCreature: - case ESM::MagicEffect::CommandHumanoid: - return 0.f; - - case ESM::MagicEffect::Sound: - { - if (enemy.isEmpty()) - return 0.f; - - // there is no need to cast sound if enemy is not able to cast spells - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); - - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0) - return 0.f; - - if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) - return 0.f; - - break; - } - - case ESM::MagicEffect::RestoreAttribute: - return 0.f; // TODO: implement based on attribute damage - case ESM::MagicEffect::RestoreSkill: - return 0.f; // TODO: implement based on skill damage - - case ESM::MagicEffect::ResistFire: - case ESM::MagicEffect::ResistFrost: - case ESM::MagicEffect::ResistMagicka: - case ESM::MagicEffect::ResistNormalWeapons: - case ESM::MagicEffect::ResistParalysis: - case ESM::MagicEffect::ResistPoison: - case ESM::MagicEffect::ResistShock: - case ESM::MagicEffect::SpellAbsorption: - case ESM::MagicEffect::Reflect: - return 0.f; // probably useless since we don't know in advance what the enemy will cast - - // don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions - case ESM::MagicEffect::FortifyAttribute: - case ESM::MagicEffect::FortifyHealth: - case ESM::MagicEffect::FortifyMagicka: - case ESM::MagicEffect::FortifyFatigue: - case ESM::MagicEffect::FortifySkill: - case ESM::MagicEffect::FortifyMaximumMagicka: - case ESM::MagicEffect::FortifyAttack: - return 0.f; - - case ESM::MagicEffect::Burden: - { - if (enemy.isEmpty()) - return 0.f; - - // Ignore enemy without inventory - if (!enemy.getClass().hasInventoryStore(enemy)) - return 0.f; - - // burden makes sense only to overburden an enemy - float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy); - if (burden > 0) - return 0.f; - - if ((effect.mMagnMin + effect.mMagnMax)/2.f > -burden) - rating *= 3; - else - return 0.f; - - break; - } - - case ESM::MagicEffect::Feather: - { - // Ignore actors without inventory - if (!actor.getClass().hasInventoryStore(actor)) - return 0.f; - - // feather makes sense only for overburden actors - float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor); - if (burden <= 0) - return 0.f; - - if ((effect.mMagnMin + effect.mMagnMax)/2.f >= burden) - rating *= 3; - else - return 0.f; - - break; - } - - case ESM::MagicEffect::Levitate: - return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway - case ESM::MagicEffect::BoundBoots: - case ESM::MagicEffect::BoundHelm: - if (actor.getClass().isNpc()) - { - // Beast races can't wear helmets or boots - std::string raceid = actor.get()->mBase->mRace; - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); - if (race->mData.mFlags & ESM::Race::Beast) - return 0.f; - } - // Intended fall-through - // Creatures can not wear armor - case ESM::MagicEffect::BoundCuirass: - case ESM::MagicEffect::BoundGloves: - if (!actor.getClass().isNpc()) - return 0.f; - break; - - case ESM::MagicEffect::RestoreHealth: - case ESM::MagicEffect::RestoreMagicka: - case ESM::MagicEffect::RestoreFatigue: - if (effect.mRange == ESM::RT_Self) - { - int priority = 1; - if (effect.mEffectID == ESM::MagicEffect::RestoreHealth) - priority = 10; - const DynamicStat& current = actor.getClass().getCreatureStats(actor). - getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); - float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration; - // Effect doesn't heal more than we need, *or* we are below 1/2 health - if (current.getModified() - current.getCurrent() > toHeal - || current.getCurrent() < current.getModified()*0.5) - { - return 10000.f * priority - - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion - } - else - return -10000.f * priority; // Save for later - } - break; - - case ESM::MagicEffect::Dispel: - { - int numPositive = 0; - int numNegative = 0; - int diff = 0; - - if (effect.mRange == ESM::RT_Self) - { - numPositive = numEffectsToDispel(actor, -1, false); - numNegative = numEffectsToDispel(actor); - - diff = numNegative - numPositive; - } - else - { - if (enemy.isEmpty()) - return 0.f; - - numPositive = numEffectsToDispel(enemy, -1, false); - numNegative = numEffectsToDispel(enemy); - - diff = numPositive - numNegative; - - // if rating < 0 here, the spell will be considered as negative later - rating *= -1; - } - - if (diff <= 0) - return 0.f; - - rating *= (diff) / 5.f; - - break; - } - - // Prefer Cure effects over Dispel, because Dispel also removes positive effects - case ESM::MagicEffect::CureParalyzation: - return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze); - - case ESM::MagicEffect::CurePoison: - return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison); - case ESM::MagicEffect::DisintegrateArmor: - { - if (enemy.isEmpty()) - return 0.f; - - // Ignore enemy without inventory - if (!enemy.getClass().hasInventoryStore(enemy)) - return 0.f; - - MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy); - - // According to UESP - static const int armorSlots[] = { - MWWorld::InventoryStore::Slot_CarriedLeft, - MWWorld::InventoryStore::Slot_Cuirass, - MWWorld::InventoryStore::Slot_LeftPauldron, - MWWorld::InventoryStore::Slot_RightPauldron, - MWWorld::InventoryStore::Slot_LeftGauntlet, - MWWorld::InventoryStore::Slot_RightGauntlet, - MWWorld::InventoryStore::Slot_Helmet, - MWWorld::InventoryStore::Slot_Greaves, - MWWorld::InventoryStore::Slot_Boots - }; - - bool enemyHasArmor = false; - - // Ignore enemy without armor - for (unsigned int i=0; i= 0 && effect.mAttribute < ESM::Attribute::Length) - { - const float attributePriorities[ESM::Attribute::Length] = { - 1.0f, // Strength - 0.5f, // Intelligence - 0.6f, // Willpower - 0.7f, // Agility - 0.5f, // Speed - 0.8f, // Endurance - 0.7f, // Personality - 0.3f // Luck - }; - rating *= attributePriorities[effect.mAttribute]; - } - } - break; - - case ESM::MagicEffect::DamageSkill: - case ESM::MagicEffect::DrainSkill: - if (enemy.isEmpty() || !enemy.getClass().isNpc()) - return 0.f; - if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0) - return 0.f; - break; - - default: - break; - } - - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); - - // Underwater casting not possible - if (effect.mRange == ESM::RT_Target) - { - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) - return 0.f; - - if (enemy.isEmpty()) - return 0.f; - - if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) - return 0.f; - } - - if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - { - rating *= -1.f; - - if (enemy.isEmpty()) - return 0.f; - - // Check resistance for harmful effects - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); - - float resistance = MWMechanics::getEffectResistanceAttribute(effect.mEffectID, &stats.getMagicEffects()); + static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); + static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); - rating *= (1.f - std::min(resistance, 100.f) / 100.f); - } + // This distance is a possible distance of melee attack + static float distance = fCombatDistance * std::max(2.f, fHandToHandReach); - // for harmful no-magnitude effects (e.g. silence) check if enemy is already has them - // for non-harmful no-magnitude effects (e.g. bound items) check if actor is already has them - if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) + if (rangeTypes & RangeTypes::Touch) { - if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - { - CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); - - if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) - return 0.f; - } - else - { - CreatureStats& stats = actor.getClass().getCreatureStats(actor); - - if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) - return 0.f; - } + return fCombatDistance; } - rating *= calcEffectCost(effect); - - // Currently treating all "on target" or "on touch" effects to target the enemy actor. - // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. - if (effect.mRange != ESM::RT_Self) - rating *= -1.f; - - return rating; - } - - float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) - { - // NOTE: enemy may be empty - float rating = 0.f; - for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) - { - rating += rateEffect(*it, actor, enemy); - - if (it->mRange == ESM::RT_Target) - rating *= 1.5f; - } - return rating; + return distance * 4; } void ActionSpell::prepare(const MWWorld::Ptr &actor) @@ -655,7 +56,7 @@ namespace MWMechanics const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(mSpellId); int types = getRangeTypes(spell->mEffects); - isRanged = (types & Target) | (types & Self); + isRanged = (types & RangeTypes::Target) | (types & RangeTypes::Self); return suggestCombatRange(types); } @@ -1106,67 +507,6 @@ namespace MWMechanics return true; } - float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) - { - const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - - static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); - static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); - - float mult = fAIMagicSpellMult; - - for (std::vector::const_iterator effectIt = - spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt) - { - if (effectIt->mRange == ESM::RT_Target) - { - if (!MWBase::Environment::get().getWorld()->isSwimming(enemy)) - mult = fAIRangeMagicSpellMult; - else - mult = 0.0f; - break; - } - } - - return MWMechanics::getSpellSuccessChance(spell, actor) * mult; - } - - float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) - { - const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - - static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat(); - static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat(); - static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat(); - - if (weapon.isEmpty()) - return 0.f; - - float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f; - float chopMult = fAIMeleeWeaponMult; - float bonusDamage = 0.f; - - const ESM::Weapon* esmWeap = weapon.get()->mBase; - - if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) - { - if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) - { - bonusDamage = ammo.get()->mBase->mData.mChop[1]; - chopMult = fAIRangeMeleeWeaponMult; - } - else - chopMult = 0.f; - } - - float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult; - float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult; - float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult; - - return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult - + std::max(std::max(chopRating, slashRating), thrustRating); - } - float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) { const CreatureStats& stats = actor.getClass().getCreatureStats(actor); @@ -1212,5 +552,4 @@ namespace MWMechanics return false; } - } diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index 393bd9f5d..dc6f359d6 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -10,7 +10,6 @@ namespace MWMechanics { - class Action { public: @@ -88,18 +87,6 @@ namespace MWMechanics virtual const ESM::Weapon* getWeapon() const; }; - float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor); - /// @param type Skip all weapons that are not of this type (i.e. return rating 0) - float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, - int type=-1, float arrowRating=0.f, float boltRating=0.f); - - /// @note target may be empty - float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - /// @note target may be empty - float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - std::shared_ptr prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); float getBestActionRating(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy); @@ -107,8 +94,6 @@ namespace MWMechanics float getMaxAttackDistance(const MWWorld::Ptr& actor); bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); - float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating); } diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp new file mode 100644 index 000000000..a73e4fd89 --- /dev/null +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -0,0 +1,545 @@ +#include "spellpriority.hpp" + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/actionequip.hpp" +#include "../mwworld/cellstore.hpp" + +#include "npcstats.hpp" +#include "spellcasting.hpp" +#include "combat.hpp" + +namespace +{ + int numEffectsToDispel (const MWWorld::Ptr& actor, int effectFilter=-1, bool negative = true) + { + int toCure=0; + const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); + for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) + { + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; + for (std::vector::const_iterator effectIt = params.mEffects.begin(); + effectIt != params.mEffects.end(); ++effectIt) + { + int effectId = effectIt->mEffectId; + if (effectFilter != -1 && effectId != effectFilter) + continue; + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectId); + + if (effectIt->mDuration <= 3) // Don't attempt to dispel if effect runs out shortly anyway + continue; + + if (negative && magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + ++toCure; + + if (!negative && !(magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)) + ++toCure; + } + } + return toCure; + } +} + +namespace MWMechanics +{ + int getRangeTypes (const ESM::EffectList& effects) + { + int types = 0; + for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) + { + if (it->mRange == ESM::RT_Self) + types |= RangeTypes::Self; + else if (it->mRange == ESM::RT_Touch) + types |= RangeTypes::Touch; + else if (it->mRange == ESM::RT_Target) + types |= RangeTypes::Target; + } + return types; + } + + float ratePotion (const MWWorld::Ptr &item, const MWWorld::Ptr& actor) + { + if (item.getTypeName() != typeid(ESM::Potion).name()) + return 0.f; + + const ESM::Potion* potion = item.get()->mBase; + return rateEffects(potion->mEffects, actor, MWWorld::Ptr()); + } + + float rateSpell(const ESM::Spell *spell, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) + { + const CreatureStats& stats = actor.getClass().getCreatureStats(actor); + + float successChance = MWMechanics::getSpellSuccessChance(spell, actor); + if (successChance == 0.f) + return 0.f; + + if (spell->mData.mType != ESM::Spell::ST_Spell) + return 0.f; + + // Don't make use of racial bonus spells, like MW. Can be made optional later + if (actor.getClass().isNpc()) + { + std::string raceid = actor.get()->mBase->mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); + if (race->mPowers.exists(spell->mId)) + return 0.f; + } + + if (spell->mData.mCost > stats.getMagicka().getCurrent()) + return 0.f; + + // Spells don't stack, so early out if the spell is still active on the target + int types = getRangeTypes(spell->mEffects); + if ((types & Self) && stats.getActiveSpells().isSpellActive(spell->mId)) + return 0.f; + if ( ((types & Touch) || (types & Target)) && enemy.getClass().getCreatureStats(enemy).getActiveSpells().isSpellActive(spell->mId)) + return 0.f; + + return rateEffects(spell->mEffects, actor, enemy) * (successChance / 100.f); + } + + float rateMagicItem(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor, const MWWorld::Ptr& enemy) + { + if (ptr.getClass().getEnchantment(ptr).empty()) + return 0.f; + + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(ptr.getClass().getEnchantment(ptr)); + + if (enchantment->mData.mType == ESM::Enchantment::CastOnce) + { + return rateEffects(enchantment->mEffects, actor, enemy); + } + else + { + //if (!ptr.getClass().canBeEquipped(ptr, actor)) + return 0.f; + } + } + + float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) + { + // NOTE: enemy may be empty + + float rating = 1; + switch (effect.mEffectID) + { + case ESM::MagicEffect::Soultrap: + case ESM::MagicEffect::AlmsiviIntervention: + case ESM::MagicEffect::DivineIntervention: + case ESM::MagicEffect::CalmHumanoid: + case ESM::MagicEffect::CalmCreature: + case ESM::MagicEffect::FrenzyHumanoid: + case ESM::MagicEffect::FrenzyCreature: + case ESM::MagicEffect::DemoralizeHumanoid: + case ESM::MagicEffect::DemoralizeCreature: + case ESM::MagicEffect::RallyHumanoid: + case ESM::MagicEffect::RallyCreature: + case ESM::MagicEffect::Charm: + case ESM::MagicEffect::DetectAnimal: + case ESM::MagicEffect::DetectEnchantment: + case ESM::MagicEffect::DetectKey: + case ESM::MagicEffect::Telekinesis: + case ESM::MagicEffect::Mark: + case ESM::MagicEffect::Recall: + case ESM::MagicEffect::Jump: + case ESM::MagicEffect::WaterBreathing: + case ESM::MagicEffect::SwiftSwim: + case ESM::MagicEffect::WaterWalking: + case ESM::MagicEffect::SlowFall: + case ESM::MagicEffect::Light: + case ESM::MagicEffect::Lock: + case ESM::MagicEffect::Open: + case ESM::MagicEffect::TurnUndead: + case ESM::MagicEffect::WeaknessToCommonDisease: + case ESM::MagicEffect::WeaknessToBlightDisease: + case ESM::MagicEffect::WeaknessToCorprusDisease: + case ESM::MagicEffect::CureCommonDisease: + case ESM::MagicEffect::CureBlightDisease: + case ESM::MagicEffect::CureCorprusDisease: + case ESM::MagicEffect::ResistBlightDisease: + case ESM::MagicEffect::ResistCommonDisease: + case ESM::MagicEffect::ResistCorprusDisease: + case ESM::MagicEffect::Invisibility: + case ESM::MagicEffect::Chameleon: + case ESM::MagicEffect::NightEye: + case ESM::MagicEffect::Vampirism: + case ESM::MagicEffect::StuntedMagicka: + case ESM::MagicEffect::ExtraSpell: + case ESM::MagicEffect::RemoveCurse: + case ESM::MagicEffect::CommandCreature: + case ESM::MagicEffect::CommandHumanoid: + return 0.f; + + case ESM::MagicEffect::Sound: + { + if (enemy.isEmpty()) + return 0.f; + + // there is no need to cast sound if enemy is not able to cast spells + CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude() > 0) + return 0.f; + + if (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) + return 0.f; + + break; + } + + case ESM::MagicEffect::RestoreAttribute: + return 0.f; // TODO: implement based on attribute damage + case ESM::MagicEffect::RestoreSkill: + return 0.f; // TODO: implement based on skill damage + + case ESM::MagicEffect::ResistFire: + case ESM::MagicEffect::ResistFrost: + case ESM::MagicEffect::ResistMagicka: + case ESM::MagicEffect::ResistNormalWeapons: + case ESM::MagicEffect::ResistParalysis: + case ESM::MagicEffect::ResistPoison: + case ESM::MagicEffect::ResistShock: + case ESM::MagicEffect::SpellAbsorption: + case ESM::MagicEffect::Reflect: + return 0.f; // probably useless since we don't know in advance what the enemy will cast + + // don't cast these for now as they would make the NPC cast the same effect over and over again, especially when they have potions + case ESM::MagicEffect::FortifyAttribute: + case ESM::MagicEffect::FortifyHealth: + case ESM::MagicEffect::FortifyMagicka: + case ESM::MagicEffect::FortifyFatigue: + case ESM::MagicEffect::FortifySkill: + case ESM::MagicEffect::FortifyMaximumMagicka: + case ESM::MagicEffect::FortifyAttack: + return 0.f; + + case ESM::MagicEffect::Burden: + { + if (enemy.isEmpty()) + return 0.f; + + // Ignore enemy without inventory + if (!enemy.getClass().hasInventoryStore(enemy)) + return 0.f; + + // burden makes sense only to overburden an enemy + float burden = enemy.getClass().getEncumbrance(enemy) - enemy.getClass().getCapacity(enemy); + if (burden > 0) + return 0.f; + + if ((effect.mMagnMin + effect.mMagnMax)/2.f > -burden) + rating *= 3; + else + return 0.f; + + break; + } + + case ESM::MagicEffect::Feather: + { + // Ignore actors without inventory + if (!actor.getClass().hasInventoryStore(actor)) + return 0.f; + + // feather makes sense only for overburden actors + float burden = actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor); + if (burden <= 0) + return 0.f; + + if ((effect.mMagnMin + effect.mMagnMax)/2.f >= burden) + rating *= 3; + else + return 0.f; + + break; + } + + case ESM::MagicEffect::Levitate: + return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway + case ESM::MagicEffect::BoundBoots: + case ESM::MagicEffect::BoundHelm: + if (actor.getClass().isNpc()) + { + // Beast races can't wear helmets or boots + std::string raceid = actor.get()->mBase->mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceid); + if (race->mData.mFlags & ESM::Race::Beast) + return 0.f; + } + // Intended fall-through + // Creatures can not wear armor + case ESM::MagicEffect::BoundCuirass: + case ESM::MagicEffect::BoundGloves: + if (!actor.getClass().isNpc()) + return 0.f; + break; + + case ESM::MagicEffect::RestoreHealth: + case ESM::MagicEffect::RestoreMagicka: + case ESM::MagicEffect::RestoreFatigue: + if (effect.mRange == ESM::RT_Self) + { + int priority = 1; + if (effect.mEffectID == ESM::MagicEffect::RestoreHealth) + priority = 10; + const DynamicStat& current = actor.getClass().getCreatureStats(actor). + getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); + float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration; + // Effect doesn't heal more than we need, *or* we are below 1/2 health + if (current.getModified() - current.getCurrent() > toHeal + || current.getCurrent() < current.getModified()*0.5) + { + return 10000.f * priority + - (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion + } + else + return -10000.f * priority; // Save for later + } + break; + + case ESM::MagicEffect::Dispel: + { + int numPositive = 0; + int numNegative = 0; + int diff = 0; + + if (effect.mRange == ESM::RT_Self) + { + numPositive = numEffectsToDispel(actor, -1, false); + numNegative = numEffectsToDispel(actor); + + diff = numNegative - numPositive; + } + else + { + if (enemy.isEmpty()) + return 0.f; + + numPositive = numEffectsToDispel(enemy, -1, false); + numNegative = numEffectsToDispel(enemy); + + diff = numPositive - numNegative; + + // if rating < 0 here, the spell will be considered as negative later + rating *= -1; + } + + if (diff <= 0) + return 0.f; + + rating *= (diff) / 5.f; + + break; + } + + // Prefer Cure effects over Dispel, because Dispel also removes positive effects + case ESM::MagicEffect::CureParalyzation: + return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Paralyze); + + case ESM::MagicEffect::CurePoison: + return 1001.f * numEffectsToDispel(actor, ESM::MagicEffect::Poison); + case ESM::MagicEffect::DisintegrateArmor: + { + if (enemy.isEmpty()) + return 0.f; + + // Ignore enemy without inventory + if (!enemy.getClass().hasInventoryStore(enemy)) + return 0.f; + + MWWorld::InventoryStore& inv = enemy.getClass().getInventoryStore(enemy); + + // According to UESP + static const int armorSlots[] = { + MWWorld::InventoryStore::Slot_CarriedLeft, + MWWorld::InventoryStore::Slot_Cuirass, + MWWorld::InventoryStore::Slot_LeftPauldron, + MWWorld::InventoryStore::Slot_RightPauldron, + MWWorld::InventoryStore::Slot_LeftGauntlet, + MWWorld::InventoryStore::Slot_RightGauntlet, + MWWorld::InventoryStore::Slot_Helmet, + MWWorld::InventoryStore::Slot_Greaves, + MWWorld::InventoryStore::Slot_Boots + }; + + bool enemyHasArmor = false; + + // Ignore enemy without armor + for (unsigned int i=0; i= 0 && effect.mAttribute < ESM::Attribute::Length) + { + const float attributePriorities[ESM::Attribute::Length] = { + 1.0f, // Strength + 0.5f, // Intelligence + 0.6f, // Willpower + 0.7f, // Agility + 0.5f, // Speed + 0.8f, // Endurance + 0.7f, // Personality + 0.3f // Luck + }; + rating *= attributePriorities[effect.mAttribute]; + } + } + break; + + case ESM::MagicEffect::DamageSkill: + case ESM::MagicEffect::DrainSkill: + if (enemy.isEmpty() || !enemy.getClass().isNpc()) + return 0.f; + if (enemy.getClass().getNpcStats(enemy).getSkill(effect.mSkill).getModified() <= 0) + return 0.f; + break; + + default: + break; + } + + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); + + // Underwater casting not possible + if (effect.mRange == ESM::RT_Target) + { + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) + return 0.f; + + if (enemy.isEmpty()) + return 0.f; + + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) + return 0.f; + } + + if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + { + rating *= -1.f; + + if (enemy.isEmpty()) + return 0.f; + + // Check resistance for harmful effects + CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + float resistance = MWMechanics::getEffectResistanceAttribute(effect.mEffectID, &stats.getMagicEffects()); + + rating *= (1.f - std::min(resistance, 100.f) / 100.f); + } + + // for harmful no-magnitude effects (e.g. silence) check if enemy is already has them + // for non-harmful no-magnitude effects (e.g. bound items) check if actor is already has them + if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) + { + if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) + { + CreatureStats& stats = enemy.getClass().getCreatureStats(enemy); + + if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) + return 0.f; + } + else + { + CreatureStats& stats = actor.getClass().getCreatureStats(actor); + + if (stats.getMagicEffects().get(effect.mEffectID).getMagnitude() > 0) + return 0.f; + } + } + + rating *= calcEffectCost(effect); + + // Currently treating all "on target" or "on touch" effects to target the enemy actor. + // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. + if (effect.mRange != ESM::RT_Self) + rating *= -1.f; + + return rating; + } + + float rateEffects(const ESM::EffectList &list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + // NOTE: enemy may be empty + float rating = 0.f; + for (std::vector::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) + { + rating += rateEffect(*it, actor, enemy); + + if (it->mRange == ESM::RT_Target) + rating *= 1.5f; + } + return rating; + } + + float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); + static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); + + float mult = fAIMagicSpellMult; + + for (std::vector::const_iterator effectIt = + spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mRange == ESM::RT_Target) + { + if (!MWBase::Environment::get().getWorld()->isSwimming(enemy)) + mult = fAIRangeMagicSpellMult; + else + mult = 0.0f; + break; + } + } + + return MWMechanics::getSpellSuccessChance(spell, actor) * mult; + } +} diff --git a/apps/openmw/mwmechanics/spellpriority.hpp b/apps/openmw/mwmechanics/spellpriority.hpp new file mode 100644 index 000000000..4e5ff5c71 --- /dev/null +++ b/apps/openmw/mwmechanics/spellpriority.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_SPELL_PRIORITY_H +#define OPENMW_SPELL_PRIORITY_H + +#include + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + // RangeTypes using bitflags to allow multiple range types, as can be the case with spells having multiple effects. + enum RangeTypes + { + Self = 0x1, + Touch = 0x10, + Target = 0x100 + }; + + int getRangeTypes (const ESM::EffectList& effects); + + float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float rateMagicItem (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float ratePotion (const MWWorld::Ptr& item, const MWWorld::Ptr &actor); + + /// @note target may be empty + float rateEffect (const ESM::ENAMstruct& effect, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + /// @note target may be empty + float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + + float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); +} + +#endif diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp new file mode 100644 index 000000000..07cf6ff5f --- /dev/null +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -0,0 +1,146 @@ +#include "weaponpriority.hpp" + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" + +#include "npcstats.hpp" +#include "combat.hpp" +#include "aicombataction.hpp" +#include "spellpriority.hpp" + +namespace MWMechanics +{ + float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, int type, + float arrowRating, float boltRating) + { + if (item.getTypeName() != typeid(ESM::Weapon).name()) + return 0.f; + + const ESM::Weapon* weapon = item.get()->mBase; + + if (type != -1 && weapon->mData.mType != type) + return 0.f; + + float rating=0.f; + float bonus=0.f; + + if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown) + { + // Range weapon is useless under water + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)) + return 0.f; + + if (enemy.isEmpty()) + return 0.f; + + if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(enemy), 0.75f)) + return 0.f; + + bonus+=1.5f; + } + + if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) + { + rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f; + + if (weapon->mData.mType >= ESM::Weapon::MarksmanThrown) + MWMechanics::resistNormalWeapon(enemy, actor, item, rating); + } + else + { + for (int i=0; i<2; ++i) + { + rating += weapon->mData.mSlash[i]; + rating += weapon->mData.mThrust[i]; + rating += weapon->mData.mChop[i]; + } + rating /= 6.f; + + MWMechanics::resistNormalWeapon(enemy, actor, item, rating); + } + + if (item.getClass().hasItemHealth(item)) + { + if (item.getClass().getItemHealth(item) == 0) + return 0.f; + rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item)); + } + + if (weapon->mData.mType == ESM::Weapon::MarksmanBow) + { + if (arrowRating <= 0.f) + rating = 0.f; + else + rating += arrowRating; + } + else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + if (boltRating <= 0.f) + rating = 0.f; + else + rating += boltRating; + } + + if (!weapon->mEnchant.empty()) + { + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); + if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes + && (item.getCellRef().getEnchantmentCharge() == -1 + || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) + rating += rateEffects(enchantment->mEffects, actor, enemy); + } + + int skill = item.getClass().getEquipmentSkill(item); + if (skill != -1) + rating *= actor.getClass().getSkill(actor, skill) / 100.f; + + // There is no need to apply bonus if weapon rating == 0 + if (rating == 0.f) + return 0.f; + + return rating + bonus; + } + + float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat(); + static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat(); + static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat(); + + if (weapon.isEmpty()) + return 0.f; + + float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f; + float chopMult = fAIMeleeWeaponMult; + float bonusDamage = 0.f; + + const ESM::Weapon* esmWeap = weapon.get()->mBase; + + if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) + { + if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) + { + bonusDamage = ammo.get()->mBase->mData.mChop[1]; + chopMult = fAIRangeMeleeWeaponMult; + } + else + chopMult = 0.f; + } + + float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult; + float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult; + float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult; + + return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult + + std::max(std::max(chopRating, slashRating), thrustRating); + } + +} diff --git a/apps/openmw/mwmechanics/weaponpriority.hpp b/apps/openmw/mwmechanics/weaponpriority.hpp new file mode 100644 index 000000000..90a767c4a --- /dev/null +++ b/apps/openmw/mwmechanics/weaponpriority.hpp @@ -0,0 +1,14 @@ +#ifndef OPENMW_WEAPON_PRIORITY_H +#define OPENMW_WEAPON_PRIORITY_H + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, + int type=-1, float arrowRating=0.f, float boltRating=0.f); + + float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); +} + +#endif From ffcdedced346871a444830ac9234a0ec8db83c37 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 1 Aug 2017 20:35:10 +0200 Subject: [PATCH 013/521] [macOS, CI] Use FTP URL from environment This URL is also subject to change, moving to Travis settings. --- CI/deploy.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/deploy.osx.sh b/CI/deploy.osx.sh index 1ff6f89c3..53bfa18b5 100755 --- a/CI/deploy.osx.sh +++ b/CI/deploy.osx.sh @@ -6,4 +6,4 @@ DATE=`date +'%d%m%Y'` SHORT_COMMIT=`git rev-parse --short ${TRAVIS_COMMIT}` TARGET_FILENAME="OpenMW-${DATE}-${SHORT_COMMIT}.dmg" -curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "ftp://s3.mydevil.net:21/nightly/${TARGET_FILENAME}" +curl --ssl --ftp-create-dirs -T *.dmg -u $OSX_FTP_USER:$OSX_FTP_PASSWORD "${OSX_FTP_URL}${TARGET_FILENAME}" From 748f5225a914907db2e918ef9a07153b002a0207 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 2 Aug 2017 02:20:27 +0300 Subject: [PATCH 014/521] Copy PathFinder::mPath back value when pass to MWMechanics::AiPackage::pathTo as dest May become dangling reference because method may remove all elements from mPath. --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index baf4efc03..b44b187ad 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -489,7 +489,7 @@ namespace MWMechanics float duration, AiWanderStorage& storage, ESM::Position& pos) { // Is there no destination or are we there yet? - if ((!mPathFinder.isPathConstructed()) || pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE)) + if ((!mPathFinder.isPathConstructed()) || pathTo(actor, ESM::Pathgrid::Point(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE)) { stopWalking(actor, storage); storage.setState(Wander_ChooseAction); From cb32f1d60ada705ce25151ea1a36538a4ccfc34c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 2 Aug 2017 16:05:05 +0000 Subject: [PATCH 015/521] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 6125ed36d..8aaa6cf73 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -50,6 +50,7 @@ Programmers Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 + elsid Emanuel Guével (potatoesmaster) eroen escondida From 3cfd9af94591bf00386c70c32fdafe2d31fa2d06 Mon Sep 17 00:00:00 2001 From: Julian Date: Wed, 2 Aug 2017 18:54:16 +0200 Subject: [PATCH 016/521] merge redundant input events --- components/sdlutil/sdlinputwrapper.cpp | 33 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index ac172b84b..56411ca88 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -49,17 +49,42 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v SDL_PumpEvents(); - SDL_Event evt; + SDL_Event event; if (windowEventsOnly) { // During loading, just handle window events, and keep others for later - while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) - handleWindowEvent(evt); + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) + handleWindowEvent(event); return; } - while(SDL_PollEvent(&evt)) + // Merge redundant events to avoid unnecessary listener calls + std::vector events; + while(SDL_PollEvent(&event)) { + if (events.empty() || events.back().type != event.type) + { + events.emplace_back(event); + continue; + } + + SDL_Event& previousEvent = events.back(); + + switch (event.type) + { + case SDL_MOUSEMOTION: + previousEvent.motion.x = event.motion.x; + previousEvent.motion.y = event.motion.y; + previousEvent.motion.xrel += event.motion.xrel; + previousEvent.motion.yrel += event.motion.yrel; + break; + default: + events.emplace_back(event); + } + } + + + for (const SDL_Event& evt : events) { switch(evt.type) { From 2fdffb1995ae920c0dfa800b270fce1417ac83ce Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 2 Aug 2017 18:05:33 -0500 Subject: [PATCH 017/521] Adding myself to Authors.md I've had a few pull requests merged, so I assume I'm ready to be added. --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8aaa6cf73..95c741eab 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -146,6 +146,7 @@ Programmers t6 terrorfisch Thomas Luppi (Digmaster) + Will Herrmann (Thunderforge) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) viadanna From 487e72fd23f527cd3288a18bb60a6a4f17647147 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 18:39:59 +0400 Subject: [PATCH 018/521] Play Up sounds instead of Down ones in trade window (bug #3982) --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index c6b8a4bd7..8b0f895d1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -320,7 +320,7 @@ namespace MWGui { ensureSelectedItemUnequipped(count); const ItemStack& item = mTradeModel->getItem(mSelectedItem); - std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); + std::string sound = item.mBase.getClass().getUpSoundId(item.mBase); MWBase::Environment::get().getWindowManager()->playSound(sound); if (item.mType == ItemStack::Type_Barter) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 5f4433a47..e05848ef8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -209,7 +209,7 @@ namespace MWGui void TradeWindow::sellItem(MyGUI::Widget* sender, int count) { const ItemStack& item = mTradeModel->getItem(mItemToSell); - std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); + std::string sound = item.mBase.getClass().getUpSoundId(item.mBase); MWBase::Environment::get().getWindowManager()->playSound(sound); TradeItemModel* playerTradeModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel(); From 35beede0658c3993def9bc2099af529b0019fc07 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 18:41:13 +0400 Subject: [PATCH 019/521] Restock items after trade deal instead of trade window opening --- apps/openmw/mwgui/tradewindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e05848ef8..f82d2f68d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -122,8 +122,6 @@ namespace MWGui mCurrentBalance = 0; mCurrentMerchantOffer = 0; - restock(); - std::vector itemSources; MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); @@ -357,6 +355,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + + restock(); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) From d1489f5b42a59c8d0d8fb9112b481409bb6a36d8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 19:12:21 +0400 Subject: [PATCH 020/521] Take in account a temporary disposition in isAggressive check (bug #3987) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 62ac9bd40..751f8d164 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1490,7 +1490,7 @@ namespace MWMechanics { int disposition = 50; if (ptr.getClass().isNpc()) - disposition = getDerivedDisposition(ptr, false); + disposition = getDerivedDisposition(ptr, true); int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast(disposition)))); From 56a30d7aeccefe15a6172089d47f648bc75995bb Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 3 Aug 2017 20:27:14 +0400 Subject: [PATCH 021/521] Journalbook layout fixes --- apps/openmw/mwgui/journalbooks.cpp | 10 +++++----- apps/openmw/mwgui/journalwindow.cpp | 8 ++++---- files/mygui/openmw_journal.layout | 16 ++++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 5634eb080..a1d74fab6 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -82,7 +82,7 @@ namespace AddEntry::operator () (entry); - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (30); } }; @@ -107,7 +107,7 @@ namespace mTypesetter->selectContent (mContentId); mTypesetter->write (mBodyStyle, 2, 3);// end quote - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (30); } }; @@ -121,7 +121,7 @@ namespace void operator () (MWGui::JournalViewModel::Utf8Span topicName) { mTypesetter->write (mBodyStyle, topicName); - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (); } }; @@ -135,7 +135,7 @@ namespace void operator () (MWGui::JournalViewModel::Utf8Span topicName) { mTypesetter->write (mBodyStyle, topicName); - mTypesetter->sectionBreak (10); + mTypesetter->sectionBreak (); } }; } @@ -250,7 +250,7 @@ book JournalBooks::createTopicIndexBook () BookTypesetter::Ptr JournalBooks::createTypesetter () { //TODO: determine page size from layout... - return BookTypesetter::create (240, 300); + return BookTypesetter::create (240, 320); } } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 105f95085..e96cc8b70 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -187,12 +187,12 @@ namespace } adjustButton(TopicsBTN); - int width = getWidget(TopicsBTN)->getSize().width + getWidget(QuestsBTN)->getSize().width; int topicsWidth = getWidget(TopicsBTN)->getSize().width; - int pageWidth = getWidget(RightBookPage)->getSize().width; + int cancelLeft = getWidget(CancelBTN)->getPosition().left; + int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(TopicsBTN)->setPosition((pageWidth - width)/2, getWidget(TopicsBTN)->getPosition().top); - getWidget(QuestsBTN)->setPosition((pageWidth - width)/2 + topicsWidth, getWidget(QuestsBTN)->getPosition().top); + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); mQuestMode = false; mAllQuests = false; diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index c53f39578..1131b1bbc 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -49,33 +49,33 @@ - - + + - + - + - + - + - + @@ -88,7 +88,7 @@ - + From c920d083e421f947a33c04203dbb49556ef88aaf Mon Sep 17 00:00:00 2001 From: Siimacore Date: Thu, 3 Aug 2017 23:15:26 +0200 Subject: [PATCH 022/521] Correcting https://bugs.openmw.org/issues/3906. --- apps/launcher/maindialog.cpp | 10 +++++++++- apps/launcher/maindialog.hpp | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 94e186db8..31da90d2f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -172,7 +172,10 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() } } - return setup() ? FirstRunDialogResultContinue : FirstRunDialogResultFailure; + if (!setup() || !setupGameData()) { + return FirstRunDialogResultFailure; + } + return FirstRunDialogResultContinue; } void Launcher::MainDialog::setVersionLabel() @@ -344,6 +347,11 @@ bool Launcher::MainDialog::setupGameSettings() file.close(); } + return true; +} + +bool Launcher::MainDialog::setupGameData() +{ QStringList dataDirs; // Check if the paths actually contain data files diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 96b5c0b97..8d0d61b8f 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -72,6 +72,7 @@ namespace Launcher bool setupLauncherSettings(); bool setupGameSettings(); bool setupGraphicsSettings(); + bool setupGameData(); void setVersionLabel(); From 23bda7613beb1257a01690d4462d0d7375b0f63a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 4 Aug 2017 07:31:41 +0400 Subject: [PATCH 023/521] Do not allow to use journal in a main menu (bug #3991) --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7b2a1560d..a823ae0fd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1022,6 +1022,7 @@ namespace MWInput return; if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { MWBase::Environment::get().getWindowManager()->playSound ("book open"); From 63343b6241de45a6db433d33aa2788ac78eb6aea Mon Sep 17 00:00:00 2001 From: Jake Westrip Date: Sat, 5 Aug 2017 06:15:15 +1000 Subject: [PATCH 024/521] Ensure jail does not decrease a skill past zero --- apps/openmw/mwgui/jailscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 211e0c5f9..8ac133d76 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -93,7 +93,7 @@ namespace MWGui if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak) value.setBase(std::min(100, value.getBase()+1)); else - value.setBase(value.getBase()-1); + value.setBase(std::max(0, value.getBase()-1)); } const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); From bf70b97f899730db4bba06b270cbf52f9ab48a98 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 4 Aug 2017 21:44:20 +0000 Subject: [PATCH 025/521] Update AUTHORS.md --- AUTHORS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 95c741eab..2a10cbc2b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -62,8 +62,8 @@ Programmers Hallfaer Tuilinn hristoast Internecine - Jacob Essex (Yacoby) - Jannik Heller (scrawl) + Jacob Essex (Yacoby) + Jake Westrip (16bitint) Jason Hooks (jhooks) jeaye Jeffrey Haines (Jyby) @@ -132,6 +132,7 @@ Programmers Roman Proskuryakov (kpp) Sandy Carter (bwrsandman) Scott Howard + scrawl Sebastian Wick (swick) Sergey Shambir ShadowRadiance From cf7a6232d021050d327b905ea16c2ef8995c488e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 1 Aug 2017 21:42:49 +0400 Subject: [PATCH 026/521] Combat AI: use WhenUsed enchantments --- apps/openmw/mwmechanics/aicombataction.cpp | 2 + apps/openmw/mwmechanics/aicombataction.hpp | 4 +- apps/openmw/mwmechanics/spellpriority.cpp | 50 ++++++++++++++++++++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 1bfeff074..d44498966 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -71,6 +71,8 @@ namespace MWMechanics { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(mItem->getClass().getEnchantment(*mItem)); int types = getRangeTypes(enchantment->mEffects); + + isRanged = (types & RangeTypes::Target) | (types & RangeTypes::Self); return suggestCombatRange(types); } diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index dc6f359d6..466ae2dc4 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -54,7 +54,7 @@ namespace MWMechanics virtual float getCombatRange (bool& isRanged) const; /// Since this action has no animation, apply a small cool down for using it - virtual float getActionCooldown() { return 1.f; } + virtual float getActionCooldown() { return 0.75f; } }; class ActionPotion : public Action @@ -68,7 +68,7 @@ namespace MWMechanics virtual bool isAttackingOrSpell() const { return false; } /// Since this action has no animation, apply a small cool down for using it - virtual float getActionCooldown() { return 1.f; } + virtual float getActionCooldown() { return 0.75f; } }; class ActionWeapon : public Action diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index a73e4fd89..a56f430c6 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -46,6 +46,26 @@ namespace } return toCure; } + + float getSpellDuration (const MWWorld::Ptr& actor, const std::string& spellId) + { + float duration = 0; + const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); + for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) + { + if (it->first != spellId) + continue; + + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; + for (std::vector::const_iterator effectIt = params.mEffects.begin(); + effectIt != params.mEffects.end(); ++effectIt) + { + if (effectIt->mDuration > duration) + duration = effectIt->mDuration; + } + } + return duration; + } } namespace MWMechanics @@ -114,15 +134,39 @@ namespace MWMechanics const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(ptr.getClass().getEnchantment(ptr)); + // Spells don't stack, so early out if the spell is still active on the target + int types = getRangeTypes(enchantment->mEffects); + if ((types & Self) && actor.getClass().getCreatureStats(actor).getActiveSpells().isSpellActive(ptr.getCellRef().getRefId())) + return 0.f; + + if (types & (Touch|Target) && getSpellDuration(enemy, ptr.getCellRef().getRefId()) > 3) + return 0.f; + if (enchantment->mData.mType == ESM::Enchantment::CastOnce) { return rateEffects(enchantment->mEffects, actor, enemy); } - else + else if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - //if (!ptr.getClass().canBeEquipped(ptr, actor)) - return 0.f; + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + + // Creatures can not wear armor/clothing, so allow creatures to use non-equipped items, + if (actor.getClass().isNpc() && !store.isEquipped(ptr)) + return 0.f; + + int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), actor); + + if (ptr.getCellRef().getEnchantmentCharge() != -1 + && ptr.getCellRef().getEnchantmentCharge() < castCost) + return 0.f; + + float rating = rateEffects(enchantment->mEffects, actor, enemy); + + rating *= 2; // prefer rechargable magic items over spells + return rating; } + + return 0.f; } float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy) From 72ce118d02ee3691be45eab187d85b16311136f3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 5 Aug 2017 12:38:26 +0400 Subject: [PATCH 027/521] Disable AiPursue package for player's followers --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 62ac9bd40..2f217ab12 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1152,7 +1152,19 @@ namespace MWMechanics it->getClass().getNpcStats(*it).setCrimeId(id); if (!it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) + { + // Player's followers should not try to arrest player + if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) + { + std::set playerFollowers; + getActorsSidingWith(player, playerFollowers); + + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + } + it->getClass().getCreatureStats(*it).getAiSequence().stack(AiPursue(player), *it); + } } else { From 393f4ab75834e41a1f1c0652ba21031cbb1d2d82 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 6 Aug 2017 13:02:22 +0200 Subject: [PATCH 028/521] Add missing include for isatty function (Fixes #4002) --- apps/openmw/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index a7e522acd..9e44f237e 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -20,6 +20,9 @@ #include #endif +#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix)) +#include +#endif #if (defined(__APPLE__) || (defined(__linux) && !defined(ANDROID)) || (defined(__unix) && !defined(ANDROID)) || defined(__posix)) #define USE_CRASH_CATCHER 1 From 60a7d3d6e0af503f81e3e5ec9b1b0c007f2cf000 Mon Sep 17 00:00:00 2001 From: Lennart Bernhardt Date: Sun, 6 Aug 2017 20:10:56 +0200 Subject: [PATCH 029/521] Fade out music before change occurs --- apps/openmw/mwsound/soundmanagerimp.cpp | 40 +++++++++++++++++++++++-- apps/openmw/mwsound/soundmanagerimp.hpp | 6 ++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 53c0643f6..97030643f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -34,7 +34,7 @@ namespace MWSound { - SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) , mFallback(fallbackMap) , mOutput(new DEFAULT_OUTPUT(*this)) @@ -328,9 +328,23 @@ namespace MWSound } } + void SoundManager::advanceMusic(const std::string& filename) + { + if (!isMusicPlaying()) + { + streamMusicFull(filename); + return; + } + + mMusicFader = 0.5f; + mNextMusic = filename; + + mMusic->setFadeout(mMusicFader); + } + void SoundManager::streamMusic(const std::string& filename) { - streamMusicFull("Music/"+filename); + advanceMusic("Music/"+filename); } void SoundManager::startRandomTitle() @@ -370,7 +384,7 @@ namespace MWSound i = (i+1) % filelist.size(); } - streamMusicFull(filelist[i]); + advanceMusic(filelist[i]); } bool SoundManager::isMusicPlaying() @@ -1029,6 +1043,25 @@ namespace MWSound } + void SoundManager::updateMusic(float duration) + { + if (!mNextMusic.empty()) + { + mMusic->updateFade(duration); + + mOutput->startUpdate(); + mOutput->updateStream(mMusic); + mOutput->finishUpdate(); + + if (mMusic->getRealVolume() <= 0.f) + { + streamMusicFull(mNextMusic); + mNextMusic.clear(); + } + } + } + + void SoundManager::update(float duration) { if(!mOutput->isInitialized()) @@ -1040,6 +1073,7 @@ namespace MWSound updateSounds(duration); updateRegionSound(duration); updateWaterSound(duration); + updateMusic(duration); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index bf628b102..1c5348e65 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -114,9 +114,15 @@ namespace MWSound MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); + void advanceMusic(const std::string& filename); + void updateSounds(float duration); void updateRegionSound(float duration); void updateWaterSound(float duration); + void updateMusic(float duration); + + float mMusicFader; + std::string mNextMusic; float volumeFromType(PlayType type) const; From 632d39ca767978620100d83052a6dedd9067157c Mon Sep 17 00:00:00 2001 From: spycrab Date: Sun, 6 Aug 2017 15:03:48 +0200 Subject: [PATCH 030/521] Allow starting at an (unnamed) exterior cell using --start (Feature #3941) --- apps/openmw/engine.cpp | 3 +-- apps/openmw/engine.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 21 ++++++++++++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 426300149..c921e17d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -278,8 +278,7 @@ void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) mResDir = parResDir; } -// Set start cell name (only interiors for now) - +// Set start cell name void OMW::Engine::setCell (const std::string& cellName) { mCellName = cellName; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 29419a4c2..bf144bfed 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -148,7 +148,7 @@ namespace OMW /// Set resource dir void setResourceDir(const boost::filesystem::path& parResDir); - /// Set start cell name (only interiors for now) + /// Set start cell name void setCell(const std::string& cellName); /** diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f8d44292e..a9506385d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2582,7 +2582,25 @@ namespace MWWorld { pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - if (const ESM::Cell *ext = getExterior(name)) { + const ESM::Cell *ext = getExterior(name); + + if (!ext && name.find(',') != std::string::npos) { + try { + int x = std::stoi(name.substr(0, name.find(','))); + int y = std::stoi(name.substr(name.find(',')+1)); + ext = getExterior(x, y)->getCell(); + } + catch (std::invalid_argument) + { + // This exception can be ignored, as this means that name probably refers to a interior cell instead of comma separated coordinates + } + catch (std::out_of_range) + { + throw std::runtime_error("Cell coordinates out of range."); + } + } + + if (ext) { int x = ext->getGridX(); int y = ext->getGridY(); indexToPosition(x, y, pos.pos[0], pos.pos[1], true); @@ -2592,6 +2610,7 @@ namespace MWWorld return true; } + return false; } From cef415509f9db64c7eea93bf1ba6f799215f2a9f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 6 Aug 2017 20:54:20 +0000 Subject: [PATCH 031/521] Revert "Merge redundant input events" --- components/sdlutil/sdlinputwrapper.cpp | 33 ++++---------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 56411ca88..ac172b84b 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -49,42 +49,17 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v SDL_PumpEvents(); - SDL_Event event; + SDL_Event evt; if (windowEventsOnly) { // During loading, just handle window events, and keep others for later - while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) - handleWindowEvent(event); + while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT)) + handleWindowEvent(evt); return; } - // Merge redundant events to avoid unnecessary listener calls - std::vector events; - while(SDL_PollEvent(&event)) { - if (events.empty() || events.back().type != event.type) - { - events.emplace_back(event); - continue; - } - - SDL_Event& previousEvent = events.back(); - - switch (event.type) - { - case SDL_MOUSEMOTION: - previousEvent.motion.x = event.motion.x; - previousEvent.motion.y = event.motion.y; - previousEvent.motion.xrel += event.motion.xrel; - previousEvent.motion.yrel += event.motion.yrel; - break; - default: - events.emplace_back(event); - } - } - - - for (const SDL_Event& evt : events) + while(SDL_PollEvent(&evt)) { switch(evt.type) { From bf8d10587ec8e3954b61764773162dba6d9ac76f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 6 Aug 2017 21:09:29 +0000 Subject: [PATCH 032/521] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2a10cbc2b..c48647f4e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -139,6 +139,7 @@ Programmers Siimacore sir_herrbatka smbas + spycrab Stefan Galowicz (bogglez) Stanislav Bobrov (Jiub) stil-t From dd919b9f2cb2e1e546e0e0ef899f051782cfebb3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 26 Jul 2017 14:42:01 +0400 Subject: [PATCH 033/521] Do not allow to loot fighting actors during death animation (bug #3528) --- apps/openmw/mwclass/creature.cpp | 30 +++++++++++++--- apps/openmw/mwclass/npc.cpp | 36 +++++++++++++------ .../reference/modding/settings/game.rst | 18 +++++++++- files/settings-default.cfg | 3 ++ 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index ce03af7a1..65f8c80d8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" @@ -448,10 +449,27 @@ namespace MWClass return action; } - if(getCreatureStats(ptr).isDead()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); - if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat()) + const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); + + if(stats.isDead()) + { + bool canLoot = Settings::Manager::getBool ("can loot during death animation", "Game"); + + // by default user can loot friendly actors during death animation + if (canLoot && !stats.getAiSequence().isInCombat()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // otherwise wait until death animation + if(stats.isDeathAnimationFinished()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // death animation is not finished, do nothing + return std::shared_ptr (new MWWorld::FailedAction("")); + } + + if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } @@ -558,7 +576,11 @@ namespace MWClass return true; const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData(); - return !customData.mCreatureStats.getAiSequence().isInCombat() || customData.mCreatureStats.isDead(); + + if (customData.mCreatureStats.isDead() && customData.mCreatureStats.isDeathAnimationFinished()) + return true; + + return !customData.mCreatureStats.getAiSequence().isInCombat(); } MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f8ff3da19..ed1f12b31 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -863,16 +864,27 @@ namespace MWClass return action; } - if(getCreatureStats(ptr).isDead()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); - if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::FailedAction("#{sActorInCombat}")); - if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) - || ptr.getClass().getCreatureStats(ptr).getKnockedDown()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing - // Can't talk to werewolfs - if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf()) + const MWMechanics::CreatureStats& stats = getCreatureStats(ptr); + + if(stats.isDead()) + { + bool canLoot = Settings::Manager::getBool ("can loot during death animation", "Game"); + + // by default user can loot friendly actors during death animation + if (canLoot && !stats.getAiSequence().isInCombat()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // otherwise wait until death animation + if(stats.isDeathAnimationFinished()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + + // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); + } + + if(stats.getAiSequence().isInCombat()) + return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } @@ -1019,7 +1031,11 @@ namespace MWClass return true; const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData(); - return !customData.mNpcStats.getAiSequence().isInCombat() || customData.mNpcStats.isDead(); + + if (customData.mNpcStats.isDead() && customData.mNpcStats.isDeathAnimationFinished()) + return true; + + return !customData.mNpcStats.getAiSequence().isInCombat(); } MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 62fe5a70e..e1d5d75f6 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -65,6 +65,22 @@ the type of attack is determined by the direction that the character is moving a The default value is false. This setting can be toggled with the Always Use Best Attack button in the Prefs panel of the Options menu. +can loot during death animation +------------------------------- + +:Type: boolean +:Range: True/False +:Default: True + +If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. +However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. +This is how original Morrowind behaves. + +If this setting is false, player has to wait until end of death animation in all cases. +This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. + +The default value is true. This setting can only be configured by editing the settings configuration file. + difficulty ---------- @@ -110,4 +126,4 @@ followers attack on sight :Default: False Makes player followers and escorters start combat with enemies who have started combat with them or the player. -Otherwise they wait for the enemies or the player to do an attack first. \ No newline at end of file +Otherwise they wait for the enemies or the player to do an attack first. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 40c1ed099..a0460326b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -180,6 +180,9 @@ prevent merchant equipping = false # or the player. Otherwise they wait for the enemies or the player to do an attack first. followers attack on sight = false +# Can loot non-fighting actors during death animation +can loot during death animation = true + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). From ab391f17dbcd06ecfbe7829503e96d37b4cd0069 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 7 Aug 2017 12:12:57 +0400 Subject: [PATCH 034/521] Fixes regression in spell school detection (bug #4007) --- apps/openmw/mwmechanics/spellcasting.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a6ae5ca65..ecd4ba48a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -121,6 +121,11 @@ namespace MWMechanics CreatureStats& stats = actor.getClass().getCreatureStats(actor); + float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); + + float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; + castChance *= stats.getFatigueTerm(); + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) return 0; @@ -138,11 +143,6 @@ namespace MWMechanics return 100; } - float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); - - float castChance = calcSpellBaseSuccessChance(spell, actor, effectiveSchool) + castBonus; - castChance *= stats.getFatigueTerm(); - if (!cap) return std::max(0.f, castChance); else From 7b8278ae45941226a555a5c9dd4840d9fc57eca1 Mon Sep 17 00:00:00 2001 From: Lennart Bernhardt Date: Tue, 8 Aug 2017 03:17:40 +0200 Subject: [PATCH 035/521] remove redundant mMusicFader variable --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +-- apps/openmw/mwsound/soundmanagerimp.hpp | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 97030643f..88ee42b01 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -336,10 +336,9 @@ namespace MWSound return; } - mMusicFader = 0.5f; mNextMusic = filename; - mMusic->setFadeout(mMusicFader); + mMusic->setFadeout(0.5f); } void SoundManager::streamMusic(const std::string& filename) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 1c5348e65..5d911d4be 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -121,7 +121,6 @@ namespace MWSound void updateWaterSound(float duration); void updateMusic(float duration); - float mMusicFader; std::string mNextMusic; float volumeFromType(PlayType type) const; From 546352dbe311a11cbd1e2da9335ef38b9197d59f Mon Sep 17 00:00:00 2001 From: Lennart Bernhardt Date: Tue, 8 Aug 2017 03:31:01 +0200 Subject: [PATCH 036/521] avoid starting sound updates more than necessary --- apps/openmw/mwsound/soundmanagerimp.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 88ee42b01..c6f663059 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -938,6 +938,8 @@ namespace MWSound env ); + updateMusic(duration); + // Check if any sounds are finished playing, and trash them SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -1048,9 +1050,7 @@ namespace MWSound { mMusic->updateFade(duration); - mOutput->startUpdate(); mOutput->updateStream(mMusic); - mOutput->finishUpdate(); if (mMusic->getRealVolume() <= 0.f) { @@ -1072,7 +1072,6 @@ namespace MWSound updateSounds(duration); updateRegionSound(duration); updateWaterSound(duration); - updateMusic(duration); } } From 6cb3c832488acbcf43b8fecdc1f98da064b29c84 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 20:36:50 +0400 Subject: [PATCH 037/521] Add transparency for interactive messageboxes in game mode --- apps/openmw/mwgui/messagebox.cpp | 2 +- files/mygui/CMakeLists.txt | 1 + ...openmw_interactive_messagebox_notransp.layout | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 files/mygui/openmw_interactive_messagebox_notransp.layout diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index f8ddeba3e..ab43df0f1 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -196,7 +196,7 @@ namespace MWGui InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout") + : WindowModal(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "openmw_interactive_messagebox_notransp.layout" : "openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 6592de56e..ed673c5d6 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -38,6 +38,7 @@ set(MYGUI_FILES openmw_hud.layout openmw_infobox.layout openmw_interactive_messagebox.layout + openmw_interactive_messagebox_notransp.layout openmw_inventory_window.layout openmw_journal.layout openmw_journal.skin.xml diff --git a/files/mygui/openmw_interactive_messagebox_notransp.layout b/files/mygui/openmw_interactive_messagebox_notransp.layout new file mode 100644 index 000000000..6b79b9417 --- /dev/null +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From 4cc8afd25da2aca12995c4801a3d034381903972 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 20:38:15 +0400 Subject: [PATCH 038/521] Add transparency for tooltips in game mode --- apps/openmw/mwgui/tooltips.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 1e770a60b..798eb1d6a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -378,17 +378,11 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - if(mShowOwned == 1 || mShowOwned == 3) - { - if(isFocusObject && checkOwned()) - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); - } - else - { - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp"); - } - } + // TODO: apply alpha to "owned" background + if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) + mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); + else + mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); std::string caption = info.caption; std::string image = info.icon; From 8c1c80ab9143900e8c527678c92bfe0b62e50481 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 20:39:25 +0400 Subject: [PATCH 039/521] Disable transparency for persuation dialogue menu --- files/mygui/openmw_persuasion_dialog.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout index d9a673ec2..c66f9d0ad 100644 --- a/files/mygui/openmw_persuasion_dialog.layout +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -1,7 +1,7 @@ - + From 56f5a5dee385eb2d1c3c97439d81447ba0885a07 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 8 Aug 2017 22:57:39 +0400 Subject: [PATCH 040/521] Added transparency to 'owned' tooltip --- apps/openmw/mwgui/tooltips.cpp | 3 +-- files/mygui/openmw_hud_box.skin.xml | 12 ++++++++++++ files/mygui/openmw_windows.skin.xml | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 798eb1d6a..81a3d864c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -378,9 +378,8 @@ namespace MWGui { mDynamicToolTipBox->setVisible(true); - // TODO: apply alpha to "owned" background if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) - mDynamicToolTipBox->changeWidgetSkin("HUD_Box_NoTransp_Owned"); + mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp_Owned" : "HUD_Box_Owned"); else mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 33199d6ae..e53493bb1 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -36,6 +36,18 @@ + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 00e6f9148..a272ae84a 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -158,13 +158,20 @@ - + + + + + + + + From f41a4bb93794de0e76665486ec13a06a589785f7 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 9 Aug 2017 00:20:49 -0500 Subject: [PATCH 041/521] Changing "New Installation" to "Retail CD/DVD" for clarity --- apps/wizard/componentselectionpage.cpp | 7 +++---- apps/wizard/conclusionpage.cpp | 6 +++--- apps/wizard/installationpage.cpp | 7 +++---- apps/wizard/languageselectionpage.cpp | 2 +- apps/wizard/mainwizard.cpp | 5 ++--- apps/wizard/methodselectionpage.cpp | 7 +++---- files/ui/wizard/methodselectionpage.ui | 18 +++++++++--------- 7 files changed, 24 insertions(+), 28 deletions(-) diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 161e51515..d99884966 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include "mainwizard.hpp" @@ -26,7 +25,7 @@ Wizard::ComponentSelectionPage::ComponentSelectionPage(QWidget *parent) : void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem*) { - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) return; // Morrowind is always checked here bool unchecked = true; @@ -60,7 +59,7 @@ void Wizard::ComponentSelectionPage::initializePage() QListWidgetItem *tribunalItem = new QListWidgetItem(QLatin1String("Tribunal")); QListWidgetItem *bloodmoonItem = new QListWidgetItem(QLatin1String("Bloodmoon")); - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { morrowindItem->setFlags((morrowindItem->flags() & ~Qt::ItemIsEnabled) | Qt::ItemIsUserCheckable); morrowindItem->setData(Qt::CheckStateRole, Qt::Checked); @@ -117,7 +116,7 @@ bool Wizard::ComponentSelectionPage::validatePage() // qDebug() << components << path << mWizard->mInstallations[path]; - if (field(QLatin1String("installation.new")).toBool() == false) { + if (field(QLatin1String("installation.retailDisc")).toBool() == false) { if (components.contains(QLatin1String("Tribunal")) && !components.contains(QLatin1String("Bloodmoon"))) { if (mWizard->mInstallations[path].hasBloodmoon) diff --git a/apps/wizard/conclusionpage.cpp b/apps/wizard/conclusionpage.cpp index 87154732a..f6a6015b8 100644 --- a/apps/wizard/conclusionpage.cpp +++ b/apps/wizard/conclusionpage.cpp @@ -16,14 +16,14 @@ Wizard::ConclusionPage::ConclusionPage(QWidget *parent) : void Wizard::ConclusionPage::initializePage() { // Write the path to openmw.cfg - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { QString path(field(QLatin1String("installation.path")).toString()); mWizard->addInstallation(path); } if (!mWizard->mError) { - if ((field(QLatin1String("installation.new")).toBool() == true) + if ((field(QLatin1String("installation.retailDisc")).toBool() == true) || (field(QLatin1String("installation.import-settings")).toBool() == true)) { qDebug() << "IMPORT SETTINGS"; @@ -33,7 +33,7 @@ void Wizard::ConclusionPage::initializePage() if (!mWizard->mError) { - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { textLabel->setText(tr("

The OpenMW Wizard successfully installed Morrowind on your computer.

\

Click Finish to close the Wizard.

")); diff --git a/apps/wizard/installationpage.cpp b/apps/wizard/installationpage.cpp index 2f0af88c9..7a4dcbf10 100644 --- a/apps/wizard/installationpage.cpp +++ b/apps/wizard/installationpage.cpp @@ -7,7 +7,6 @@ #include #include "mainwizard.hpp" -#include "inisettings.hpp" Wizard::InstallationPage::InstallationPage(QWidget *parent) : QWizardPage(parent) @@ -76,7 +75,7 @@ void Wizard::InstallationPage::initializePage() // That way installing all three components would yield 300% // When one component is done the bar will be filled by 33% - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { installProgressBar->setMaximum((components.count() * 100)); } else { if (components.contains(QLatin1String("Tribunal")) @@ -96,7 +95,7 @@ void Wizard::InstallationPage::startInstallation() QStringList components(field(QLatin1String("installation.components")).toStringList()); QString path(field(QLatin1String("installation.path")).toString()); - if (field(QLatin1String("installation.new")).toBool() == true) + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { // Always install Morrowind mUnshield->setInstallComponent(Wizard::Component_Morrowind, true); @@ -227,7 +226,7 @@ bool Wizard::InstallationPage::isComplete() const int Wizard::InstallationPage::nextId() const { - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { return MainWizard::Page_Conclusion; } else { if (!mWizard->mError) { diff --git a/apps/wizard/languageselectionpage.cpp b/apps/wizard/languageselectionpage.cpp index 0d5132f5b..4c10bf38c 100644 --- a/apps/wizard/languageselectionpage.cpp +++ b/apps/wizard/languageselectionpage.cpp @@ -30,7 +30,7 @@ void Wizard::LanguageSelectionPage::initializePage() int Wizard::LanguageSelectionPage::nextId() const { - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { return MainWizard::Page_ComponentSelection; } else { QString path(field(QLatin1String("installation.path")).toString()); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 7ef8761dd..b99f151aa 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -258,7 +257,7 @@ void Wizard::MainWizard::runSettingsImporter() QStringList arguments; // Import plugin selection? - if (field(QLatin1String("installation.new")).toBool() == true + if (field(QLatin1String("installation.retailDisc")).toBool() == true || field(QLatin1String("installation.import-addons")).toBool() == true) arguments.append(QLatin1String("--game-files")); @@ -278,7 +277,7 @@ void Wizard::MainWizard::runSettingsImporter() // Now the paths arguments.append(QLatin1String("--ini")); - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { arguments.append(path + QDir::separator() + QLatin1String("Morrowind.ini")); } else { arguments.append(mInstallations[path].iniPath); diff --git a/apps/wizard/methodselectionpage.cpp b/apps/wizard/methodselectionpage.cpp index 5f3917bd5..e00344af9 100644 --- a/apps/wizard/methodselectionpage.cpp +++ b/apps/wizard/methodselectionpage.cpp @@ -1,5 +1,4 @@ #include "methodselectionpage.hpp" -#include #include "mainwizard.hpp" Wizard::MethodSelectionPage::MethodSelectionPage(QWidget *parent) : @@ -10,16 +9,16 @@ Wizard::MethodSelectionPage::MethodSelectionPage(QWidget *parent) : setupUi(this); #ifndef OPENMW_USE_UNSHIELD - newLocationRadioButton->setEnabled(false); + retailDiscRadioButton->setEnabled(false); existingLocationRadioButton->setChecked(true); #endif - registerField(QLatin1String("installation.new"), newLocationRadioButton); + registerField(QLatin1String("installation.retailDisc"), retailDiscRadioButton); } int Wizard::MethodSelectionPage::nextId() const { - if (field(QLatin1String("installation.new")).toBool() == true) { + if (field(QLatin1String("installation.retailDisc")).toBool() == true) { return MainWizard::Page_InstallationTarget; } else { return MainWizard::Page_ExistingInstallation; diff --git a/files/ui/wizard/methodselectionpage.ui b/files/ui/wizard/methodselectionpage.ui index 531d093af..4d4d66bad 100644 --- a/files/ui/wizard/methodselectionpage.ui +++ b/files/ui/wizard/methodselectionpage.ui @@ -17,16 +17,16 @@ Select Installation Method
- Select how OpenMW should get the required Morrowind installation files. + <html><head/><body><p>Select how you would like to install <i>The Elder Scrolls III: Morrowind</i>.</p></body></html> - + font-weight:bold; - Install Morrowind to a new location + Retail CD/DVD true @@ -34,7 +34,7 @@ - + @@ -72,14 +72,14 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - newLocationRadioButton + retailDiscRadioButton
- + - Install Morrowind from a retail disk to a new location for OpenMW to use. + Install from a retail disc to a new location. true @@ -94,7 +94,7 @@ font-weight:bold - Select an existing Morrowind installation + Existing Installation @@ -138,7 +138,7 @@ - Select an existing Morrowind installation for OpenMW to use. + Select an existing installation. true From 464c64a306bb79ca76fc0bdc3de0324e6982c37a Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 9 Aug 2017 20:03:27 -0500 Subject: [PATCH 042/521] Swap the OIS Ctrl and Meta keys on macOS to match Qt --- components/sdlutil/sdlinputwrapper.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index ac172b84b..f622f2166 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -1,7 +1,6 @@ #include "sdlinputwrapper.hpp" #include -#include #include @@ -423,7 +422,6 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyMap.insert( KeyMap::value_type(SDLK_o, OIS::KC_O) ); mKeyMap.insert( KeyMap::value_type(SDLK_p, OIS::KC_P) ); mKeyMap.insert( KeyMap::value_type(SDLK_RETURN, OIS::KC_RETURN) ); - mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL)); mKeyMap.insert( KeyMap::value_type(SDLK_a, OIS::KC_A) ); mKeyMap.insert( KeyMap::value_type(SDLK_s, OIS::KC_S) ); mKeyMap.insert( KeyMap::value_type(SDLK_d, OIS::KC_D) ); @@ -499,9 +497,19 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyMap.insert( KeyMap::value_type(SDLK_INSERT, OIS::KC_INSERT) ); mKeyMap.insert( KeyMap::value_type(SDLK_DELETE, OIS::KC_DELETE) ); mKeyMap.insert( KeyMap::value_type(SDLK_KP_ENTER, OIS::KC_NUMPADENTER) ); - mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RCONTROL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) ); + +//Qt switches the Ctrl and Meta keys on macOS. See http://doc.qt.io/qt-5/qkeysequence.html +#if defined(__APPLE__) + mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LCONTROL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RCONTROL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LWIN)); + mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RWIN) ); +#else mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LWIN) ); mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RWIN) ); - mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL)); + mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RCONTROL) ); +#endif } } From 54fe6457031080a806985c6d41d5bc5a9ac0bda7 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Wed, 9 Aug 2017 23:12:43 -0500 Subject: [PATCH 043/521] Removing erroneous comment since Qt is not relevant here --- components/sdlutil/sdlinputwrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index f622f2166..a76de00d1 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -499,7 +499,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mKeyMap.insert( KeyMap::value_type(SDLK_KP_ENTER, OIS::KC_NUMPADENTER) ); mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) ); -//Qt switches the Ctrl and Meta keys on macOS. See http://doc.qt.io/qt-5/qkeysequence.html +//The function of the Ctrl and Meta keys are switched on macOS compared to other platforms. +//For instance, Cmd+C versus Ctrl+C to copy from the system clipboard #if defined(__APPLE__) mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LCONTROL) ); mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RCONTROL) ); From e4df17ccafbdfe897bcd9ef912a9467594ca8b93 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 11 Aug 2017 09:02:50 +0400 Subject: [PATCH 044/521] Make inventory avatar to fit within border (bug #4003) --- files/mygui/openmw_inventory_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 09e5ed9c7..bb707fa0d 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -12,7 +12,7 @@ - + From c542ae6875c8e913f8824cdc4fca303d0e893b45 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Aug 2017 09:06:31 +0400 Subject: [PATCH 045/521] Create autosave when waiting (bug #1452) --- apps/openmw/mwgui/waitdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 8685475a4..ba58a9c69 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -134,7 +134,7 @@ namespace MWGui void WaitDialog::startWaiting(int hoursToWait) { - if(Settings::Manager::getBool("autosave","Saves") && mSleeping) //autosaves when enabled and sleeping + if(Settings::Manager::getBool("autosave","Saves")) //autosaves when enabled MWBase::Environment::get().getStateManager()->quickSave("Autosave"); MWBase::World* world = MWBase::Environment::get().getWorld(); From b3b7d6aa9f48fb4924737b8b682219e26db5957b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Aug 2017 09:36:09 +0400 Subject: [PATCH 046/521] Do not make target reference unavailable on cell change (bug #3898) --- apps/openmw/mwgui/referenceinterface.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 76bb4f53f..9aaa98f19 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -20,9 +20,8 @@ namespace MWGui { MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); - // check if player has changed cell, or count of the reference has become 0 - if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) + // check if count of the reference has become 0 + if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0) { if (!mPtr.isEmpty()) { From 3f159960b7f430b6e8ecc6e0ac2da4d1a348ecac Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 12 Aug 2017 21:18:05 +0400 Subject: [PATCH 047/521] Restored pickpocket and werewolf check --- apps/openmw/mwclass/npc.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ed1f12b31..ca6c85aba 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -885,6 +885,14 @@ namespace MWClass if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak) + || ptr.getClass().getCreatureStats(ptr).getKnockedDown()) + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing + + // Can't talk to werewolfs + if(ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).isWerewolf()) + return std::shared_ptr (new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } From 249c1ae95a6c70acd2f2b13af9a5bb863e6044f1 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 13 Aug 2017 19:26:32 -0400 Subject: [PATCH 048/521] Fix orbit camera jumping back to old position --- apps/opencs/view/render/scenewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 82eebf127..3a801ffc3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -393,6 +393,7 @@ void SceneWidget::selectNavigationMode (const std::string& mode) mCurrentCamControl->setCamera(NULL); mCurrentCamControl = mOrbitCamControl; mOrbitCamControl->setCamera(getCamera()); + mOrbitCamControl->reset(); } } From f84eb68b3d1e173b84c41618ebe21e0dbe474f9d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 10:41:37 +0400 Subject: [PATCH 049/521] Confiscate an item when you try to sell it to its owner (bug #3944) --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 6 +-- .../mwmechanics/mechanicsmanagerimp.cpp | 37 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 + 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index bd0d2ea4a..9cb004107 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -241,6 +241,8 @@ namespace MWBase virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor) = 0; virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; + + virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f82d2f68d..ca0bb48e8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -311,9 +311,9 @@ namespace MWGui if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, - it->mBase.getClass().getValue(it->mBase) - * it->mCount, true); + + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); + onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); return; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8460a1473..b174e87cd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -907,6 +907,43 @@ namespace MWMechanics return ownerFound != owners.end(); } + void MechanicsManager::confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) + { + if (player != getPlayer()) + return; + + const std::string itemId = Misc::StringUtils::lowerCase(item.getCellRef().getRefId()); + + StolenItemsMap::iterator stolenIt = mStolenItems.find(itemId); + if (stolenIt == mStolenItems.end()) + return; + + Owner owner; + owner.first = victim.getCellRef().getRefId(); + owner.second = false; + + Misc::StringUtils::lowerCaseInPlace(owner.first); + + // decrease count of stolen items + int toRemove = std::min(count, mStolenItems[itemId][owner]); + mStolenItems[itemId][owner] -= toRemove; + if (mStolenItems[itemId][owner] == 0) + { + // erase owner from stolen items owners + OwnerMap& owners = stolenIt->second; + OwnerMap::iterator ownersIt = owners.find(owner); + if (ownersIt != owners.end()) + owners.erase(ownersIt); + } + + MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); + + // move items from player to owner and report about theft + victim.getClass().getContainerStore(victim).add(item, toRemove, victim); + store.remove(item, toRemove, player); + commitCrime(player, victim, OT_Theft, item.getClass().getValue(item) * toRemove); + } + void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer) { MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ed06f58c5..a5598252f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -206,6 +206,8 @@ namespace MWMechanics virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId); + virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); From 7a5645b35d8ae2ff3ecf15efc0eddcccfaf271aa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 18:42:19 +0400 Subject: [PATCH 050/521] Prevent followers from attacking player if crime was reported --- .../mwmechanics/mechanicsmanagerimp.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8460a1473..e5f1d73dc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1030,11 +1030,6 @@ namespace MWMechanics if (playerFollowers.find(*it) != playerFollowers.end()) continue; - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) - MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); - crimeSeen = true; } } @@ -1136,10 +1131,25 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + // Player's followers should not attack player, or try to arrest him + if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) + { + std::set playerFollowers; + getActorsSidingWith(player, playerFollowers); + + if (playerFollowers.find(*it) != playerFollowers.end()) + continue; + } + // Will the witness report the crime? if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) { reported = true; + + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Trespassing) + MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); } if (it->getClass().isClass(*it, "guard")) @@ -1153,16 +1163,6 @@ namespace MWMechanics if (!it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) { - // Player's followers should not try to arrest player - if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) - { - std::set playerFollowers; - getActorsSidingWith(player, playerFollowers); - - if (playerFollowers.find(*it) != playerFollowers.end()) - continue; - } - it->getClass().getCreatureStats(*it).getAiSequence().stack(AiPursue(player), *it); } } From ec640341608b0b68c1fe47a1900ae4b125449d6e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 19:29:34 +0400 Subject: [PATCH 051/521] Confiscate stolen item/gem when enchanting --- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 643b69532..c7d2ef7de 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -360,8 +360,9 @@ namespace MWGui if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); MWBase::Environment::get().getWindowManager()->messageBox(msg); - MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, - item.getClass().getValue(item), true); + + MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); return; From 1e983604db7c5e6ec2f1a129cf0281044b763cb5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 14 Aug 2017 20:39:04 +0400 Subject: [PATCH 052/521] Dispel only effects from spells (bug #3995) --- apps/openmw/mwmechanics/activespells.cpp | 15 ++++++++++++++- apps/openmw/mwmechanics/activespells.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwmechanics/spellpriority.cpp | 8 ++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 52c05fdfa..90d29f686 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -222,10 +222,23 @@ namespace MWMechanics } } - void ActiveSpells::purgeAll(float chance) + void ActiveSpells::purgeAll(float chance, bool spellOnly) { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { + const std::string spellId = it->first; + + // if spellOnly is true, dispell only spells. Leave potions, enchanted items etc. + if (spellOnly) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(spellId); + if (!spell || spell->mData.mType != ESM::Spell::ST_Spell) + { + ++it; + continue; + } + } + if (Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 0f1f803b7..a19c8a51d 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -89,7 +89,7 @@ namespace MWMechanics void purgeEffect (short effectId, const std::string& sourceId); /// Remove all active effects, if roll succeeds (for each effect) - void purgeAll (float chance); + void purgeAll(float chance, bool spellOnly = false); /// Remove all effects with CASTER_LINKED flag that were cast by \a casterActorId void purge (int casterActorId); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ecd4ba48a..f7ee15bf4 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -673,7 +673,7 @@ namespace MWMechanics } else if (target.getClass().isActor() && effectId == ESM::MagicEffect::Dispel) { - target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); + target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude, true); return true; } else if (target.getClass().isActor() && target == getPlayer()) diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index a73e4fd89..0b86b9494 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -25,6 +25,14 @@ namespace const MWMechanics::ActiveSpells& activeSpells = actor.getClass().getCreatureStats(actor).getActiveSpells(); for (MWMechanics::ActiveSpells::TIterator it = activeSpells.begin(); it != activeSpells.end(); ++it) { + // if the effect filter is not specified, take in account only spells effects. Leave potions, enchanted items etc. + if (effectFilter == -1) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().search(it->first); + if (!spell || spell->mData.mType != ESM::Spell::ST_Spell) + continue; + } + const MWMechanics::ActiveSpells::ActiveSpellParams& params = it->second; for (std::vector::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt) From 67d59bead51ce4948c0e0256ee014bdab3bc8b5f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 Aug 2017 15:03:04 +0400 Subject: [PATCH 053/521] Get only text from input fields (bug #4025) --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/class.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 +++-- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 4 ++-- apps/openmw/mwgui/textinput.cpp | 4 ++-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 7379f3613..95dc8cc4d 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,7 +64,7 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); + MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getOnlyText()); MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); switch (result) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e1f5a165e..ac61041c3 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -483,7 +483,7 @@ namespace MWGui std::string CreateClassDialog::getName() const { - return mEditName->getCaption(); + return mEditName->getOnlyText(); } std::string CreateClassDialog::getDescription() const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c7d2ef7de..5dc1f3454 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -312,7 +313,7 @@ namespace MWGui return; } - if (mName->getCaption ().empty()) + if (mName->getOnlyText().empty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -336,7 +337,7 @@ namespace MWGui return; } - mEnchanting.setNewItemName(mName->getCaption()); + mEnchanting.setNewItemName(mName->getOnlyText()); mEnchanting.setEffect(mEffectList); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index cb7c6c0d0..6391f8597 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -58,7 +58,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::TextBox* mName; + MyGUI::EditBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 84d4ca959..4d1a490aa 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -248,7 +248,7 @@ namespace MWGui dialog->eventCancelClicked.clear(); return; } - if (mSaveNameEdit->getCaption().empty()) + if (mSaveNameEdit->getOnlyText().empty()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); return; @@ -275,7 +275,7 @@ namespace MWGui if (mSaving) { - MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); + MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getOnlyText(), mCurrentSlot); } else { diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 354253fa4..cd2d2cd1d 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -373,7 +373,7 @@ namespace MWGui return; } - if (mNameEdit->getCaption () == "") + if (mNameEdit->getOnlyText() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -394,7 +394,7 @@ namespace MWGui return; } - mSpell.mName = mNameEdit->getCaption(); + mSpell.mName = mNameEdit->getOnlyText(); int price = MyGUI::utility::parseInt(mPriceLabel->getCaption()); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 958b52dc0..9ddfac612 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -53,7 +53,7 @@ namespace MWGui void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { - if (mTextEdit->getCaption() == "") + if (mTextEdit->getOnlyText() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); @@ -69,7 +69,7 @@ namespace MWGui std::string TextInputDialog::getTextInput() const { - return mTextEdit->getCaption(); + return mTextEdit->getOnlyText(); } void TextInputDialog::setTextInput(const std::string &text) From bc7353f100f1bdfbce0630da949bf25906771cde Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 16 Aug 2017 20:30:47 +0400 Subject: [PATCH 054/521] Check animation state for GetPCRunning and GetPCSneaking --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 ++++- apps/openmw/mwmechanics/actors.cpp | 20 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 16 +++++++++++++-- apps/openmw/mwmechanics/character.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 10 ++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwscript/controlextensions.cpp | 16 ++++++++++++--- 8 files changed, 68 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 9cb004107..2daaf9711 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -230,7 +230,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. @@ -243,6 +243,9 @@ namespace MWBase virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; + + virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; + virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 00f8899de..9a23526f7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -802,6 +802,26 @@ namespace MWMechanics } } + bool Actors::isRunning(const MWWorld::Ptr& ptr) + { + PtrActorMap::iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isRunning(); + } + + bool Actors::isSneaking(const MWWorld::Ptr& ptr) + { + PtrActorMap::iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isSneaking(); + } + void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) { PtrActorMap::iterator it = mActors.find(ptr); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 362c2f126..cd949696b 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -107,6 +107,9 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + bool isRunning(const MWWorld::Ptr& ptr); + bool isSneaking(const MWWorld::Ptr& ptr); + void forceStateUpdate(const MWWorld::Ptr &ptr); bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 661df35b0..25d04d176 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1650,7 +1650,7 @@ void CharacterController::update(float duration) mSecondsOfSwimming -= 1; } } - else if(isrunning) + else if(isrunning && !sneak) { mSecondsOfRunning += duration; while(mSecondsOfRunning > 1) @@ -1688,7 +1688,7 @@ void CharacterController::update(float duration) else fatigueLoss = fFatigueSwimRunBase + encumbrance * fFatigueSwimRunMult; } - if (isrunning) + else if (isrunning) fatigueLoss = fFatigueRunBase + encumbrance * fFatigueRunMult; } } @@ -2237,6 +2237,18 @@ bool CharacterController::isSneaking() const mMovementState == CharState_SneakRight; } +bool CharacterController::isRunning() const +{ + return mMovementState == CharState_RunForward || + mMovementState == CharState_RunBack || + mMovementState == CharState_RunLeft || + mMovementState == CharState_RunRight || + mMovementState == CharState_SwimRunForward || + mMovementState == CharState_SwimRunBack || + mMovementState == CharState_SwimRunLeft || + mMovementState == CharState_SwimRunRight; +} + void CharacterController::setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index a3cdf097d..66039bf5d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -266,6 +266,7 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; bool isSneaking() const; + bool isRunning() const; void setAttackingOrSpell(bool attackingOrSpell); void setAIAttackType(const std::string& attackType); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index f4b4cec91..d182e40d7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -422,6 +422,16 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr) + { + return mActors.isRunning(ptr); + } + + bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr) + { + return mActors.isSneaking(ptr); + } + void MechanicsManager::rest(bool sleep) { mActors.rest(sleep); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index a5598252f..af0377a33 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -197,7 +197,7 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); - + /// @return is \a ptr allowed to take/use \a cellref or is it a crime? virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); @@ -208,6 +208,8 @@ namespace MWMechanics virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count); + virtual bool isRunning(const MWWorld::Ptr& ptr); + virtual bool isSneaking(const MWWorld::Ptr& ptr); private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 626fafb5a..21b3b5587 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -9,12 +9,14 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/movement.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -167,7 +169,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - runtime.push (ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)); + const MWWorld::Class &cls = ptr.getClass(); + + bool isRunning = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr); + + runtime.push (isRunning && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run)); } }; @@ -177,8 +183,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - runtime.push (ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + const MWWorld::Class &cls = ptr.getClass(); + + bool isSneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr); + + runtime.push (isSneaking && cls.getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak)); } }; From d8d47f081bda51d254b25df98e126677a054f950 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 13 Aug 2017 18:05:35 +0400 Subject: [PATCH 055/521] AiFollow: add a threshold when turning to target --- apps/openmw/mwmechanics/aifollow.cpp | 48 ++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index fe94246c4..fd5f9c7fe 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -22,8 +22,15 @@ struct AiFollowStorage : AiTemporaryBase { float mTimer; bool mMoving; - - AiFollowStorage() : mTimer(0.f), mMoving(false) {} + float mTargetAngleRadians; + bool mTurnActorToTarget; + + AiFollowStorage() : + mTimer(0.f), + mMoving(false), + mTargetAngleRadians(0.f), + mTurnActorToTarget(false) + {} }; int AiFollow::mFollowIndexCounter = 0; @@ -73,6 +80,15 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte AiFollowStorage& storage = state.get(); + bool& rotate = storage.mTurnActorToTarget; + if (rotate) + { + if (zTurn(actor, storage.mTargetAngleRadians)) + rotate = false; + + return false; + } + // AiFollow requires the target to be in range and within sight for the initial activation if (!mActive) { @@ -144,13 +160,33 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte //Set the target destination from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; - if (!storage.mMoving) - { - const short threshold = 10; // to avoid constant switching between moving/stopping + short baseFollowDistance = followDistance; + short threshold = 30; // to avoid constant switching between moving/stopping + if (storage.mMoving) + followDistance -= threshold; + else followDistance += threshold; + + osg::Vec3f targetPos(target.getRefData().getPosition().asVec3()); + osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); + + osg::Vec3f dir = targetPos - actorPos; + float targetDistSqr = dir.length2(); + + if (targetDistSqr <= followDistance * followDistance) + { + float faceAngleRadians = std::atan2(dir.x(), dir.y()); + + if (!zTurn(actor, faceAngleRadians, osg::DegreesToRadians(45.f))) + { + storage.mTargetAngleRadians = faceAngleRadians; + storage.mTurnActorToTarget = true; + } + + return false; } - storage.mMoving = !pathTo(actor, dest, duration, followDistance); // Go to the destination + storage.mMoving = !pathTo(actor, dest, duration, baseFollowDistance); // Go to the destination if (storage.mMoving) { From 6c8c883dc07bd98df19fdbb6e6d5369b5631600f Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 18 Aug 2017 00:47:28 +0300 Subject: [PATCH 056/521] Making knownEffect aware that there can be more than 4 potion effects --- apps/openmw/mwmechanics/alchemy.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index e6e3b4c4e..124468641 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -457,7 +457,9 @@ bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWW static const float fWortChanceValue = MWBase::Environment::get().getWorld()->getStore().get().find("fWortChanceValue")->getFloat(); return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue) - || (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2); + || (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2) + || (potionEffectIndex <= 5 && alchemySkill >= fWortChanceValue*3) + || (potionEffectIndex <= 7 && alchemySkill >= fWortChanceValue*4); } MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name) From 641a6cd842d0d39b597ecb1d5a5770e2cd0f0904 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 18 Aug 2017 11:58:28 +0400 Subject: [PATCH 057/521] Added a delay before summoned creature corpse despawning --- apps/openmw/mwmechanics/actors.cpp | 8 +++- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/summoning.cpp | 53 ++++++++++++++------------- apps/openmw/mwmechanics/summoning.hpp | 2 +- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 431ad09b3..e701336fe 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -781,7 +781,7 @@ namespace MWMechanics creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures); if (ptr.getClass().hasInventoryStore(ptr)) ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures); - updateSummonedCreatures.process(); + updateSummonedCreatures.process(mTimerDisposeSummonsCorpses == 0.f); } } @@ -1009,7 +1009,9 @@ namespace MWMechanics } } - Actors::Actors() {} + Actors::Actors() { + mTimerDisposeSummonsCorpses = 0.2f; // We should add a delay between summoned creature death and its corpse despawning + } Actors::~Actors() { @@ -1078,6 +1080,7 @@ namespace MWMechanics // target lists get updated once every 1.0 sec if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; if (timerUpdateHeadTrack >= 0.3f) timerUpdateHeadTrack = 0; + if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0; if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0; MWWorld::Ptr player = getPlayer(); @@ -1182,6 +1185,7 @@ namespace MWMechanics timerUpdateAITargets += duration; timerUpdateHeadTrack += duration; timerUpdateEquippedLight += duration; + mTimerDisposeSummonsCorpses += duration; // Looping magic VFX update // Note: we need to do this before any of the animations are updated. diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 362c2f126..8228284a7 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -150,6 +150,7 @@ namespace MWMechanics private: PtrActorMap mActors; + float mTimerDisposeSummonsCorpses; }; } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index e4a825efc..fad7bc96d 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -38,26 +38,10 @@ namespace MWMechanics } } - void UpdateSummonedCreatures::process() + void UpdateSummonedCreatures::process(bool cleanup) { - - MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); - - // Update summon effects std::map& creatureMap = creatureStats.getSummonedCreatureMap(); - for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) - { - bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); - if (!found) - { - // Effect has ended - MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); - creatureMap.erase(it++); - continue; - } - ++it; - } for (std::set >::iterator it = mActiveEffects.begin(); it != mActiveEffects.end(); ++it) { @@ -101,21 +85,18 @@ namespace MWMechanics } } + // Update summon effects for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); - if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead() && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()) + bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); + if (!found) { - // Purge the magic effect so a new creature can be summoned if desired - creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); - if (mActor.getClass().hasInventoryStore(ptr)) - mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); - + // Effect has ended MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); creatureMap.erase(it++); + continue; } - else - ++it; + ++it; } std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); @@ -137,6 +118,26 @@ namespace MWMechanics else ++it; } + + if (!cleanup) + return; + + for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second); + if (ptr.isEmpty() || (ptr.getClass().getCreatureStats(ptr).isDead() && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished())) + { + // Purge the magic effect so a new creature can be summoned if desired + creatureStats.getActiveSpells().purgeEffect(it->first.first, it->first.second); + if (mActor.getClass().hasInventoryStore(mActor)) + mActor.getClass().getInventoryStore(mActor).purgeEffect(it->first.first, it->first.second); + + MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, it->second); + creatureMap.erase(it++); + } + else + ++it; + } } } diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index b2a3c60ea..9329dcb83 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -22,7 +22,7 @@ namespace MWMechanics float magnitude, float remainingTime = -1, float totalTime = -1); /// To call after all effect sources have been visited - void process(); + void process(bool cleanup); private: MWWorld::Ptr mActor; From 7c80ddc9de385996c9e331aaffe433c330a56f62 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 18 Aug 2017 17:06:47 +0400 Subject: [PATCH 058/521] Owned crosshair improvements (bug #2789) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++- apps/openmw/mwclass/activator.cpp | 5 +++++ apps/openmw/mwclass/activator.hpp | 2 ++ apps/openmw/mwclass/door.cpp | 5 +++++ apps/openmw/mwclass/door.hpp | 2 ++ apps/openmw/mwgui/tooltips.cpp | 3 +-- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 ++++++++++++++---- .../openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/class.hpp | 8 ++++++++ 9 files changed, 41 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2daaf9711..f5013a8f3 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -7,6 +7,8 @@ #include #include +#include "../mwworld/ptr.hpp" + namespace osg { class Vec3f; @@ -231,7 +233,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) = 0; + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 4910ab932..8df262f24 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -51,6 +51,11 @@ namespace MWClass return ""; } + bool Activator::isActivator() const + { + return true; + } + bool Activator::useAnim() const { return true; diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 21afa7b8e..3f333f4cb 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -42,6 +42,8 @@ namespace MWClass virtual bool useAnim() const; ///< Whether or not to use animated variant of model (default false) + + virtual bool isActivator() const; }; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 3801cd261..07e6cc9db 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -76,6 +76,11 @@ namespace MWClass } } + bool Door::isDoor() const + { + return true; + } + bool Door::useAnim() const { return true; diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index a2d129522..57e475382 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -20,6 +20,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + virtual bool isDoor() const; + virtual bool useAnim() const; virtual std::string getName (const MWWorld::ConstPtr& ptr) const; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 81a3d864c..9b89c3957 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -359,12 +359,11 @@ namespace MWGui { if(!mFocusObject.isEmpty()) { - const MWWorld::CellRef& cellref = mFocusObject.getCellRef(); MWWorld::Ptr ptr = MWMechanics::getPlayer(); MWWorld::Ptr victim; MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, cellref, victim); + bool allowed = mm->isAllowedToUse(ptr, mFocusObject, victim); return !allowed; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d182e40d7..68115301f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/ptr.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -829,8 +830,17 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) { + const MWWorld::CellRef& cellref = item.getCellRef(); + // there is no harm to use unlocked doors + if (item.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) + return true; + + // TODO: implement a better check to check if item is owned bed + if (item.getClass().isActivator() && item.getClass().getScript(item).compare(0, 3, "Bed") != 0) + return true; + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; @@ -872,7 +882,7 @@ namespace MWMechanics } MWWorld::Ptr victim; - if (isAllowedToUse(ptr, bed.getCellRef(), victim)) + if (isAllowedToUse(ptr, bed, victim)) return false; if(commitCrime(ptr, victim, OT_SleepingInOwnedBed)) @@ -887,7 +897,7 @@ namespace MWMechanics void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; - if (isAllowedToUse(ptr, item.getCellRef(), victim)) + if (isAllowedToUse(ptr, item, victim)) return; commitCrime(ptr, victim, OT_Trespassing); } @@ -1007,7 +1017,7 @@ namespace MWMechanics } } - if (isAllowedToUse(ptr, *ownerCellRef, victim)) + if (isAllowedToUse(ptr, item, victim)) return; Owner owner; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index af0377a33..bba2c55d6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -199,7 +199,7 @@ namespace MWMechanics virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim); + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim); virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 42d57ffab..097ec0faa 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -301,6 +301,10 @@ namespace MWWorld virtual Ptr copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const; + virtual bool isActivator() const { + return false; + } + virtual bool isActor() const { return false; } @@ -309,6 +313,10 @@ namespace MWWorld return false; } + virtual bool isDoor() const { + return false; + } + virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; virtual bool canFly(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; From d31ed83b54383fbb669297e094c3fc66a740305f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 19 Aug 2017 03:43:31 -0400 Subject: [PATCH 059/521] Preliminary asset reloading --- apps/opencs/model/doc/document.cpp | 4 +-- apps/opencs/model/doc/document.hpp | 6 ++-- apps/opencs/model/doc/documentmanager.cpp | 2 +- apps/opencs/model/doc/documentmanager.hpp | 4 +-- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/model/world/data.cpp | 33 +++++++++++++++++++- apps/opencs/model/world/data.hpp | 6 ++-- apps/opencs/model/world/resources.cpp | 8 +++++ apps/opencs/model/world/resources.hpp | 2 ++ apps/opencs/model/world/resourcesmanager.cpp | 19 +++++++++-- apps/opencs/model/world/resourcesmanager.hpp | 8 +++-- apps/opencs/model/world/resourcetable.cpp | 10 ++++++ apps/opencs/model/world/resourcetable.hpp | 7 ++++- apps/opencs/view/doc/view.cpp | 8 +++++ components/vfs/archive.hpp | 3 ++ components/vfs/filesystemarchive.cpp | 6 ++++ components/vfs/filesystemarchive.hpp | 2 ++ components/vfs/manager.cpp | 8 +++++ components/vfs/manager.hpp | 3 ++ 19 files changed, 123 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index ef984c0ca..a7809f3e3 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -269,11 +269,11 @@ void CSMDoc::Document::createBase() } } -CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, +CSMDoc::Document::Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const Fallback::Map* fallback, - ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, + ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback, resDir), mTools (*this, encoding), diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 030a0174e..ad0201407 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -59,7 +59,7 @@ namespace CSMDoc private: - const VFS::Manager* mVFS; + VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector mContentFiles; bool mNew; @@ -102,11 +102,11 @@ namespace CSMDoc public: - Document (const VFS::Manager* vfs, const Files::ConfigurationManager& configuration, + Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const Fallback::Map* fallback, - ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager, + ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts); ~Document(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 098d7bad5..11378cab4 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -127,7 +127,7 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: removeDocument (document); } -void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs) +void CSMDoc::DocumentManager::setVFS(VFS::Manager *vfs) { mResourcesManager.setVFS(vfs); mVFS = vfs; diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index ed8e327d7..771afe8e5 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -41,7 +41,7 @@ namespace CSMDoc ToUTF8::FromType mEncoding; CSMWorld::ResourcesManager mResourcesManager; std::vector mBlacklistedScripts; - const VFS::Manager* mVFS; + VFS::Manager* mVFS; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -74,7 +74,7 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector& scriptIds); - void setVFS(const VFS::Manager* vfs); + void setVFS(VFS::Manager* vfs); bool isEmpty(); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c87e283a8..5c0b2e282 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -259,6 +259,7 @@ void CSMPrefs::State::declare() declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence()); declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence()); declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence()); + declareShortcut ("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5)); declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence()); declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence()); declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence()); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ee9e4329c..8c25faaa5 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "idtable.hpp" #include "idtree.hpp" @@ -61,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) +CSMWorld::Data::Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), mResourcesManager (resourcesManager), mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) @@ -1215,6 +1216,36 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const return ids; } +void CSMWorld::Data::assetsChanged() +{ + VFS::Manager* vfs = mResourcesManager.getVFS(); + vfs->rebuildIndex(); + + ResourceTable* meshTable = static_cast(getTableModel(UniversalId::Type_Meshes)); + ResourceTable* iconTable = static_cast(getTableModel(UniversalId::Type_Icons)); + ResourceTable* musicTable = static_cast(getTableModel(UniversalId::Type_Musics)); + ResourceTable* soundResTable = static_cast(getTableModel(UniversalId::Type_SoundsRes)); + ResourceTable* texTable = static_cast(getTableModel(UniversalId::Type_Textures)); + ResourceTable* vidTable = static_cast(getTableModel(UniversalId::Type_Videos)); + + meshTable->beginReset(); + iconTable->beginReset(); + musicTable->beginReset(); + soundResTable->beginReset(); + texTable->beginReset(); + vidTable->beginReset(); + + // Trigger recreation + mResourcesManager.recreateResources(); + + meshTable->endReset(); + iconTable->endReset(); + musicTable->endReset(); + soundResTable->endReset(); + texTable->endReset(); + vidTable->endReset(); +} + void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (topLeft.column()<=0) diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index f96003e44..8bc1c4271 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -108,7 +108,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; - const ResourcesManager& mResourcesManager; + ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector mModels; std::map mModelIndex; @@ -140,7 +140,7 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); + Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); virtual ~Data(); @@ -306,6 +306,8 @@ namespace CSMWorld private slots: + void assetsChanged(); + void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void rowsChanged (const QModelIndex& parent, int start, int end); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 5fe9194d7..5bf0267bb 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -12,6 +12,14 @@ CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& base const char * const *extensions) : mBaseDirectory (baseDirectory), mType (type) { + recreate(vfs, extensions); +} + +void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const *extensions) +{ + mFiles.clear(); + mIndex.clear(); + int baseSize = mBaseDirectory.size(); const std::map& index = vfs->getIndex(); diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index d6998da9f..5e9872ea8 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -27,6 +27,8 @@ namespace CSMWorld Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type, const char * const *extensions = 0); + void recreate(const VFS::Manager* vfs, const char * const *extensions = 0); + int getSize() const; std::string getId (int index) const; diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 016799be3..6b271c276 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -14,7 +14,7 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) resources)); } -void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) +void CSMWorld::ResourcesManager::setVFS(VFS::Manager *vfs) { mVFS = vfs; mResources.clear(); @@ -31,11 +31,26 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } -const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const +VFS::Manager* CSMWorld::ResourcesManager::getVFS() const { return mVFS; } +void CSMWorld::ResourcesManager::recreateResources() +{ + // TODO make this shared with setVFS function + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; + + std::map::iterator it = mResources.begin(); + for ( ; it != mResources.end(); ++it) + { + if (it->first == UniversalId::Type_Mesh) + it->second.recreate(mVFS, sMeshTypes); + else + it->second.recreate(mVFS); + } +} + const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const { std::map::const_iterator iter = mResources.find (type); diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 1ce06f2d3..969666856 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -16,7 +16,7 @@ namespace CSMWorld class ResourcesManager { std::map mResources; - const VFS::Manager* mVFS; + VFS::Manager* mVFS; private: @@ -26,9 +26,11 @@ namespace CSMWorld ResourcesManager(); - const VFS::Manager* getVFS() const; + VFS::Manager* getVFS() const; - void setVFS(const VFS::Manager* vfs); + void setVFS(VFS::Manager* vfs); + + void recreateResources(); const Resources& get (UniversalId::Type type) const; }; diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index 5227ec3e6..f55f87873 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -154,3 +154,13 @@ int CSMWorld::ResourceTable::getColumnId (int column) const return -1; } + +void CSMWorld::ResourceTable::beginReset() +{ + beginResetModel(); +} + +void CSMWorld::ResourceTable::endReset() +{ + endResetModel(); +} diff --git a/apps/opencs/model/world/resourcetable.hpp b/apps/opencs/model/world/resourcetable.hpp index 88dcc24b0..7d538df53 100644 --- a/apps/opencs/model/world/resourcetable.hpp +++ b/apps/opencs/model/world/resourcetable.hpp @@ -52,7 +52,12 @@ namespace CSMWorld /// Is \a id flagged as deleted? virtual bool isDeleted (const std::string& id) const; - virtual int getColumnId (int column) const; + virtual int getColumnId (int column) const; + + /// Signal Qt that the data is about to change. + void beginReset(); + /// Signal Qt that the data has been changed. + void endReset(); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ff49a90fd..92ed07daf 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -284,6 +284,13 @@ void CSVDoc::View::setupAssetsMenu() { QMenu *assets = menuBar()->addMenu (tr ("Assets")); + QAction *reload = new QAction (tr ("Reload"), this); + connect (reload, SIGNAL (triggered()), &mDocument->getData(), SLOT (assetsChanged())); + setupShortcut("document-assets-reload", reload); + assets->addAction (reload); + + assets->addSeparator(); + QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); setupShortcut("document-assets-sounds", sounds); @@ -889,6 +896,7 @@ void CSVDoc::View::addMetaDataSubView() addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta")); } + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index b36c7117b..9bdf12c23 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -21,6 +21,9 @@ namespace VFS public: virtual ~Archive() {} + /// Clears cached data for archives that may change. + virtual void resetIfNotStatic(){}; + /// List all resources contained in this archive, and run the resource names through the given normalize function. virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; }; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index ad5150a44..9240909ad 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -12,6 +12,12 @@ namespace VFS } + void FileSystemArchive::resetIfNotStatic() + { + mIndex.clear(); + mBuiltIndex = false; + } + void FileSystemArchive::listResources(std::map &out, char (*normalize_function)(char)) { if (!mBuiltIndex) diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 6c8e1b82b..16c2d65ea 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -23,6 +23,8 @@ namespace VFS public: FileSystemArchive(const std::string& path); + virtual void resetIfNotStatic(); + virtual void listResources(std::map& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 457947d40..037fef325 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -57,6 +57,14 @@ namespace VFS (*it)->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); } + void Manager::rebuildIndex() + { + for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) + (*it)->resetIfNotStatic(); + + buildIndex(); + } + Files::IStreamPtr Manager::get(const std::string &name) const { std::string normalized = name; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 6592a65a8..2ad7cf643 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -33,6 +33,9 @@ namespace VFS /// Build the file index. Should be called when all archives have been registered. void buildIndex(); + /// Rebuild the file index. New/deleted files (actual files, not bsa's) will be reflected. + void rebuildIndex(); + /// Does a file with this name exist? /// @note May be called from any thread once the index has been built. bool exists(const std::string& name) const; From e0bb9c089bcc7459de77609a9d2c2df0245a0b39 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 19 Aug 2017 14:31:25 +0400 Subject: [PATCH 060/521] Revert commit 67d59bead51ce4948c0e0256ee014bdab3bc8b5f (a better implementation found) --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/class.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 ++--- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 4 ++-- apps/openmw/mwgui/textinput.cpp | 4 ++-- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 95dc8cc4d..7379f3613 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,7 +64,7 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { - MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getOnlyText()); + MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); switch (result) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index ac61041c3..e1f5a165e 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -483,7 +483,7 @@ namespace MWGui std::string CreateClassDialog::getName() const { - return mEditName->getOnlyText(); + return mEditName->getCaption(); } std::string CreateClassDialog::getDescription() const diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 5dc1f3454..c7d2ef7de 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -313,7 +312,7 @@ namespace MWGui return; } - if (mName->getOnlyText().empty()) + if (mName->getCaption ().empty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -337,7 +336,7 @@ namespace MWGui return; } - mEnchanting.setNewItemName(mName->getOnlyText()); + mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 6391f8597..cb7c6c0d0 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -58,7 +58,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::EditBox* mName; + MyGUI::TextBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 4d1a490aa..84d4ca959 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -248,7 +248,7 @@ namespace MWGui dialog->eventCancelClicked.clear(); return; } - if (mSaveNameEdit->getOnlyText().empty()) + if (mSaveNameEdit->getCaption().empty()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}"); return; @@ -275,7 +275,7 @@ namespace MWGui if (mSaving) { - MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getOnlyText(), mCurrentSlot); + MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot); } else { diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index cd2d2cd1d..354253fa4 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -373,7 +373,7 @@ namespace MWGui return; } - if (mNameEdit->getOnlyText() == "") + if (mNameEdit->getCaption () == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; @@ -394,7 +394,7 @@ namespace MWGui return; } - mSpell.mName = mNameEdit->getOnlyText(); + mSpell.mName = mNameEdit->getCaption(); int price = MyGUI::utility::parseInt(mPriceLabel->getCaption()); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 9ddfac612..958b52dc0 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -53,7 +53,7 @@ namespace MWGui void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { - if (mTextEdit->getOnlyText() == "") + if (mTextEdit->getCaption() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); @@ -69,7 +69,7 @@ namespace MWGui std::string TextInputDialog::getTextInput() const { - return mTextEdit->getOnlyText(); + return mTextEdit->getCaption(); } void TextInputDialog::setTextInput(const std::string &text) From 65d05ee1cd5abe81456537fa75b6b326c1de9370 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 19 Aug 2017 14:30:04 +0400 Subject: [PATCH 061/521] Get only text from clipboard (bug #4025) --- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..e4f6eafde 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1983,12 +1983,8 @@ namespace MWGui char* text=0; text = SDL_GetClipboardText(); if (text) - { - // MyGUI's clipboard might still have color information, to retain that information, only set the new text - // if it actually changed (clipboard inserted by an external application) - if (MyGUI::TextIterator::getOnlyText(_data) != text) - _data = text; - } + _data = MyGUI::TextIterator::toTagsString(text); + SDL_free(text); } From f3361ed085ba47d4e33f10dffe1c9674998a7263 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 19 Aug 2017 18:28:40 +0100 Subject: [PATCH 062/521] Add an EditorConfig file --- .editorconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..25cc3fffc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*.cpp] +indent_style = space +indent_size = 4 +insert_final_newline = true + +[*.hpp] +indent_style = space +indent_size = 4 +insert_final_newline = true \ No newline at end of file From 91597af051d012df6897c9afaf7170e4f70366b2 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 19 Aug 2017 18:48:29 +0100 Subject: [PATCH 063/521] Add VS2017 aps files to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ca2c6502e..9fbb82dba 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ Doxygen .settings .directory .idea +files/windows/*.aps ## qt-creator CMakeLists.txt.user* From 2a85c5f011ad4381460d8ded00cdec6052b4f99b Mon Sep 17 00:00:00 2001 From: Harry Date: Sat, 19 Aug 2017 14:48:00 -0400 Subject: [PATCH 064/521] Implement a Fisher-Yates shuffle on background music This fixes sometimes getting repetitive background music --- apps/openmw/mwsound/soundmanagerimp.cpp | 26 ++++++++++++++++--------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c6f663059..1cba2e13a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -271,7 +271,6 @@ namespace MWSound return sound; } - // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -298,7 +297,6 @@ namespace MWSound return volume; } - void SoundManager::stopMusic() { if(mMusic) @@ -367,7 +365,9 @@ namespace MWSound } mMusicFiles[mCurrentPlaylist] = filelist; - + mMusicToPlay.reserve(mMusicToPlay.size() + filelist.size()); + for(int it = 0; it < filelist.size(); it++) + mMusicToPlay.push_back(it); } else filelist = mMusicFiles[mCurrentPlaylist]; @@ -375,15 +375,23 @@ namespace MWSound if(filelist.empty()) return; - int i = Misc::Rng::rollDice(filelist.size()); - - // Don't play the same music track twice in a row - if (filelist[i] == mLastPlayedMusic) + // Do a Fisher-Yates shuffle + if(mMusicFiles.size() == 0) { - i = (i+1) % filelist.size(); + mMusicToPlay.reserve(filelist.size()); + for (int it = 0; it < filelist.size(); it++) + mMusicToPlay.push_back(it); } - advanceMusic(filelist[i]); + int i = Misc::Rng::rollDice(mMusicToPlay.size()); + + // Fix last played music being the same after another shuffle + if(filelist[mMusicToPlay[i]] == mLastPlayedMusic) + i = (i+1) % mMusicToPlay.size(); + + advanceMusic(filelist[mMusicToPlay[i]]); + mMusicToPlay[i] = mMusicToPlay.back(); + mMusicToPlay.pop_back(); } bool SoundManager::isMusicPlaying() diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5d911d4be..46a03818b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,6 +49,7 @@ namespace MWSound // Caches available music tracks by std::map > mMusicFiles; + std::vector mMusicToPlay; // The list of music files not played yet std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; From 742bd00ec6e7b1802f8bf8a78d76a400885f0b25 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 19 Aug 2017 15:26:46 -0400 Subject: [PATCH 065/521] Clear cached resources --- apps/opencs/model/world/data.cpp | 3 +++ components/resource/resourcemanager.cpp | 5 +++++ components/resource/resourcemanager.hpp | 3 +++ components/resource/resourcesystem.cpp | 10 ++++++++++ components/resource/resourcesystem.hpp | 3 +++ 5 files changed, 24 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8c25faaa5..633b1ae20 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1244,6 +1244,9 @@ void CSMWorld::Data::assetsChanged() soundResTable->endReset(); texTable->endReset(); vidTable->endReset(); + + // Get rid of potentially old cached assets + mResourceSystem->clearCache(); } void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index d19d9cf80..4e48d9745 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -23,6 +23,11 @@ namespace Resource mCache->removeExpiredObjectsInCache(referenceTime - mExpiryDelay); } + void ResourceManager::clearCache() + { + mCache->clear(); + } + void ResourceManager::setExpiryDelay(double expiryDelay) { mExpiryDelay = expiryDelay; diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index 61599cd5e..58200993b 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -28,6 +28,9 @@ namespace Resource /// Clear cache entries that have not been referenced for longer than expiryDelay. virtual void updateCache(double referenceTime); + /// Clear all cache entries. + virtual void clearCache(); + /// How long to keep objects in cache after no longer being referenced. void setExpiryDelay (double expiryDelay); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 8d05a1b4e..a9686e5db 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,6 +2,8 @@ #include +#include + #include "scenemanager.hpp" #include "imagemanager.hpp" #include "niffilemanager.hpp" @@ -68,6 +70,14 @@ namespace Resource (*it)->updateCache(referenceTime); } + void ResourceSystem::clearCache() + { + for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + (*it)->clearCache(); + + osgDB::Registry::instance()->clearObjectCache(); + } + void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) { mResourceManagers.push_back(resourceMgr); diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index dc608b875..ef9ac9647 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -41,6 +41,9 @@ namespace Resource /// @note May be called from any thread if you do not add or remove resource managers at that point. void updateCache(double referenceTime); + /// Indicates to each resource manager to clear the entire cache. + void clearCache(); + /// Add this ResourceManager to be handled by the ResourceSystem. /// @note Does not transfer ownership. void addResourceManager(ResourceManager* resourceMgr); From 5950b26912893b40333586c32e49c737a232d148 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 19 Aug 2017 19:36:45 -0400 Subject: [PATCH 066/521] Update scene assets --- apps/opencs/model/world/data.cpp | 2 ++ apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/view/render/cell.cpp | 9 +++++++++ apps/opencs/view/render/cell.hpp | 2 ++ apps/opencs/view/render/object.cpp | 6 ++++++ apps/opencs/view/render/object.hpp | 3 +++ apps/opencs/view/render/pagedworldspacewidget.cpp | 14 +++++++++++++- apps/opencs/view/render/pagedworldspacewidget.hpp | 4 +++- apps/opencs/view/render/previewwidget.cpp | 8 ++++++++ apps/opencs/view/render/previewwidget.hpp | 2 ++ .../opencs/view/render/unpagedworldspacewidget.cpp | 9 +++++++++ .../opencs/view/render/unpagedworldspacewidget.hpp | 2 ++ components/resource/resourcesystem.cpp | 2 -- 13 files changed, 61 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 633b1ae20..61db4ff77 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1247,6 +1247,8 @@ void CSMWorld::Data::assetsChanged() // Get rid of potentially old cached assets mResourceSystem->clearCache(); + + emit assetTablesChanged(); } void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8bc1c4271..8fe5eeff9 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -304,6 +304,8 @@ namespace CSMWorld void idListChanged(); + void assetTablesChanged(); + private slots: void assetsChanged(); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 48156359f..4b06432d6 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -283,6 +283,15 @@ void CSVRender::Cell::pathgridRemoved() mPathgrid->removeGeometry(); } +void CSVRender::Cell::reloadAssets() +{ + for (std::map::const_iterator iter (mObjects.begin()); + iter != mObjects.end(); ++iter) + { + iter->second->reloadAssets(); + } +} + void CSVRender::Cell::setSelection (int elementMask, Selection mode) { if (elementMask & Mask_Reference) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index ca82dd580..f53f61973 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -118,6 +118,8 @@ namespace CSVRender void pathgridRemoved(); + void reloadAssets(); + void setSelection (int elementMask, Selection mode); // Select everything that references the same ID as at least one of the elements diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index eb90e9db3..522057097 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -532,6 +532,12 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, return false; } +void CSVRender::Object::reloadAssets() +{ + update(); + updateMarker(); +} + std::string CSVRender::Object::getReferenceId() const { return mReferenceId; diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index e28e2562c..e14697e62 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -151,6 +151,9 @@ namespace CSVRender /// this object? bool referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + /// Reloads the underlying asset + void reloadAssets(); + /// Returns an empty string if this is a refereceable-type object. std::string getReferenceId() const; diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b5497558a..b1077139c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -472,6 +472,9 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); + connect (&document.getData(), SIGNAL (assetTablesChanged ()), + this, SLOT (assetTablesChanged ())); + // Shortcuts CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this); connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell())); @@ -520,7 +523,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) // Loop through all the coordinates to add them to selection while (stream >> ignore1 >> ignore2 >> x >> y) selection.add (CSMWorld::CellCoordinates (x, y)); - + // Mark that camera needs setup mCamPositionSet=false; } @@ -763,6 +766,15 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int flagAsModified(); } +void CSVRender::PagedWorldspaceWidget::assetTablesChanged() +{ + std::map::iterator iter = mCells.begin(); + for ( ; iter != mCells.end(); ++iter) + { + iter->second->reloadAssets(); + } +} + void CSVRender::PagedWorldspaceWidget::loadCameraCell() { addCellToSceneFromCamera(0, 0); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 0663d3424..8c41df51e 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -84,7 +84,7 @@ namespace CSVRender /// hint system. virtual ~PagedWorldspaceWidget(); - + /// Decodes the the hint string to set of cell that are rendered. void useViewHint (const std::string& hint); @@ -155,6 +155,8 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + void assetTablesChanged (); + void loadCameraCell(); void loadEastCell(); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 2f3510317..972fb556d 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -17,6 +17,9 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int))); + connect (&mData, SIGNAL (assetTablesChanged ()), + this, SLOT (assetTablesChanged ())); + if (!referenceable) { QAbstractItemModel *references = @@ -119,3 +122,8 @@ void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& par if (index.row()>=start && index.row()<=end) emit closeRequest(); } + +void CSVRender::PreviewWidget::assetTablesChanged () +{ + mObject.reloadAssets(); +} diff --git a/apps/opencs/view/render/previewwidget.hpp b/apps/opencs/view/render/previewwidget.hpp index 73f7dc810..630ccf293 100644 --- a/apps/opencs/view/render/previewwidget.hpp +++ b/apps/opencs/view/render/previewwidget.hpp @@ -47,6 +47,8 @@ namespace CSVRender void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void assetTablesChanged (); }; } diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index b82aa45b2..3201f7303 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -47,6 +47,9 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& connect (mCellsModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (cellRowsAboutToBeRemoved (const QModelIndex&, int, int))); + connect (&document.getData(), SIGNAL (assetTablesChanged ()), + this, SLOT (assetTablesChanged ())); + update(); mCell.reset (new Cell (document.getData(), mRootNode, mCellId)); @@ -82,6 +85,12 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI emit closeRequest(); } +void CSVRender::UnpagedWorldspaceWidget::assetTablesChanged() +{ + if (mCell) + mCell->reloadAssets(); +} + bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector& universalIdData, DropType type) { if (WorldspaceWidget::handleDrop (universalIdData, type)) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 5283b3a97..527463990 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -108,6 +108,8 @@ namespace CSVRender void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + void assetTablesChanged (); + signals: void cellChanged(const CSMWorld::UniversalId& id); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index a9686e5db..b1061adcd 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -74,8 +74,6 @@ namespace Resource { for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->clearCache(); - - osgDB::Registry::instance()->clearObjectCache(); } void ResourceSystem::addResourceManager(ResourceManager *resourceMgr) From 765f982123c3e13c027345c354c9e95dce907c34 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 20 Aug 2017 20:48:14 +0400 Subject: [PATCH 067/521] Removed cursor from Favorite Attributes label --- files/mygui/openmw_chargen_class.layout | 1 + files/mygui/openmw_chargen_create_class.layout | 1 + 2 files changed, 2 insertions(+) diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index 35dd57ca3..d875fae22 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -34,6 +34,7 @@ + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index 9ca6c6a31..e2920c742 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -33,6 +33,7 @@ + From 6ef5d1408f7dbec911b14c8d6f13838ae80e19b9 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 20 Aug 2017 21:25:36 +0400 Subject: [PATCH 068/521] Disabled transparency for description edit fields --- files/mygui/openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_edit_note.layout | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 3d341eee5..43b0518fd 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index eb2a2789d..7039c719e 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -1,7 +1,7 @@ - + From f0dea8b8e6797bb8f4ee4cbfe2c03c988522bfa5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 20 Aug 2017 20:20:27 +0000 Subject: [PATCH 069/521] Revert "Implement a Fisher-Yates shuffle on background music" --- apps/openmw/mwsound/soundmanagerimp.cpp | 26 +++++++++---------------- apps/openmw/mwsound/soundmanagerimp.hpp | 1 - 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1cba2e13a..c6f663059 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -271,6 +271,7 @@ namespace MWSound return sound; } + // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -297,6 +298,7 @@ namespace MWSound return volume; } + void SoundManager::stopMusic() { if(mMusic) @@ -365,9 +367,7 @@ namespace MWSound } mMusicFiles[mCurrentPlaylist] = filelist; - mMusicToPlay.reserve(mMusicToPlay.size() + filelist.size()); - for(int it = 0; it < filelist.size(); it++) - mMusicToPlay.push_back(it); + } else filelist = mMusicFiles[mCurrentPlaylist]; @@ -375,23 +375,15 @@ namespace MWSound if(filelist.empty()) return; - // Do a Fisher-Yates shuffle - if(mMusicFiles.size() == 0) + int i = Misc::Rng::rollDice(filelist.size()); + + // Don't play the same music track twice in a row + if (filelist[i] == mLastPlayedMusic) { - mMusicToPlay.reserve(filelist.size()); - for (int it = 0; it < filelist.size(); it++) - mMusicToPlay.push_back(it); + i = (i+1) % filelist.size(); } - int i = Misc::Rng::rollDice(mMusicToPlay.size()); - - // Fix last played music being the same after another shuffle - if(filelist[mMusicToPlay[i]] == mLastPlayedMusic) - i = (i+1) % mMusicToPlay.size(); - - advanceMusic(filelist[mMusicToPlay[i]]); - mMusicToPlay[i] = mMusicToPlay.back(); - mMusicToPlay.pop_back(); + advanceMusic(filelist[i]); } bool SoundManager::isMusicPlaying() diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 46a03818b..5d911d4be 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -49,7 +49,6 @@ namespace MWSound // Caches available music tracks by std::map > mMusicFiles; - std::vector mMusicToPlay; // The list of music files not played yet std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; From d7744e8b16a1f4887abbc036b755d3356eada244 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 19:07:23 -0400 Subject: [PATCH 070/521] A bit of cleanup --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/data.cpp | 9 ++++---- apps/opencs/model/world/data.hpp | 3 ++- apps/opencs/model/world/resourcesmanager.cpp | 22 ++++++++++---------- apps/opencs/model/world/resourcesmanager.hpp | 8 ++++--- components/resource/resourcesystem.cpp | 2 -- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a7809f3e3..d9f86cdde 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -275,7 +275,7 @@ CSMDoc::Document::Document (VFS::Manager* vfs, const Files::ConfigurationManager const Fallback::Map* fallback, ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, const std::vector& blacklistedScripts) -: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback, resDir), +: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, vfs, resourcesManager, fallback, resDir), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 61db4ff77..d7f42d027 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -62,9 +62,9 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) +CSMWorld::Data::Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mResourcesManager (resourcesManager), mFallbackMap(fallback), + mVFS(vfs), mResourcesManager (resourcesManager), mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) { mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string()); @@ -1218,8 +1218,7 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const void CSMWorld::Data::assetsChanged() { - VFS::Manager* vfs = mResourcesManager.getVFS(); - vfs->rebuildIndex(); + mVFS->rebuildIndex(); ResourceTable* meshTable = static_cast(getTableModel(UniversalId::Type_Meshes)); ResourceTable* iconTable = static_cast(getTableModel(UniversalId::Type_Icons)); @@ -1264,7 +1263,7 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) const VFS::Manager* CSMWorld::Data::getVFS() const { - return mResourcesManager.getVFS(); + return mVFS; } const Fallback::Map* CSMWorld::Data::getFallbackMap() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8fe5eeff9..771a706b3 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -108,6 +108,7 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; + VFS::Manager* mVFS; ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector mModels; @@ -140,7 +141,7 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); + Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); virtual ~Data(); diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index 6b271c276..c50b86682 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -14,16 +14,19 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources) resources)); } -void CSMWorld::ResourcesManager::setVFS(VFS::Manager *vfs) +const char * const * CSMWorld::ResourcesManager::getMeshExtensions() { - mVFS = vfs; - mResources.clear(); - // maybe we could go over the osgDB::Registry to list all supported node formats - static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; + return sMeshTypes; +} - addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes)); +void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) +{ + mVFS = vfs; + mResources.clear(); + + addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, getMeshExtensions())); addResources (Resources (vfs, "icons", UniversalId::Type_Icon)); addResources (Resources (vfs, "music", UniversalId::Type_Music)); addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes)); @@ -31,21 +34,18 @@ void CSMWorld::ResourcesManager::setVFS(VFS::Manager *vfs) addResources (Resources (vfs, "videos", UniversalId::Type_Video)); } -VFS::Manager* CSMWorld::ResourcesManager::getVFS() const +const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const { return mVFS; } void CSMWorld::ResourcesManager::recreateResources() { - // TODO make this shared with setVFS function - static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", 0 }; - std::map::iterator it = mResources.begin(); for ( ; it != mResources.end(); ++it) { if (it->first == UniversalId::Type_Mesh) - it->second.recreate(mVFS, sMeshTypes); + it->second.recreate(mVFS, getMeshExtensions()); else it->second.recreate(mVFS); } diff --git a/apps/opencs/model/world/resourcesmanager.hpp b/apps/opencs/model/world/resourcesmanager.hpp index 969666856..0e8385300 100644 --- a/apps/opencs/model/world/resourcesmanager.hpp +++ b/apps/opencs/model/world/resourcesmanager.hpp @@ -16,19 +16,21 @@ namespace CSMWorld class ResourcesManager { std::map mResources; - VFS::Manager* mVFS; + const VFS::Manager* mVFS; private: void addResources (const Resources& resources); + const char * const * getMeshExtensions(); + public: ResourcesManager(); - VFS::Manager* getVFS() const; + const VFS::Manager* getVFS() const; - void setVFS(VFS::Manager* vfs); + void setVFS(const VFS::Manager* vfs); void recreateResources(); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index b1061adcd..d7a6771c4 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -2,8 +2,6 @@ #include -#include - #include "scenemanager.hpp" #include "imagemanager.hpp" #include "niffilemanager.hpp" From 7914fd5c9c42ea4c678a925253d495429c049248 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 19:36:21 -0400 Subject: [PATCH 071/521] Re-index BSAs --- components/vfs/archive.hpp | 4 ++-- components/vfs/bsaarchive.cpp | 24 ++++++++++++++++++------ components/vfs/bsaarchive.hpp | 5 +++++ components/vfs/filesystemarchive.cpp | 2 +- components/vfs/filesystemarchive.hpp | 2 +- components/vfs/manager.cpp | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index 9bdf12c23..f2082f750 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -21,8 +21,8 @@ namespace VFS public: virtual ~Archive() {} - /// Clears cached data for archives that may change. - virtual void resetIfNotStatic(){}; + /// Clears cached data. + virtual void reset() = 0; /// List all resources contained in this archive, and run the resource names through the given normalize function. virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index a527a6ad9..88e6bf2c7 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -5,14 +5,15 @@ namespace VFS BsaArchive::BsaArchive(const std::string &filename) + : mFileName(filename) { - mFile.open(filename); + load(); +} - const Bsa::BSAFile::FileList &filelist = mFile.getList(); - for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) - { - mResources.push_back(BsaArchiveFile(&*it, &mFile)); - } +void BsaArchive::reset() +{ + mResources.clear(); + load(); } void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) @@ -26,6 +27,17 @@ void BsaArchive::listResources(std::map &out, char (*normal } } +void BsaArchive::load() +{ + mFile.open(mFileName); + + const Bsa::BSAFile::FileList &filelist = mFile.getList(); + for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) + { + mResources.push_back(BsaArchiveFile(&*it, &mFile)); + } +} + // ------------------------------------------------------------------------------ BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index a6e274037..92204f90c 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -24,9 +24,14 @@ namespace VFS public: BsaArchive(const std::string& filename); + virtual void reset(); + virtual void listResources(std::map& out, char (*normalize_function) (char)); private: + void load(); + + std::string mFileName; Bsa::BSAFile mFile; std::vector mResources; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 9240909ad..8fb992e76 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -12,7 +12,7 @@ namespace VFS } - void FileSystemArchive::resetIfNotStatic() + void FileSystemArchive::reset() { mIndex.clear(); mBuiltIndex = false; diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 16c2d65ea..5843bf871 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -23,7 +23,7 @@ namespace VFS public: FileSystemArchive(const std::string& path); - virtual void resetIfNotStatic(); + virtual void reset(); virtual void listResources(std::map& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 037fef325..9b1798e8f 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -60,7 +60,7 @@ namespace VFS void Manager::rebuildIndex() { for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) - (*it)->resetIfNotStatic(); + (*it)->reset(); buildIndex(); } From b62cb0e2a47d5252d686ee2770ddc6fb6711a194 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 19:55:16 -0400 Subject: [PATCH 072/521] Clear out GPU texture/stateset cache --- components/resource/scenemanager.cpp | 16 ++++++++++++++++ components/resource/scenemanager.hpp | 2 ++ 2 files changed, 18 insertions(+) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 226933760..2f04aa7c2 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -122,6 +122,13 @@ namespace Resource { return _sharedStateSetList.size(); } + + void clearCache() + { + OpenThreads::ScopedLock lock(_listMutex); + _sharedTextureList.clear(); + _sharedStateSetList.clear(); + } }; /// Set texture filtering settings on textures contained in a FlipController. @@ -710,6 +717,15 @@ namespace Resource mSharedStateMutex.unlock(); } + void SceneManager::clearCache() + { + ResourceManager::clearCache(); + + mSharedStateMutex.lock(); + mSharedStateManager->clearCache(); + mSharedStateMutex.unlock(); + } + void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const { { diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index c6ff02acf..14032df77 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -143,6 +143,8 @@ namespace Resource /// @see ResourceManager::updateCache virtual void updateCache(double referenceTime); + virtual void clearCache(); + virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; private: From d4a722067db0aeeac725ea654ab70f36a8eee968 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 20:55:56 -0400 Subject: [PATCH 073/521] Reload water --- apps/opencs/view/render/cell.cpp | 2 ++ apps/opencs/view/render/cellwater.cpp | 5 +++++ apps/opencs/view/render/cellwater.hpp | 2 ++ 3 files changed, 9 insertions(+) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 4b06432d6..ebc383ff2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -290,6 +290,8 @@ void CSVRender::Cell::reloadAssets() { iter->second->reloadAssets(); } + + mCellWater->reloadAssets(); } void CSVRender::Cell::setSelection (int elementMask, Selection mode) diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 15ea15cc4..d7e8669ef 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -92,6 +92,11 @@ namespace CSVRender } } + void CellWater::reloadAssets() + { + recreate(); + } + void CellWater::cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { const CSMWorld::Collection& cells = mData.getCells(); diff --git a/apps/opencs/view/render/cellwater.hpp b/apps/opencs/view/render/cellwater.hpp index d2ed9b458..47e586707 100644 --- a/apps/opencs/view/render/cellwater.hpp +++ b/apps/opencs/view/render/cellwater.hpp @@ -42,6 +42,8 @@ namespace CSVRender void updateCellData(const CSMWorld::Record& cellRecord); + void reloadAssets(); + private slots: void cellDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); From 3b9326d238f0dd2da0afd47e0a96dda8aa401e0b Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 20 Aug 2017 22:34:41 -0400 Subject: [PATCH 074/521] Clear terrain cache and reload terrain --- apps/opencs/view/render/cell.cpp | 7 +++++++ components/terrain/buffercache.cpp | 12 ++++++++++++ components/terrain/buffercache.hpp | 2 ++ components/terrain/chunkmanager.cpp | 7 +++++++ components/terrain/chunkmanager.hpp | 2 ++ components/terrain/world.cpp | 6 ++++++ components/terrain/world.hpp | 3 +++ 7 files changed, 39 insertions(+) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index ebc383ff2..5aa534232 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -291,6 +291,13 @@ void CSVRender::Cell::reloadAssets() iter->second->reloadAssets(); } + if (mTerrain) + { + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + mTerrain->clearCache(); + mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY()); + } + mCellWater->reloadAssets(); } diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 470655539..361dd6c04 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -231,4 +231,16 @@ namespace Terrain return buffer; } + void BufferCache::clearCache() + { + { + OpenThreads::ScopedLock lock(mIndexBufferMutex); + mIndexBufferMap.clear(); + } + { + OpenThreads::ScopedLock lock(mUvBufferMutex); + mUvBufferMap.clear(); + } + } + } diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index e8963354b..bfdf558bc 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -22,6 +22,8 @@ namespace Terrain /// @note Thread safe. osg::ref_ptr getUVBuffer(unsigned int numVerts); + void clearCache(); + // TODO: add releaseGLObjects() for our vertex/element buffer objects private: diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index e4a7c2d68..ea71c726f 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -55,6 +55,13 @@ void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats) cons stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize()); } +void ChunkManager::clearCache() +{ + ResourceManager::clearCache(); + + mBufferCache.clearCache(); +} + void ChunkManager::setCullingActive(bool active) { mCullingActive = active; diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 553e06d97..2f92fa836 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -34,6 +34,8 @@ namespace Terrain virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + virtual void clearCache(); + void setCullingActive(bool active); private: diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index b7cc0ae01..9bbb585a8 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -70,6 +70,12 @@ float World::getHeightAt(const osg::Vec3f &worldPos) return mStorage->getHeightAt(worldPos); } +void World::clearCache() +{ + mTextureManager->clearCache(); + mChunkManager->clearCache(); +} + void World::updateTextureFiltering() { mTextureManager->updateTextureFiltering(); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index d0576fbd3..2fb669494 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -67,6 +67,9 @@ namespace Terrain /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} + /// Clears cached texture and chunk data. + virtual void clearCache(); + /// Load the cell into the scene graph. /// @note Not thread safe. /// @note May be ignored by derived implementations that don't organize the terrain into cells. From 679a2847355e722bd1bd600a246985828c36f79d Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 21 Aug 2017 13:33:11 -0400 Subject: [PATCH 075/521] Use scoped lock instead of directly locking/unlocking mutex --- components/resource/scenemanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 2f04aa7c2..aba1d454e 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -721,9 +721,8 @@ namespace Resource { ResourceManager::clearCache(); - mSharedStateMutex.lock(); + OpenThreads::ScopedLock lock(mSharedStateMutex); mSharedStateManager->clearCache(); - mSharedStateMutex.unlock(); } void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const From 979b0d7211ab0a8db8dd27bb7a69db3c70bf2ad3 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 21 Aug 2017 18:58:38 -0400 Subject: [PATCH 076/521] Code cleanup and more cache clearing --- apps/opencs/model/world/data.cpp | 40 ++++++++++++---------- apps/opencs/view/doc/view.cpp | 1 - apps/opencs/view/render/cell.cpp | 1 - components/resource/bulletshapemanager.cpp | 7 ++++ components/resource/bulletshapemanager.hpp | 2 ++ components/resource/multiobjectcache.cpp | 6 ++++ components/resource/multiobjectcache.hpp | 3 ++ components/resource/resourcesystem.hpp | 1 + components/resource/scenemanager.cpp | 1 + components/terrain/world.cpp | 6 ---- components/terrain/world.hpp | 3 -- 11 files changed, 41 insertions(+), 30 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d7f42d027..39c0291fc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1220,29 +1220,31 @@ void CSMWorld::Data::assetsChanged() { mVFS->rebuildIndex(); - ResourceTable* meshTable = static_cast(getTableModel(UniversalId::Type_Meshes)); - ResourceTable* iconTable = static_cast(getTableModel(UniversalId::Type_Icons)); - ResourceTable* musicTable = static_cast(getTableModel(UniversalId::Type_Musics)); - ResourceTable* soundResTable = static_cast(getTableModel(UniversalId::Type_SoundsRes)); - ResourceTable* texTable = static_cast(getTableModel(UniversalId::Type_Textures)); - ResourceTable* vidTable = static_cast(getTableModel(UniversalId::Type_Videos)); - - meshTable->beginReset(); - iconTable->beginReset(); - musicTable->beginReset(); - soundResTable->beginReset(); - texTable->beginReset(); - vidTable->beginReset(); + const UniversalId assetTableIds[] = { + UniversalId::Type_Meshes, + UniversalId::Type_Icons, + UniversalId::Type_Musics, + UniversalId::Type_SoundsRes, + UniversalId::Type_Textures, + UniversalId::Type_Videos + }; + + size_t numAssetTables = sizeof(assetTableIds) / sizeof(UniversalId); + + for (size_t i = 0; i < numAssetTables; ++i) + { + ResourceTable* table = static_cast(getTableModel(assetTableIds[i])); + table->beginReset(); + } // Trigger recreation mResourcesManager.recreateResources(); - meshTable->endReset(); - iconTable->endReset(); - musicTable->endReset(); - soundResTable->endReset(); - texTable->endReset(); - vidTable->endReset(); + for (size_t i = 0; i < numAssetTables; ++i) + { + ResourceTable* table = static_cast(getTableModel(assetTableIds[i])); + table->endReset(); + } // Get rid of potentially old cached assets mResourceSystem->clearCache(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 92ed07daf..dfbeea031 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -896,7 +896,6 @@ void CSVDoc::View::addMetaDataSubView() addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta")); } - void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 5aa534232..a10e38397 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -294,7 +294,6 @@ void CSVRender::Cell::reloadAssets() if (mTerrain) { mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); - mTerrain->clearCache(); mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY()); } diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 010917572..c1a7eb8f3 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -190,6 +190,13 @@ void BulletShapeManager::updateCache(double referenceTime) mInstanceCache->removeUnreferencedObjectsInCache(); } +void BulletShapeManager::clearCache() +{ + ResourceManager::clearCache(); + + mInstanceCache->clear(); +} + void BulletShapeManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const { stats->setAttribute(frameNumber, "Shape", mCache->getCacheSize()); diff --git a/components/resource/bulletshapemanager.hpp b/components/resource/bulletshapemanager.hpp index fec7251ac..8ae2b531f 100644 --- a/components/resource/bulletshapemanager.hpp +++ b/components/resource/bulletshapemanager.hpp @@ -42,6 +42,8 @@ namespace Resource /// @see ResourceManager::updateCache virtual void updateCache(double referenceTime); + virtual void clearCache(); + void reportStats(unsigned int frameNumber, osg::Stats *stats) const; private: diff --git a/components/resource/multiobjectcache.cpp b/components/resource/multiobjectcache.cpp index fcda455cc..266139f3c 100644 --- a/components/resource/multiobjectcache.cpp +++ b/components/resource/multiobjectcache.cpp @@ -43,6 +43,12 @@ namespace Resource objectsToRemove.clear(); } + void MultiObjectCache::clear() + { + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.clear(); + } + void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object) { OpenThreads::ScopedLock lock(_objectCacheMutex); diff --git a/components/resource/multiobjectcache.hpp b/components/resource/multiobjectcache.hpp index a314a9e4b..527247bf9 100644 --- a/components/resource/multiobjectcache.hpp +++ b/components/resource/multiobjectcache.hpp @@ -25,6 +25,9 @@ namespace Resource void removeUnreferencedObjectsInCache(); + /** Remove all objects from the cache. */ + void clear(); + void addEntryToObjectCache(const std::string& filename, osg::Object* object); /** Take an Object from cache. Return NULL if no object found. */ diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index ef9ac9647..efce50b97 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -42,6 +42,7 @@ namespace Resource void updateCache(double referenceTime); /// Indicates to each resource manager to clear the entire cache. + /// @note May be called from any thread if you do not add or remove resource managers at that point. void clearCache(); /// Add this ResourceManager to be handled by the ResourceSystem. diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index aba1d454e..69a54bf17 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -723,6 +723,7 @@ namespace Resource OpenThreads::ScopedLock lock(mSharedStateMutex); mSharedStateManager->clearCache(); + mInstanceCache->clear(); } void SceneManager::reportStats(unsigned int frameNumber, osg::Stats *stats) const diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 9bbb585a8..b7cc0ae01 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -70,12 +70,6 @@ float World::getHeightAt(const osg::Vec3f &worldPos) return mStorage->getHeightAt(worldPos); } -void World::clearCache() -{ - mTextureManager->clearCache(); - mChunkManager->clearCache(); -} - void World::updateTextureFiltering() { mTextureManager->updateTextureFiltering(); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 2fb669494..d0576fbd3 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -67,9 +67,6 @@ namespace Terrain /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} - /// Clears cached texture and chunk data. - virtual void clearCache(); - /// Load the cell into the scene graph. /// @note Not thread safe. /// @note May be ignored by derived implementations that don't organize the terrain into cells. From 8c4b12a6035588e1e9dfdcc2d4475ac6babd57e8 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 21 Aug 2017 22:31:19 -0400 Subject: [PATCH 077/521] VFS changes, one VFS and resource system per document. Added ability to reset a VFS::Manager. Removed ability to rebuild the index for a VFS::Manager. Moved VFS creation to CSM::Data. --- apps/opencs/editor.cpp | 9 +-------- apps/opencs/editor.hpp | 10 ---------- apps/opencs/model/doc/document.cpp | 16 ++++++---------- apps/opencs/model/doc/document.hpp | 12 +++++------- apps/opencs/model/doc/documentmanager.cpp | 11 ++++++----- apps/opencs/model/doc/documentmanager.hpp | 20 ++++++++++---------- apps/opencs/model/world/data.cpp | 19 ++++++++++++++----- apps/opencs/model/world/data.hpp | 13 ++++++++++--- components/vfs/archive.hpp | 3 --- components/vfs/bsaarchive.cpp | 6 ------ components/vfs/bsaarchive.hpp | 2 -- components/vfs/filesystemarchive.cpp | 6 ------ components/vfs/filesystemarchive.hpp | 2 -- components/vfs/manager.cpp | 14 ++++++-------- components/vfs/manager.hpp | 6 +++--- 15 files changed, 61 insertions(+), 88 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 54e323956..86c87962d 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -5,9 +5,6 @@ #include #include -#include -#include - #include #include @@ -33,11 +30,7 @@ CS::Editor::Editor () NifOsg::Loader::setShowMarkers(true); - mVFS.reset(new VFS::Manager(mFsStrict)); - - VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true); - - mDocumentManager.setVFS(mVFS.get()); + mDocumentManager.setFileData(mFsStrict, config.first, config.second); mNewGame.setLocalData (mLocal); mFileDialog.setLocalData (mLocal); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index ff670ba1b..b60f5c6a8 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,8 +1,6 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H -#include - #include #include @@ -30,11 +28,6 @@ #include "view/tools/merge.hpp" -namespace VFS -{ - class Manager; -} - namespace CSMDoc { class Document; @@ -46,9 +39,6 @@ namespace CS { Q_OBJECT - // FIXME: should be moved to document, so we can have different resources for each opened project - std::unique_ptr mVFS; - Files::ConfigurationManager mCfgMgr; CSMPrefs::State mSettingsState; CSMDoc::DocumentManager mDocumentManager; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d9f86cdde..7257b2fe3 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -269,13 +269,14 @@ void CSMDoc::Document::createBase() } } -CSMDoc::Document::Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, - const std::vector< boost::filesystem::path >& files, bool new_, +CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, + const std::vector< boost::filesystem::path >& files,bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const Fallback::Map* fallback, - ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, - const std::vector& blacklistedScripts) -: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, vfs, resourcesManager, fallback, resDir), + ToUTF8::FromType encoding, + const std::vector& blacklistedScripts, + bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives) +: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, fsStrict, dataPaths, archives, fallback, resDir), mTools (*this, encoding), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), @@ -337,11 +338,6 @@ CSMDoc::Document::~Document() { } -const VFS::Manager *CSMDoc::Document::getVFS() const -{ - return mVFS; -} - QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index ad0201407..d31fd5aca 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include "../world/data.hpp" @@ -59,7 +60,6 @@ namespace CSMDoc private: - VFS::Manager* mVFS; boost::filesystem::path mSavePath; std::vector mContentFiles; bool mNew; @@ -102,17 +102,15 @@ namespace CSMDoc public: - Document (VFS::Manager* vfs, const Files::ConfigurationManager& configuration, + Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, bool new_, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, - const Fallback::Map* fallback, - ToUTF8::FromType encoding, CSMWorld::ResourcesManager& resourcesManager, - const std::vector& blacklistedScripts); + const Fallback::Map* fallback, ToUTF8::FromType encoding, + const std::vector& blacklistedScripts, + bool fsStrict, const Files::PathContainer& dataPaths, const std::vector& archives); ~Document(); - const VFS::Manager* getVFS() const; - QUndoStack& getUndoStack(); int getState() const; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 11378cab4..531cfd267 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -9,7 +9,7 @@ #include "document.hpp" CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) -: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL) +: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252) { boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; @@ -62,7 +62,7 @@ CSMDoc::Document *CSMDoc::DocumentManager::makeDocument ( const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, bool new_) { - return new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mResourcesManager, mBlacklistedScripts); + return new Document (mConfiguration, files, new_, savePath, mResDir, &mFallbackMap, mEncoding, mBlacklistedScripts, mFsStrict, mDataPaths, mArchives); } void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document) @@ -127,8 +127,9 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std:: removeDocument (document); } -void CSMDoc::DocumentManager::setVFS(VFS::Manager *vfs) +void CSMDoc::DocumentManager::setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector& archives) { - mResourcesManager.setVFS(vfs); - mVFS = vfs; + mFsStrict = strict; + mDataPaths = dataPaths; + mArchives = archives; } diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 771afe8e5..ae6d9481a 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -11,8 +11,7 @@ #include #include - -#include "../world/resourcesmanager.hpp" +#include #include "loader.hpp" @@ -39,9 +38,14 @@ namespace CSMDoc QThread mLoaderThread; Loader mLoader; ToUTF8::FromType mEncoding; - CSMWorld::ResourcesManager mResourcesManager; std::vector mBlacklistedScripts; - VFS::Manager* mVFS; + + boost::filesystem::path mResDir; + Fallback::Map mFallbackMap; + + bool mFsStrict; + Files::PathContainer mDataPaths; + std::vector mArchives; DocumentManager (const DocumentManager&); DocumentManager& operator= (const DocumentManager&); @@ -74,15 +78,11 @@ namespace CSMDoc void setBlacklistedScripts (const std::vector& scriptIds); - void setVFS(VFS::Manager* vfs); + /// Sets the file data that gets passed to newly created documents. + void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector& archives); bool isEmpty(); - private: - - boost::filesystem::path mResDir; - Fallback::Map mFallbackMap; - private slots: void documentLoaded (Document *document); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 39c0291fc..007190e4a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "idtable.hpp" #include "idtree.hpp" @@ -62,11 +63,18 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec return number; } -CSMWorld::Data::Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir) +CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, + const std::vector& archives, const Fallback::Map* fallback, const boost::filesystem::path& resDir) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), - mVFS(vfs), mResourcesManager (resourcesManager), mFallbackMap(fallback), - mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS())) + mFallbackMap(fallback), mReader (0), mDialogue (0), mReaderIndex(1), + mFsStrict(fsStrict), mDataPaths(dataPaths), mArchives(archives) { + mVFS.reset(new VFS::Manager(mFsStrict)); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); + + mResourcesManager.setVFS(mVFS.get()); + mResourceSystem.reset(new Resource::ResourceSystem(mVFS.get())); + mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string()); int index = 0; @@ -1218,7 +1226,8 @@ std::vector CSMWorld::Data::getIds (bool listDeleted) const void CSMWorld::Data::assetsChanged() { - mVFS->rebuildIndex(); + mVFS.get()->reset(); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, @@ -1265,7 +1274,7 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) const VFS::Manager* CSMWorld::Data::getVFS() const { - return mVFS; + return mVFS.get(); } const Fallback::Map* CSMWorld::Data::getFallbackMap() const diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 771a706b3..8a3667ea1 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -31,6 +31,7 @@ #include +#include #include #include "../doc/stage.hpp" @@ -46,6 +47,7 @@ #include "infocollection.hpp" #include "nestedinfocollection.hpp" #include "pathgrid.hpp" +#include "resourcesmanager.hpp" #include "metadata.hpp" #ifndef Q_MOC_RUN #include "subcellcollection.hpp" @@ -108,8 +110,6 @@ namespace CSMWorld RefCollection mRefs; IdCollection mFilters; Collection mMetaData; - VFS::Manager* mVFS; - ResourcesManager& mResourcesManager; const Fallback::Map* mFallbackMap; std::vector mModels; std::map mModelIndex; @@ -120,6 +120,11 @@ namespace CSMWorld std::map > mRefLoadCache; int mReaderIndex; + bool mFsStrict; + Files::PathContainer mDataPaths; + std::vector mArchives; + std::unique_ptr mVFS; + ResourcesManager mResourcesManager; std::shared_ptr mResourceSystem; std::vector > mReaders; @@ -141,7 +146,9 @@ namespace CSMWorld public: - Data (ToUTF8::FromType encoding, VFS::Manager* vfs, ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir); + Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, + const std::vector& archives, const Fallback::Map* fallback, + const boost::filesystem::path& resDir); virtual ~Data(); diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index f2082f750..b36c7117b 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -21,9 +21,6 @@ namespace VFS public: virtual ~Archive() {} - /// Clears cached data. - virtual void reset() = 0; - /// List all resources contained in this archive, and run the resource names through the given normalize function. virtual void listResources(std::map& out, char (*normalize_function) (char)) = 0; }; diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index 88e6bf2c7..9b686049f 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -10,12 +10,6 @@ BsaArchive::BsaArchive(const std::string &filename) load(); } -void BsaArchive::reset() -{ - mResources.clear(); - load(); -} - void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) { for (std::vector::iterator it = mResources.begin(); it != mResources.end(); ++it) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 92204f90c..217594abd 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -24,8 +24,6 @@ namespace VFS public: BsaArchive(const std::string& filename); - virtual void reset(); - virtual void listResources(std::map& out, char (*normalize_function) (char)); private: diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index 8fb992e76..ad5150a44 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -12,12 +12,6 @@ namespace VFS } - void FileSystemArchive::reset() - { - mIndex.clear(); - mBuiltIndex = false; - } - void FileSystemArchive::listResources(std::map &out, char (*normalize_function)(char)) { if (!mBuiltIndex) diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index 5843bf871..6c8e1b82b 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -23,8 +23,6 @@ namespace VFS public: FileSystemArchive(const std::string& path); - virtual void reset(); - virtual void listResources(std::map& out, char (*normalize_function) (char)); diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 9b1798e8f..4f3994bac 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -39,6 +39,12 @@ namespace VFS Manager::~Manager() { + reset(); + } + + void Manager::reset() + { + mIndex.clear(); for (std::vector::iterator it = mArchives.begin(); it != mArchives.end(); ++it) delete *it; mArchives.clear(); @@ -57,14 +63,6 @@ namespace VFS (*it)->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); } - void Manager::rebuildIndex() - { - for (std::vector::const_iterator it = mArchives.begin(); it != mArchives.end(); ++it) - (*it)->reset(); - - buildIndex(); - } - Files::IStreamPtr Manager::get(const std::string &name) const { std::string normalized = name; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 2ad7cf643..c5f0a8fec 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -26,6 +26,9 @@ namespace VFS ~Manager(); + // Empty the file index and unregister archives. + void reset(); + /// Register the given archive. All files contained in it will be added to the index on the next buildIndex() call. /// @note Takes ownership of the given pointer. void addArchive(Archive* archive); @@ -33,9 +36,6 @@ namespace VFS /// Build the file index. Should be called when all archives have been registered. void buildIndex(); - /// Rebuild the file index. New/deleted files (actual files, not bsa's) will be reflected. - void rebuildIndex(); - /// Does a file with this name exist? /// @note May be called from any thread once the index has been built. bool exists(const std::string& name) const; From e799cbdb51c2a3d0a74df24951eb59405a3a9740 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 22 Aug 2017 09:18:49 +0400 Subject: [PATCH 078/521] Combat AI: allow only one summoned creature at time --- apps/openmw/mwmechanics/spellpriority.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 9c57a2a7f..3a730fbeb 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -496,6 +496,15 @@ namespace MWMechanics break; } + // Allow only one summoned creature at time + if (isSummoningEffect(effect.mEffectID)) + { + MWMechanics::CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); + + if (!creatureStats.getSummonedCreatureMap().empty()) + return 0.f; + } + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); // Underwater casting not possible From d3d04171f9f1c80cfce59ed99a3e66da8fa57770 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 22 Aug 2017 15:06:56 -0400 Subject: [PATCH 079/521] Fix seg fault, undo changes BsaArchive --- apps/opencs/view/render/cell.cpp | 3 ++- components/vfs/bsaarchive.cpp | 20 +++++++------------- components/vfs/bsaarchive.hpp | 3 --- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a10e38397..153de773c 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -297,7 +297,8 @@ void CSVRender::Cell::reloadAssets() mTerrain->loadCell(mCoordinates.getX(), mCoordinates.getY()); } - mCellWater->reloadAssets(); + if (mCellWater) + mCellWater->reloadAssets(); } void CSVRender::Cell::setSelection (int elementMask, Selection mode) diff --git a/components/vfs/bsaarchive.cpp b/components/vfs/bsaarchive.cpp index 9b686049f..a527a6ad9 100644 --- a/components/vfs/bsaarchive.cpp +++ b/components/vfs/bsaarchive.cpp @@ -5,9 +5,14 @@ namespace VFS BsaArchive::BsaArchive(const std::string &filename) - : mFileName(filename) { - load(); + mFile.open(filename); + + const Bsa::BSAFile::FileList &filelist = mFile.getList(); + for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) + { + mResources.push_back(BsaArchiveFile(&*it, &mFile)); + } } void BsaArchive::listResources(std::map &out, char (*normalize_function)(char)) @@ -21,17 +26,6 @@ void BsaArchive::listResources(std::map &out, char (*normal } } -void BsaArchive::load() -{ - mFile.open(mFileName); - - const Bsa::BSAFile::FileList &filelist = mFile.getList(); - for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it) - { - mResources.push_back(BsaArchiveFile(&*it, &mFile)); - } -} - // ------------------------------------------------------------------------------ BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa) diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 217594abd..a6e274037 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -27,9 +27,6 @@ namespace VFS virtual void listResources(std::map& out, char (*normalize_function) (char)); private: - void load(); - - std::string mFileName; Bsa::BSAFile mFile; std::vector mResources; From 0177fe6602f5550538be170ce18a09fd8bb90eae Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 22 Aug 2017 23:08:06 +0400 Subject: [PATCH 080/521] Display large entries in journal correctly --- apps/openmw/mwgui/bookpage.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 20d3448b5..137594076 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -435,9 +435,15 @@ struct TypesetBookImpl::Typesetter : BookTypesetter } else { + // The section won't completely fit on the current page. Finish the current page and start a new one. + mBook->mPages.push_back (Page (curPageStart, curPageStop)); + + curPageStart = i->mRect.top; + curPageStop = i->mRect.bottom; + //split section int sectionHeightLeft = sectionHeight; - while (sectionHeightLeft > mPageHeight) + while (sectionHeightLeft >= mPageHeight) { // Adjust to the top of the first line that does not fit on the current page anymore int splitPos = curPageStop; From 157ecb166ce406bed76698a1fc55b4a86506d9c6 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Wed, 23 Aug 2017 00:02:02 -0400 Subject: [PATCH 081/521] Fix wrong folder name --- apps/opencs/model/world/resourcesmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/resourcesmanager.cpp b/apps/opencs/model/world/resourcesmanager.cpp index c50b86682..62dfe53a9 100644 --- a/apps/opencs/model/world/resourcesmanager.cpp +++ b/apps/opencs/model/world/resourcesmanager.cpp @@ -31,7 +31,7 @@ void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs) addResources (Resources (vfs, "music", UniversalId::Type_Music)); addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes)); addResources (Resources (vfs, "textures", UniversalId::Type_Texture)); - addResources (Resources (vfs, "videos", UniversalId::Type_Video)); + addResources (Resources (vfs, "video", UniversalId::Type_Video)); } const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const From 42b948dffe39cbf80f926b144f00a587275f346f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Wed, 23 Aug 2017 11:35:26 -0400 Subject: [PATCH 082/521] Fix pathgrid segfault --- apps/opencs/view/render/cell.cpp | 12 +++++++----- apps/opencs/view/render/pathgridmode.cpp | 15 +++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 153de773c..765c5b316 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -275,12 +275,14 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int void CSVRender::Cell::pathgridModified() { - mPathgrid->recreateGeometry(); + if (mPathgrid) + mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridRemoved() { - mPathgrid->removeGeometry(); + if (mPathgrid) + mPathgrid->removeGeometry(); } void CSVRender::Cell::reloadAssets() @@ -320,7 +322,7 @@ void CSVRender::Cell::setSelection (int elementMask, Selection mode) iter->second->setSelected (selected); } } - if (elementMask & Mask_Pathgrid) + if (mPathgrid && elementMask & Mask_Pathgrid) { // Only one pathgrid may be selected, so some operations will only have an effect // if the pathgrid is already focused @@ -420,7 +422,7 @@ std::vector > CSVRender::Cell::getSelection (un iter!=mObjects.end(); ++iter) if (iter->second->getSelected()) result.push_back (iter->second->getTag()); - if (elementMask & Mask_Pathgrid) + if (mPathgrid && elementMask & Mask_Pathgrid) if (mPathgrid->isSelected()) result.push_back(mPathgrid->getTag()); @@ -457,6 +459,6 @@ void CSVRender::Cell::reset (unsigned int elementMask) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) iter->second->reset(); - if (elementMask & Mask_Pathgrid) + if (mPathgrid && elementMask & Mask_Pathgrid) mPathgrid->resetIndicators(); } diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp index 228b2b5e7..a9cce0200 100644 --- a/apps/opencs/view/render/pathgridmode.cpp +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -72,12 +72,15 @@ namespace CSVRender } else if (Cell* cell = getWorldspaceWidget().getCell (hitResult.worldPos)) { - // Add node - QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); - QString description = "Add node"; + if (cell->getPathgrid()) + { + // Add node + QUndoStack& undoStack = getWorldspaceWidget().getDocument().getUndoStack(); + QString description = "Add node"; - CSMWorld::CommandMacro macro(undoStack, description); - cell->getPathgrid()->applyPoint(macro, hitResult.worldPos); + CSMWorld::CommandMacro macro(undoStack, description); + cell->getPathgrid()->applyPoint(macro, hitResult.worldPos); + } } } @@ -205,7 +208,7 @@ namespace CSVRender WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask()); Cell* cell = getWorldspaceWidget().getCell(hit.worldPos); - if (cell) + if (cell && cell->getPathgrid()) { PathgridTag* tag = 0; if (hit.tag && (tag = dynamic_cast(hit.tag.get())) && tag->getPathgrid()->getId() == mEdgeId) From a8576d78ad4ed809a336ea8a89e40eec0ad3585f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 24 Aug 2017 13:51:53 -0400 Subject: [PATCH 083/521] Change default topic info values --- apps/opencs/view/world/infocreator.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index f68c69094..2f1615c87 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -32,13 +32,19 @@ std::string CSVWorld::InfoCreator::getId() const void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const { - int index = - dynamic_cast (*getData().getTableModel (getCollectionId())). - findColumnIndex ( - getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ? - CSMWorld::Columns::ColumnId_Topic : CSMWorld::Columns::ColumnId_Journal); + CSMWorld::IdTable& table = dynamic_cast (*getData().getTableModel (getCollectionId())); - command.addValue (index, mTopic->text()); + if (getCollectionId() == CSMWorld::UniversalId::Type_TopicInfos) + { + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Topic), mTopic->text()); + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Rank), -1); + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Gender), -1); + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_PcRank), -1); + } + else + { + command.addValue (table.findColumnIndex(CSMWorld::Columns::ColumnId_Journal), mTopic->text()); + } } CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, From 663f3088d19432278d8cad805267d948c0030b98 Mon Sep 17 00:00:00 2001 From: "Hristos N. Triantafillou" Date: Thu, 24 Aug 2017 19:50:53 -0500 Subject: [PATCH 084/521] Use "Remove Branch" instead of "Remove" in normals tutorial * Pherim over at nexusmods advised me that using "Remove" leaves stranded references at the end of the file, and that the proper way to fully remove the unwanted `NiTextureEffect` block is to use "Remove Branch". This commit clarifies that in the normal map conversion tutorial. --- docs/source/reference/modding/convert_bump_mapped_mods.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/modding/convert_bump_mapped_mods.rst b/docs/source/reference/modding/convert_bump_mapped_mods.rst index 791e77353..71ac29468 100644 --- a/docs/source/reference/modding/convert_bump_mapped_mods.rst +++ b/docs/source/reference/modding/convert_bump_mapped_mods.rst @@ -176,7 +176,7 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Open up each of the models in NifSkope and look for these certain blocks_: - NiTextureEffect - NiSourceTexture with the value that appears to be a normal map file, in this mod, they have the suffix *_nm.dds*. -#. Remove all these tags by selecting them one at a time and press right click>Block>Remove. +#. Remove all these tags by selecting them one at a time and press right click>Block>Remove Branch. (Ctrl-Del) #. Repeat this on all the affected models. #. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. #. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. From 1578fcbec7ed6c4b7347613b01a426de2fe9cd83 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 25 Aug 2017 11:05:56 +0100 Subject: [PATCH 085/521] Escape content file names before sending them to the GUI --- apps/openmw/mwworld/contentloader.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp index 46bd7d3f9..0f2d807aa 100644 --- a/apps/openmw/mwworld/contentloader.hpp +++ b/apps/openmw/mwworld/contentloader.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "components/loadinglistener/loadinglistener.hpp" @@ -24,7 +25,7 @@ struct ContentLoader virtual void load(const boost::filesystem::path& filepath, int& index) { std::cout << "Loading content file " << filepath.string() << std::endl; - mListener.setLabel(filepath.string()); + mListener.setLabel(MyGUI::TextIterator::toTagsString(filepath.string())); } protected: From 86ae2ae3953f72a8d96c7359b7bf9fd2614b2cad Mon Sep 17 00:00:00 2001 From: Harry Date: Fri, 25 Aug 2017 16:08:49 -0400 Subject: [PATCH 086/521] Improved shuffle (#1412) --- AUTHORS.md | 1 + apps/openmw/mwsound/soundmanagerimp.cpp | 25 +++++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index c48647f4e..bb773c4ef 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -60,6 +60,7 @@ Programmers Gašper Sedej gugus/gus Hallfaer Tuilinn + Haoda Wang (h313) hristoast Internecine Jacob Essex (Yacoby) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c6f663059..811797369 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -271,7 +272,6 @@ namespace MWSound return sound; } - // Gets the combined volume settings for the given sound type float SoundManager::volumeFromType(PlayType type) const { @@ -298,7 +298,6 @@ namespace MWSound return volume; } - void SoundManager::stopMusic() { if(mMusic) @@ -349,6 +348,7 @@ namespace MWSound void SoundManager::startRandomTitle() { std::vector filelist; + auto &tracklist = mMusicToPlay[mCurrentPlaylist]; if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) { const std::map& index = mVFS->getIndex(); @@ -367,7 +367,6 @@ namespace MWSound } mMusicFiles[mCurrentPlaylist] = filelist; - } else filelist = mMusicFiles[mCurrentPlaylist]; @@ -375,15 +374,25 @@ namespace MWSound if(filelist.empty()) return; - int i = Misc::Rng::rollDice(filelist.size()); + // Do a Fisher-Yates shuffle - // Don't play the same music track twice in a row - if (filelist[i] == mLastPlayedMusic) + // Repopulate if playlist is empty + if(tracklist.empty()) { - i = (i+1) % filelist.size(); + tracklist.resize(filelist.size()); + std::iota(tracklist.begin(), tracklist.end(), 0); } - advanceMusic(filelist[i]); + int i = Misc::Rng::rollDice(tracklist.size()); + + // Reshuffle if last played music is the same after a repopulation + if(filelist[tracklist[i]] == mLastPlayedMusic) + i = (i+1) % tracklist.size(); + + // Remove music from list after advancing music + advanceMusic(filelist[tracklist[i]]); + tracklist[i] = tracklist.back(); + tracklist.pop_back(); } bool SoundManager::isMusicPlaying() diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 5d911d4be..691e52932 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -49,6 +50,7 @@ namespace MWSound // Caches available music tracks by std::map > mMusicFiles; + std::unordered_map> mMusicToPlay; // A list with music files not yet played std::string mLastPlayedMusic; // The music file that was last played float mMasterVolume; From 4fba157d3bd073cf5800487575077b0256162bd0 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 26 Aug 2017 19:28:23 +0000 Subject: [PATCH 087/521] Implement releaseGLObjects for cached resources --- apps/opencs/view/render/scenewidget.cpp | 4 ++-- apps/openmw/mwgui/loadingscreen.hpp | 2 -- components/resource/resourcemanager.cpp | 5 +++++ components/resource/resourcemanager.hpp | 3 +++ components/resource/resourcesystem.cpp | 6 ++++++ components/resource/resourcesystem.hpp | 4 ++++ components/resource/scenemanager.cpp | 5 +++++ components/resource/scenemanager.hpp | 2 +- components/shader/shadermanager.cpp | 9 +++++++++ components/shader/shadermanager.hpp | 1 + components/terrain/buffercache.cpp | 14 ++++++++++++++ components/terrain/buffercache.hpp | 2 +- components/terrain/chunkmanager.cpp | 6 ++++++ components/terrain/chunkmanager.hpp | 2 ++ 14 files changed, 59 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 3a801ffc3..11c7f5926 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -221,8 +221,8 @@ SceneWidget::SceneWidget(std::shared_ptr resourceSyste SceneWidget::~SceneWidget() { - // Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects - mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); + // Since we're holding on to the resources past the existence of this graphics context, we'll need to manually release the created objects + mResourceSystem->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } void SceneWidget::setLighting(Lighting *lighting) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 100c17e11..1a53495a9 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -73,8 +73,6 @@ namespace MWGui std::vector mSplashScreens; - // TODO: add releaseGLObjects() for mTexture - osg::ref_ptr mTexture; std::unique_ptr mGuiTexture; diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index 4e48d9745..c0e99674e 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -38,4 +38,9 @@ namespace Resource return mVFS; } + void ResourceManager::releaseGLObjects(osg::State *state) + { + mCache->releaseGLObjects(state); + } + } diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index 58200993b..6031ecc01 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -11,6 +11,7 @@ namespace VFS namespace osg { class Stats; + class State; } namespace Resource @@ -38,6 +39,8 @@ namespace Resource virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const {} + virtual void releaseGLObjects(osg::State* state); + protected: const VFS::Manager* mVFS; osg::ref_ptr mCache; diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index d7a6771c4..4d61dce69 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -97,4 +97,10 @@ namespace Resource (*it)->reportStats(frameNumber, stats); } + void ResourceSystem::releaseGLObjects(osg::State *state) + { + for (std::vector::const_iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) + (*it)->releaseGLObjects(state); + } + } diff --git a/components/resource/resourcesystem.hpp b/components/resource/resourcesystem.hpp index efce50b97..396bdb8fa 100644 --- a/components/resource/resourcesystem.hpp +++ b/components/resource/resourcesystem.hpp @@ -12,6 +12,7 @@ namespace VFS namespace osg { class Stats; + class State; } namespace Resource @@ -60,6 +61,9 @@ namespace Resource void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + /// Call releaseGLObjects for each resource manager. + void releaseGLObjects(osg::State* state); + private: std::unique_ptr mSceneManager; std::unique_ptr mImageManager; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 69a54bf17..ab801ab82 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -628,6 +628,11 @@ namespace Resource { mCache->releaseGLObjects(state); mInstanceCache->releaseGLObjects(state); + + mShaderManager->releaseGLObjects(state); + + OpenThreads::ScopedLock lock(mSharedStateMutex); + mSharedStateManager->releaseGLObjects(state); } void SceneManager::setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation *ico) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 14032df77..65524f76e 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -116,7 +116,7 @@ namespace Resource /// Manually release created OpenGL objects for the given graphics context. This may be required /// in cases where multiple contexts are used over the lifetime of the application. - void releaseGLObjects(osg::State* state); + void releaseGLObjects(osg::State* state) override; /// Set up an IncrementalCompileOperation for background compiling of loaded scenes. void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 2bfb17b5c..7cb49c6cb 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -158,4 +158,13 @@ namespace Shader return found->second; } + void ShaderManager::releaseGLObjects(osg::State *state) + { + OpenThreads::ScopedLock lock(mMutex); + for (auto shader : mShaders) + shader.second->releaseGLObjects(state); + for (auto program : mPrograms) + program.second->releaseGLObjects(state); + } + } diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index 5196dbe80..bd820a725 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -32,6 +32,7 @@ namespace Shader osg::ref_ptr getProgram(osg::ref_ptr vertexShader, osg::ref_ptr fragmentShader); + void releaseGLObjects(osg::State* state); private: std::string mPath; diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index 361dd6c04..1734686de 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -243,4 +243,18 @@ namespace Terrain } } + void BufferCache::releaseGLObjects(osg::State *state) + { + { + OpenThreads::ScopedLock lock(mIndexBufferMutex); + for (auto indexbuffer : mIndexBufferMap) + indexbuffer.second->releaseGLObjects(state); + } + { + OpenThreads::ScopedLock lock(mUvBufferMutex); + for (auto uvbuffer : mUvBufferMap) + uvbuffer.second->releaseGLObjects(state); + } + } + } diff --git a/components/terrain/buffercache.hpp b/components/terrain/buffercache.hpp index bfdf558bc..37563d2c6 100644 --- a/components/terrain/buffercache.hpp +++ b/components/terrain/buffercache.hpp @@ -24,7 +24,7 @@ namespace Terrain void clearCache(); - // TODO: add releaseGLObjects() for our vertex/element buffer objects + void releaseGLObjects(osg::State* state); private: // Index buffers are shared across terrain batches where possible. There is one index buffer for each diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index ea71c726f..7575113ef 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -62,6 +62,12 @@ void ChunkManager::clearCache() mBufferCache.clearCache(); } +void ChunkManager::releaseGLObjects(osg::State *state) +{ + ResourceManager::releaseGLObjects(state); + mBufferCache.releaseGLObjects(state); +} + void ChunkManager::setCullingActive(bool active) { mCullingActive = active; diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 2f92fa836..46531f23e 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -36,6 +36,8 @@ namespace Terrain virtual void clearCache(); + void releaseGLObjects(osg::State* state) override; + void setCullingActive(bool active); private: From 5d2fe5e887b10ca84f645af42008723777b1e31a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 27 Aug 2017 21:22:17 +0000 Subject: [PATCH 088/521] Implement lightmode/vertmode of NiVertexColorProperty --- components/nifosg/nifloader.cpp | 40 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e514cca12..522cf6ac3 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1674,6 +1674,8 @@ namespace NifOsg bool hasMatCtrl = false; + int lightmode = 1; + for (std::vector::const_reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { const Nif::Property* property = *it; @@ -1706,19 +1708,25 @@ namespace NifOsg case Nif::RC_NiVertexColorProperty: { const Nif::NiVertexColorProperty* vertprop = static_cast(property); - if (!hasVertexColors) - break; - switch (vertprop->flags) + lightmode = vertprop->data.lightmode; + + if (hasVertexColors) { - case 0: - mat->setColorMode(osg::Material::OFF); - break; - case 1: - mat->setColorMode(osg::Material::EMISSION); - break; - case 2: - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); - break; + switch (vertprop->data.vertmode) + { + case 0: + mat->setColorMode(osg::Material::OFF); + break; + case 1: + mat->setColorMode(osg::Material::EMISSION); + break; + case 2: + if (lightmode != 0) + mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + else + mat->setColorMode(osg::Material::OFF); + break; + } } break; } @@ -1772,6 +1780,14 @@ namespace NifOsg mat->setColorMode(osg::Material::AMBIENT); } + if (lightmode == 0) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse = osg::Vec4f(0,0,0,diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f()); + } + if (!hasMatCtrl && mat->getColorMode() == osg::Material::OFF && mat->getEmission(osg::Material::FRONT_AND_BACK) == osg::Vec4f(0,0,0,1) && mat->getDiffuse(osg::Material::FRONT_AND_BACK) == osg::Vec4f(1,1,1,1) From bc82c6a35da5c6d46581b91afcfb5300fd360b53 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 27 Aug 2017 21:22:44 +0000 Subject: [PATCH 089/521] Use white color if told to use nonexisting vertexcolors (Fixes #3833) --- components/nifosg/nifloader.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 522cf6ac3..78186c439 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1710,10 +1710,8 @@ namespace NifOsg const Nif::NiVertexColorProperty* vertprop = static_cast(property); lightmode = vertprop->data.lightmode; - if (hasVertexColors) + switch (vertprop->data.vertmode) { - switch (vertprop->data.vertmode) - { case 0: mat->setColorMode(osg::Material::OFF); break; @@ -1726,7 +1724,6 @@ namespace NifOsg else mat->setColorMode(osg::Material::OFF); break; - } } break; } @@ -1788,6 +1785,27 @@ namespace NifOsg mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f()); } + // If we're told to use vertex colors but there are none to use, use a default color instead. + if (!hasVertexColors) + { + switch (mat->getColorMode()) + { + case osg::Material::AMBIENT: + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + break; + case osg::Material::AMBIENT_AND_DIFFUSE: + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + break; + case osg::Material::EMISSION: + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); + break; + default: + break; + } + mat->setColorMode(osg::Material::OFF); + } + if (!hasMatCtrl && mat->getColorMode() == osg::Material::OFF && mat->getEmission(osg::Material::FRONT_AND_BACK) == osg::Vec4f(0,0,0,1) && mat->getDiffuse(osg::Material::FRONT_AND_BACK) == osg::Vec4f(1,1,1,1) From fb45995a41e55f3956459878e13f94c67f641880 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 18 Aug 2017 19:24:34 +0400 Subject: [PATCH 090/521] Do not allow player to change weapon/spell during attack or spellcasting (bug #2445) --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwbase/windowmanager.hpp | 5 +- apps/openmw/mwclass/weapon.cpp | 4 ++ apps/openmw/mwgui/inventorywindow.cpp | 12 ++++- apps/openmw/mwgui/quickkeysmenu.cpp | 49 +++++++++++++++++++ apps/openmw/mwgui/quickkeysmenu.hpp | 3 +- apps/openmw/mwgui/spellwindow.cpp | 10 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 5 +- apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++ apps/openmw/mwmechanics/actors.cpp | 10 ++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 6 +++ apps/openmw/mwmechanics/character.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 + 16 files changed, 124 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2daaf9711..7966cb6da 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -221,6 +221,7 @@ namespace MWBase virtual void keepPlayerAlive() = 0; virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; + virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0; virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 416a7ad87..d7ccfa3e4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -212,7 +212,10 @@ namespace MWBase virtual void setSpellVisibility(bool visible) = 0; virtual void setSneakVisibility(bool visible) = 0; - virtual void activateQuickKey (int index) = 0; + /// activate selected quick key + virtual void activateQuickKey (int index) = 0; + /// update activated quick key state (if action executing was delayed for some reason) + virtual void updateActivatedQuickKey () = 0; virtual std::string getSelectedSpell() = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index efb6248af..62a9b6d0f 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -4,6 +4,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -373,6 +374,9 @@ namespace MWClass if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc)) + return std::make_pair(0, "#{sCantEquipWeapWarning}"); + std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); if (slots_.first.empty()) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8b0f895d1..4cba7a0ae 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -29,6 +29,7 @@ #include "../mwrender/characterpreview.hpp" #include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" @@ -660,9 +661,18 @@ namespace MWGui void InventoryWindow::cycle(bool next) { + MWWorld::Ptr player = MWMechanics::getPlayer(); + + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player)) + return; + + const MWMechanics::CreatureStats &stats = player.getClass().getCreatureStats(player); + if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery()) + return; + ItemModel::ModelIndex selected = -1; // not using mSortFilterModel as we only need sorting, not filtering - SortFilterItemModel model(new InventoryItemModel(MWMechanics::getPlayer())); + SortFilterItemModel model(new InventoryItemModel(player)); model.setSortByType(false); model.update(); if (model.getItemCount() == 0) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 619540cff..4e4462409 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -14,6 +14,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -36,6 +37,7 @@ namespace MWGui , mItemSelectionDialog(0) , mMagicSelectionDialog(0) , mSelectedIndex(-1) + , mActivatedIndex(-1) { getWidget(mOkButton, "OKButton"); getWidget(mInstructionLabel, "InstructionLabel"); @@ -69,6 +71,8 @@ namespace MWGui void QuickKeysMenu::clear() { + mActivatedIndex = -1; + for (int i=0; i<10; ++i) { unassign(mQuickKeyButtons[i], i); @@ -254,6 +258,15 @@ namespace MWGui mMagicSelectionDialog->setVisible(false); } + void QuickKeysMenu::updateActivatedQuickKey() + { + // there is no delayed action, nothing to do. + if (mActivatedIndex < 0) + return; + + activateQuickKey(mActivatedIndex); + } + void QuickKeysMenu::activateQuickKey(int index) { assert (index-1 >= 0); @@ -263,6 +276,27 @@ namespace MWGui MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); + + // Delay action executing, + // if player is busy for now (casting a spell, attacking someone, etc.) + bool isDelayNeeded = MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player) + || playerStats.getKnockedDown() + || playerStats.getHitRecovery(); + + bool isReturnNeeded = playerStats.isParalyzed() || playerStats.isDead(); + if (isReturnNeeded && type != Type_Item) + { + return; + } + + if (isDelayNeeded && type != Type_Item) + { + mActivatedIndex = index; + return; + } + else + mActivatedIndex = -1; if (type == Type_Item || type == Type_MagicItem) { @@ -309,6 +343,21 @@ namespace MWGui else if (type == Type_Item) { MWWorld::Ptr item = *button->getUserData(); + bool isWeapon = item.getTypeName() == typeid(ESM::Weapon).name(); + + // delay weapon switching if player is busy + if (isDelayNeeded && isWeapon) + { + mActivatedIndex = index; + return; + } + + // disable weapon switching if player is dead or paralyzed + if (isReturnNeeded && isWeapon) + { + return; + } + MWBase::Environment::get().getWindowManager()->useItem(item); MWWorld::ConstContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); // change draw state only if the item is in player's right hand diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index afbcff001..64db9043e 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -36,6 +36,7 @@ namespace MWGui void onAssignMagicCancel (); void activateQuickKey(int index); + void updateActivatedQuickKey(); /// @note This enum is serialized, so don't move the items around! enum QuickKeyType @@ -64,7 +65,7 @@ namespace MWGui MagicSelectionDialog* mMagicSelectionDialog; int mSelectedIndex; - + int mActivatedIndex; void onQuickKeyButtonClicked(MyGUI::Widget* sender); void onOkButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 0c3485e6a..5ce3fd1fe 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" @@ -195,6 +196,15 @@ namespace MWGui void SpellWindow::cycle(bool next) { + MWWorld::Ptr player = MWMechanics::getPlayer(); + + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player)) + return; + + const MWMechanics::CreatureStats &stats = player.getClass().getCreatureStats(player); + if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead() || stats.getHitRecovery()) + return; + mSpellView->setModel(new SpellModel(MWMechanics::getPlayer())); SpellModel::ModelIndex selected = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 97aedab81..06854c43f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -518,6 +518,8 @@ namespace MWGui cleanupGarbage(); mHud->update(); + + updateActivatedQuickKey (); } void WindowManager::updateVisible() @@ -1528,6 +1530,11 @@ namespace MWGui mHud->setCrosshairVisible (show && mCrosshairEnabled); } + void WindowManager::updateActivatedQuickKey () + { + mQuickKeysMenu->updateActivatedQuickKey(); + } + void WindowManager::activateQuickKey (int index) { mQuickKeysMenu->activateQuickKey(index); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f74ba21a3..ceb6f62b7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -241,7 +241,10 @@ namespace MWGui virtual void setSpellVisibility(bool visible); virtual void setSneakVisibility(bool visible); - virtual void activateQuickKey (int index); + /// activate selected quick key + virtual void activateQuickKey (int index); + /// update activated quick key state (if action executing was delayed for some reason) + virtual void updateActivatedQuickKey (); virtual std::string getSelectedSpell() { return mSelectedSpell; } virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a823ae0fd..5f3e3152d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -20,6 +20,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -929,6 +930,9 @@ namespace MWInput inventory.getSelectedEnchantItem() == inventory.end()) return; + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) + return; + MWMechanics::DrawState_ state = mPlayer->getDrawState(); if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) mPlayer->setDrawState(MWMechanics::DrawState_Spell); @@ -944,6 +948,9 @@ namespace MWInput if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"]) return; + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) + return; + MWMechanics::DrawState_ state = mPlayer->getDrawState(); if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) mPlayer->setDrawState(MWMechanics::DrawState_Weapon); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9a23526f7..cd15c4074 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1784,6 +1784,16 @@ namespace MWMechanics return it->second->getCharacterController()->isReadyToBlock(); } + bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const + { + PtrActorMap::const_iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isAttackingOrSpell(); + } + void Actors::fastForwardAi() { if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index cd949696b..b7aae21e8 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -150,6 +150,7 @@ namespace MWMechanics void clear(); // Clear death counter bool isReadyToBlock(const MWWorld::Ptr& ptr) const; + bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const; private: PtrActorMap mActors; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 25d04d176..e9f42476b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2228,6 +2228,12 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +bool CharacterController::isAttackingOrSpell() const +{ + return mUpperBodyState != UpperCharState_Nothing && + mUpperBodyState != UpperCharState_WeapEquiped; +} + bool CharacterController::isSneaking() const { return mIdleState == CharState_IdleSneak || diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 66039bf5d..bde64cdfb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -267,6 +267,7 @@ public: bool isKnockedOut() const; bool isSneaking() const; bool isRunning() const; + bool isAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell); void setAIAttackType(const std::string& attackType); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d182e40d7..c0685e6f0 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1581,6 +1581,11 @@ namespace MWMechanics return mActors.isReadyToBlock(ptr); } + bool MechanicsManager::isAttackingOrSpell(const MWWorld::Ptr &ptr) const + { + return mActors.isAttackingOrSpell(ptr); + } + void MechanicsManager::setWerewolf(const MWWorld::Ptr& actor, bool werewolf) { MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index af0377a33..1cab13cbc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -188,6 +188,8 @@ namespace MWMechanics virtual void keepPlayerAlive(); virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const; + /// Is \a ptr casting spell or using weapon now? + virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const; virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); From 8003dbee12b67e9c52e4dc8a9c75a9861ee0d794 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 29 Aug 2017 16:40:55 +0400 Subject: [PATCH 091/521] Combat AI: use effective cast cost when rate enchanted weapon --- apps/openmw/mwmechanics/weaponpriority.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/weaponpriority.cpp b/apps/openmw/mwmechanics/weaponpriority.cpp index 07cf6ff5f..d06e73c93 100644 --- a/apps/openmw/mwmechanics/weaponpriority.cpp +++ b/apps/openmw/mwmechanics/weaponpriority.cpp @@ -13,6 +13,7 @@ #include "combat.hpp" #include "aicombataction.hpp" #include "spellpriority.hpp" +#include "spellcasting.hpp" namespace MWMechanics { @@ -90,10 +91,13 @@ namespace MWMechanics if (!weapon->mEnchant.empty()) { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(weapon->mEnchant); - if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes - && (item.getCellRef().getEnchantmentCharge() == -1 - || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) - rating += rateEffects(enchantment->mEffects, actor, enemy); + if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes) + { + int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), actor); + + if (item.getCellRef().getEnchantmentCharge() == -1 || item.getCellRef().getEnchantmentCharge() >= castCost) + rating += rateEffects(enchantment->mEffects, actor, enemy); + } } int skill = item.getClass().getEquipmentSkill(item); From 3fc86342061bab0c30bed6821f66933fef546930 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 29 Aug 2017 12:55:42 +0000 Subject: [PATCH 092/521] Check for a Geometry node when attaching bodyparts (Fixes #3957) --- components/nifosg/nifloader.cpp | 3 +++ components/sceneutil/attach.cpp | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 78186c439..b7d1c15b8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1130,6 +1130,8 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } + geometry->setName(triShape->name); + if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1219,6 +1221,7 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); + rig->setName(triShape->name); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 1385f771e..8634a4df6 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -32,29 +32,29 @@ namespace SceneUtil virtual void apply(osg::MatrixTransform& node) { - applyNode(node); - } - virtual void apply(osg::Geometry& node) - { - applyNode(node); + traverse(node); } virtual void apply(osg::Node& node) { - applyNode(node); + traverse(node); } virtual void apply(osg::Group& node) { - applyNode(node); + traverse(node); } - void applyNode(osg::Node& node) + virtual void apply(osg::Geometry& geom) { - std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) - mToCopy.push_back(&node); - else - traverse(node); + { + osg::Node* node = &geom; + while (node && node->getNumParents() && !node->getStateSet()) + node = node->getParent(0); + if (node) + mToCopy.push_back(node); + } } void doCopy() From 73d5efabeed6b07cdaea8d7cf147fbc6a4739f6e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 29 Aug 2017 18:04:31 +0400 Subject: [PATCH 093/521] Display negative values on fatigue progress bar --- apps/openmw/mwgui/hud.cpp | 18 +++++++++++------- apps/openmw/mwgui/review.cpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 11 ++++++++--- apps/openmw/mwgui/widgets.cpp | 5 ++--- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 84e5794e3..0e1b2cc89 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -179,29 +179,33 @@ namespace MWGui void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { - int current = std::max(0, static_cast(value.getCurrent())); + int current = static_cast(value.getCurrent()); int modified = static_cast(value.getModified()); + // Fatigue can be negative + if (id != "FBar") + current = std::max(0, current); + MyGUI::Widget* w; std::string valStr = MyGUI::utility::toString(current) + " / " + MyGUI::utility::toString(modified); if (id == "HBar") { - mHealth->setProgressRange(modified); - mHealth->setProgressPosition(current); + mHealth->setProgressRange(std::max(0, modified)); + mHealth->setProgressPosition(std::max(0, current)); getWidget(w, "HealthFrame"); w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } else if (id == "MBar") { - mMagicka->setProgressRange (modified); - mMagicka->setProgressPosition (current); + mMagicka->setProgressRange(std::max(0, modified)); + mMagicka->setProgressPosition(std::max(0, current)); getWidget(w, "MagickaFrame"); w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr); } else if (id == "FBar") { - mStamina->setProgressRange (modified); - mStamina->setProgressPosition (current); + mStamina->setProgressRange(std::max(0, modified)); + mStamina->setProgressPosition(std::max(0, current)); getWidget(w, "FatigueFrame"); w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 1a680b801..bf18e7355 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -180,7 +180,7 @@ namespace MWGui void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { - int current = std::max(0, static_cast(value.getCurrent())); + int current = static_cast(value.getCurrent()); int modified = static_cast(value.getModified()); mFatigue->setValue(current, modified); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 22140b8b2..17e51e338 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -102,12 +102,13 @@ namespace MWGui { MyGUI::ProgressBar* pt; getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); std::stringstream out; out << val << "/" << max; setText(tname, out.str().c_str()); + + pt->setProgressRange(std::max(0, max)); + pt->setProgressPosition(std::max(0, val)); } void StatsWindow::setPlayerName(const std::string& playerName) @@ -147,9 +148,13 @@ namespace MWGui void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { - int current = std::max(0, static_cast(value.getCurrent())); + int current = static_cast(value.getCurrent()); int modified = static_cast(value.getModified()); + // Fatigue can be negative + if (id != "FBar") + current = std::max(0, current); + setBar (id, id + "T", current, modified); // health, magicka, fatigue tooltip diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 695337cde..744ef236f 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -502,11 +502,10 @@ namespace MWGui if (mBarWidget) { - mBarWidget->setProgressRange(mMax); - mBarWidget->setProgressPosition(mValue); + mBarWidget->setProgressRange(std::max(0, mMax)); + mBarWidget->setProgressPosition(std::max(0, mValue)); } - if (mBarTextWidget) { std::stringstream out; From 47d6c5091ff0ca0289dd686782d2bd6fbb14a42c Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Tue, 29 Aug 2017 23:39:24 +0100 Subject: [PATCH 094/521] OpenMW CS Manual - typo fixes etc (#1422) * Update files-and-directories.rst * OpenMW CS Manual - minor typo fixes --- .../openmw-cs/files-and-directories.rst | 46 +++++++++---------- .../manuals/openmw-cs/starting-dialog.rst | 4 +- docs/source/manuals/openmw-cs/tour.rst | 4 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/source/manuals/openmw-cs/files-and-directories.rst b/docs/source/manuals/openmw-cs/files-and-directories.rst index 34680fa94..77593dece 100644 --- a/docs/source/manuals/openmw-cs/files-and-directories.rst +++ b/docs/source/manuals/openmw-cs/files-and-directories.rst @@ -14,22 +14,22 @@ Basics Directories =========== -OpenMW and OpenMW CS us multiple directories on the file system. First of all +OpenMW and OpenMW CS use multiple directories on the file system. First of all there is a *user directory* that holds configuration files and a number of different sub-directories. The location of the user directory is hard-coded into the CS and depends on your operating system. ================ ========================================= -Operating System User Dircetory +Operating System User Directory ================ ========================================= -GNU/Linux ```` +GNU/Linux ``~/.config/openmw/`` OS X ``~/Library/Application Support/openmw/`` -Windows ```` +Windows ``C:\Users\ *Username* \Documents\my games\OpenMW`` ================ ========================================= In addition to to this single hard-coded directory both OpenMW and OpenMW CS -need a place to seek for a actuals data files of the game: textures, 3D models, -sounds and record files that store objects in game; dialogues an so one. These +need a place to search for actual data files of the game: textures, 3D models, +sounds and record files that store objects in game; dialogues and so on. These files are called *content files*. We support multiple such paths (we call them *data paths*) as specified in the configuration. Usually one data path points to the directory where the original Morrowind game is either installed or @@ -42,12 +42,12 @@ Content files ============= The original Morrowind engine by Bethesda Softworks uses two types of content -files: `esm` (master) and `esp` (plugin). The distinction between those two is -not clear, and often confusing. One would expect the `esm` (master) file to be -used to specify one master, which is then modified by the `esp` plugins. And +files: `ESM` (master) and `ESP` (plugin). The distinction between those two is +not clear, and often confusing. One would expect the `ESM` (master) file to be +used to specify one master, which is then modified by the `ESP` plugins. And indeed: this is the basic idea. However, the official expansions were also made as ESM files, even though they could essentially be described as really large -plugins, and therefore would rather use `esp` files. There were technical +plugins, and therefore should have been `ESP` files. There were technical reasons behind this decision – somewhat valid in the case of the original engine, but clearly it is better to create a system that can be used in a more sensible way. OpenMW achieves this with our own content file types. @@ -62,7 +62,7 @@ OpenMW content files The concepts of *Game* and *Addon* files are somewhat similar to the old concept of *ESM* and *ESP*, but more strictly enforced. It is quite -straight-formward: If you want to make new game using OpenMW as the engine (a +straight-forward: If you want to make new game using OpenMW as the engine (a so called *total conversion*) you should create a game file. If you want to create an addon for an existing game file create an addon file. Nothing else matters; the only distinction you should consider is if your project is about @@ -75,21 +75,21 @@ Another simple thing about content files are the extensions: we are using Morrowind content files ----------------------- -Using our content files is recommended for projects that are intended to used -with the OpenMW engine. However, some players might wish to still use the +Using our content files is recommended for projects that are intended to use +the OpenMW engine. However, some players might wish to still use the original Morrowind engine. In addition thousands of *ESP*/*ESM* files were created since 2002, some of them with really outstanding content. Because of this OpenMW CS simply has no other choice but to support *ESP*/*ESM* files. If -you decid to choose *ESP*/*ESM* file instead of using our own content file -types you are most likely aimng at compatibility with the original engine. This -subject is covered in it own chapter of this manual. +you decide to choose *ESP*/*ESM* file instead of using our own content file +types you are most likely aiming at compatibility with the original engine. This +subject is covered in its own chapter of this manual. .. TODO This paragraph sounds weird The actual creation of new files is described in the next chapter. Here we are going to focus only on the details you need to know in order to create your -first OpenMW CS file while fully understanding your needs. For now let’s jut +first OpenMW CS file while fully understanding your needs. For now let’s just remember that content files are created inside the user directory in the the ``data`` subdirectory (that is the one special data directory mentioned earlier). @@ -99,8 +99,8 @@ Dependencies ------------ Since an addon is supposed to change the game it follows that it also depends -on the said game to work. We can conceptualise this with an examples: your -modification is the changing prize of an iron sword, but what if there is no +on the said game to work. We can conceptualise this with an example: your +modification is changing the price of an iron sword, but what if there is no iron sword in game? That's right: we get nonsense. What you want to do is tie your addon to the files you are changing. Those can be either game files (for example when making an expansion island for a game) or other addon files @@ -112,9 +112,9 @@ files – it is only a theoretical introduction to the subject. For now just kee in mind that dependencies exist, and is up to you to decide whether your content file should depend on other content files. -Game files are not intend to have any dependencies for a very simple reasons: +Game files are not intended to have any dependencies for a very simple reasons: the player is using only one game file (excluding original and the dirty -ESP/ESM system) at a time and therefore no game file can depend on other game +ESP/ESM system) at a time and therefore no game file can depend on another game file, and since a game file makes the base for addon files it can not depend on addon files. @@ -123,7 +123,7 @@ Project files ------------- Project files act as containers for data not used by the OpenMW game engine -itself, but still useful for OpenMW CS. The shining example of this data +itself, but still useful for OpenMW CS. The shining examples of this data category are without doubt record filters (described in a later chapter of the manual). As a mod author you probably do not need or want to distribute project files at all, they are meant to be used only by you and your team. @@ -132,7 +132,7 @@ files at all, they are meant to be used only by you and your team. As you would imagine, project files make sense only in combination with actual content files. In fact, each time you start to work on new content file and a -project file was not found, one will be created. The extensio of project files +project file was not found, one will be created. The extension of project files is ``.project``. The whole name of the project file is the whole name of the content file with appended extension. For instance a ``swords.omwaddon`` file is associated with a ``swords.omwaddon.project`` file. diff --git a/docs/source/manuals/openmw-cs/starting-dialog.rst b/docs/source/manuals/openmw-cs/starting-dialog.rst index 02a65ff21..fa069d8d6 100644 --- a/docs/source/manuals/openmw-cs/starting-dialog.rst +++ b/docs/source/manuals/openmw-cs/starting-dialog.rst @@ -3,7 +3,7 @@ OpenMW CS Starting Dialog In this chapter we will cover starting up OpenMW CS and the starting interface. Start the CS the way intended for your operating system and you will be -presented with window and three main buttons and a small button with a +presented with a window and three main buttons and a small button with a wrench-icon. The wrench will open the configuration dialog which we will cover later. The three main buttons are the following: @@ -32,7 +32,7 @@ choose exactly one game and you can choose an arbitrary amount of addon dependencies. For the sake of simplicity and maintainability choose only the addons you actually want to depend on. Also keep in mind that your dependencies might have dependencies of their own, you have to depend on those as well. If -one of your dependencies nees something it will be indicated by a warning sign +one of your dependencies needs something it will be indicated by a warning sign and automatically include its dependencies when you choose it. If you want to edit an existing content file you will be presented with a diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index 9844948ea..bb1097e0c 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -48,7 +48,7 @@ Once the addon has been created you will be presented with a table. If you see a blank window rather than a table choose *World* → *Objects* from the menu. .. figure:: _static/images/chapter-1/objects.png - :alt: The table showing all objet records in the game. + :alt: The table showing all object records in the game. Let's talk about the interface for a second. Every window in OpenMW CS has *panels*, these are often but not always tables. You can close a panel by @@ -139,7 +139,7 @@ the first character. Type the following into the field: A filter is defined by a number of *queries* which can be logically linked. For now all that matters is that the `string(, )` query will check -whether `` matches ``. The pattern is a regular expression, +whether `` matches ``. The pattern is a regular expression, if you don't know about them you should learn their syntax. For now all that matters is that `.` stands for any character and `*` stands for any amount, even zero. In other words, we are looking for all entries which have an ID that From a1e3fb7604a11307ed08f1ec84b31a359cb5ead5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 29 Aug 2017 22:40:19 +0000 Subject: [PATCH 095/521] Revert "Check for a Geometry node when attaching bodyparts" This reverts commit 3fc86342061bab0c30bed6821f66933fef546930. --- components/nifosg/nifloader.cpp | 3 --- components/sceneutil/attach.cpp | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b7d1c15b8..78186c439 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1130,8 +1130,6 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } - geometry->setName(triShape->name); - if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1221,7 +1219,6 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); - rig->setName(triShape->name); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 8634a4df6..1385f771e 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -32,29 +32,29 @@ namespace SceneUtil virtual void apply(osg::MatrixTransform& node) { - traverse(node); + applyNode(node); + } + virtual void apply(osg::Geometry& node) + { + applyNode(node); } virtual void apply(osg::Node& node) { - traverse(node); + applyNode(node); } virtual void apply(osg::Group& node) { - traverse(node); + applyNode(node); } - virtual void apply(osg::Geometry& geom) + void applyNode(osg::Node& node) { - std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) - { - osg::Node* node = &geom; - while (node && node->getNumParents() && !node->getStateSet()) - node = node->getParent(0); - if (node) - mToCopy.push_back(node); - } + mToCopy.push_back(&node); + else + traverse(node); } void doCopy() From 8c6a8ca48d7077e360ff49cc2795cad271b2d139 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 30 Aug 2017 21:26:30 +0000 Subject: [PATCH 096/521] Respect the framelimit in all cases (Fixes #3531) Affects loading screen, videos & modal dialogs. Also skips rendering if window is minimized. --- apps/openmw/engine.cpp | 16 ++++------ apps/openmw/mwbase/environment.cpp | 27 ++++++++++++++++- apps/openmw/mwbase/environment.hpp | 5 ++++ apps/openmw/mwgui/loadingscreen.cpp | 15 ++++++++-- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 41 +++++++++++++++++++------- 6 files changed, 81 insertions(+), 25 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c921e17d0..f5ec86cc3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -84,7 +84,6 @@ void OMW::Engine::frame(float frametime) try { mStartTick = mViewer->getStartTick(); - mEnvironment.setFrameDuration (frametime); // update input mEnvironment.getInputManager()->update(frametime, false); @@ -651,6 +650,8 @@ void OMW::Engine::go() Settings::Manager::getString("screenshot format", "General"))); mViewer->addEventHandler(mScreenCaptureHandler); + mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video")); + // Create encoder ToUTF8::Utf8Encoder encoder (mEncoding); mEncoder = &encoder; @@ -684,7 +685,6 @@ void OMW::Engine::go() // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; - float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video"); while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) { double dt = frameTimer.time_s(); @@ -697,6 +697,8 @@ void OMW::Engine::go() mViewer->advance(simulationTime); + mEnvironment.setFrameDuration(dt); + frame(dt); if (!mEnvironment.getInputManager()->isWindowVisible()) @@ -714,15 +716,7 @@ void OMW::Engine::go() mViewer->renderingTraversals(); } - if (framerateLimit > 0.f) - { - double thisFrameTime = frameTimer.time_s(); - double minFrameTime = 1.0 / framerateLimit; - if (thisFrameTime < minFrameTime) - { - OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); - } - } + mEnvironment.limitFrameRate(frameTimer.time_s()); } // Save user settings diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 4efa7c273..5d01525b9 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -2,6 +2,8 @@ #include +#include + #include "world.hpp" #include "scriptmanager.hpp" #include "dialoguemanager.hpp" @@ -17,7 +19,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment::Environment() : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0), - mFrameDuration (0) + mFrameDuration (0), mFrameRateLimit(0.f) { assert (!sThis); sThis = this; @@ -79,6 +81,29 @@ void MWBase::Environment::setFrameDuration (float duration) mFrameDuration = duration; } +void MWBase::Environment::setFrameRateLimit(float limit) +{ + mFrameRateLimit = limit; +} + +float MWBase::Environment::getFrameRateLimit() const +{ + return mFrameRateLimit; +} + +void MWBase::Environment::limitFrameRate(double dt) const +{ + if (mFrameRateLimit > 0.f) + { + double thisFrameTime = dt; + double minFrameTime = 1.0 / static_cast(mFrameRateLimit); + if (thisFrameTime < minFrameTime) + { + OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime)); + } + } +} + MWBase::World *MWBase::Environment::getWorld() const { assert (mWorld); diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 7f7919f81..9163b21f3 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -33,6 +33,7 @@ namespace MWBase InputManager *mInputManager; StateManager *mStateManager; float mFrameDuration; + float mFrameRateLimit; Environment (const Environment&); ///< not implemented @@ -67,6 +68,10 @@ namespace MWBase void setFrameDuration (float duration); ///< Set length of current frame in seconds. + void setFrameRateLimit(float frameRateLimit); + float getFrameRateLimit() const; + void limitFrameRate(double dt) const; + World *getWorld() const; SoundManager *getSoundManager() const; diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index ca6a0b0a4..c5836b653 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -102,6 +102,15 @@ namespace MWGui mBackgroundImage->setVisible(visible); } + double LoadingScreen::getTargetFrameRate() const + { + double frameRateLimit = MWBase::Environment::get().getFrameRateLimit(); + if (frameRateLimit > 0) + return std::min(frameRateLimit, mTargetFrameRate); + else + return mTargetFrameRate; + } + class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback { public: @@ -141,7 +150,7 @@ namespace MWGui if (mViewer->getIncrementalCompileOperation()) { mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100); - mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate); + mViewer->getIncrementalCompileOperation()->setTargetFrameRate(getTargetFrameRate()); } // Assign dummy bounding sphere callback to avoid the bounding sphere of the entire scene being recomputed after each frame of loading @@ -210,7 +219,7 @@ namespace MWGui void LoadingScreen::setProgress (size_t value) { // skip expensive update if there isn't enough visible progress - if (value - mProgress < mProgressBar->getScrollRange()/200.f) + if (mProgressBar->getWidth() <= 0 || value - mProgress < mProgressBar->getScrollRange()/mProgressBar->getWidth()) return; value = std::min(value, mProgressBar->getScrollRange()-1); mProgress = value; @@ -231,7 +240,7 @@ namespace MWGui bool LoadingScreen::needToDrawLoadingScreen() { - if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) + if ( mTimer.time_m() <= mLastRenderTime + (1.0/getTargetFrameRate()) * 1000.0) return false; // the minimal delay before a loading screen shows diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 1a53495a9..2f8831fdc 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -43,6 +43,8 @@ namespace MWGui virtual void setVisible(bool visible); + double getTargetFrameRate() const; + private: void findSplashScreens(); bool needToDrawLoadingScreen(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b0d0d8acd..33ba58cc7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -906,19 +906,30 @@ namespace MWGui if (block) { + osg::Timer frameTimer; while (mMessageBoxManager->readPressedButton(false) == -1 && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - mMessageBoxManager->onFrame(0.f); - MWBase::Environment::get().getInputManager()->update(0, true, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + mMessageBoxManager->onFrame(dt); + MWBase::Environment::get().getInputManager()->update(dt, true, false); + + if (!MWBase::Environment::get().getInputManager()->isWindowVisible()) + OpenThreads::Thread::microSleep(5000); + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. // refer to the advance() and frame() order in Engine::go() - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + + MWBase::Environment::get().limitFrameRate(frameTimer.time_s()); } } } @@ -1838,18 +1849,28 @@ namespace MWGui if (mVideoWidget->hasAudioStream()) MWBase::Environment::get().getSoundManager()->pauseSounds( MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie)); - + osg::Timer frameTimer; while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { - MWBase::Environment::get().getInputManager()->update(0, true, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + MWBase::Environment::get().getInputManager()->update(dt, true, false); + + if (!MWBase::Environment::get().getInputManager()->isWindowVisible()) + OpenThreads::Thread::microSleep(5000); + else + { + mViewer->eventTraversal(); + mViewer->updateTraversal(); + mViewer->renderingTraversals(); + } // at the time this function is called we are in the middle of a frame, // so out of order calls are necessary to get a correct frameNumber for the next frame. // refer to the advance() and frame() order in Engine::go() - mViewer->eventTraversal(); - mViewer->updateTraversal(); - mViewer->renderingTraversals(); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); + + MWBase::Environment::get().limitFrameRate(frameTimer.time_s()); } mVideoWidget->stop(); From 6f22d819c51fbd9499952507caaa34bac6c4686d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 31 Aug 2017 12:36:54 +0400 Subject: [PATCH 097/521] Do not allow to switch weapon to probe or lockpick during attack --- apps/openmw/mwclass/lockpick.cpp | 11 +++++++++++ apps/openmw/mwclass/lockpick.hpp | 2 ++ apps/openmw/mwclass/probe.cpp | 11 +++++++++++ apps/openmw/mwclass/probe.hpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.cpp | 5 +++-- 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index b8f6f5ecb..15499c1a8 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -3,6 +3,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -155,6 +156,16 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } + std::pair Lockpick::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const + { + // Do not allow equip tools from inventory during attack + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) + return std::make_pair(0, "#{sCantEquipWeapWarning}"); + + return std::make_pair(1, ""); + } + bool Lockpick::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Picks) != 0; diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index efa675c95..1bcf7fb85 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -51,6 +51,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; + virtual std::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index ecaa056f9..030ee3f8b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -3,6 +3,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -155,6 +156,16 @@ namespace MWClass return MWWorld::Ptr(cell.insert(ref), &cell); } + std::pair Probe::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const + { + // Do not allow equip tools from inventory during attack + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) + return std::make_pair(0, "#{sCantEquipWeapWarning}"); + + return std::make_pair(1, ""); + } + bool Probe::canSell (const MWWorld::ConstPtr& item, int npcServices) const { return (npcServices & ESM::NPC::Probes) != 0; diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index f67d8af86..9ac3ab0c9 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -51,6 +51,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::ConstPtr& ptr) const; ///< Return name of inventory icon. + virtual std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const; + virtual std::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 4e4462409..e912193bf 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -344,16 +344,17 @@ namespace MWGui { MWWorld::Ptr item = *button->getUserData(); bool isWeapon = item.getTypeName() == typeid(ESM::Weapon).name(); + bool isTool = item.getTypeName() == typeid(ESM::Probe).name() || item.getTypeName() == typeid(ESM::Lockpick).name(); // delay weapon switching if player is busy - if (isDelayNeeded && isWeapon) + if (isDelayNeeded && (isWeapon || isTool)) { mActivatedIndex = index; return; } // disable weapon switching if player is dead or paralyzed - if (isReturnNeeded && isWeapon) + if (isReturnNeeded && (isWeapon || isTool)) { return; } From 91dcd5bc6e6de5ee25231c9b64e75206dba3ddb7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 31 Aug 2017 13:28:09 +0400 Subject: [PATCH 098/521] Do not allow to unequip weapon from inventory during attack --- apps/openmw/mwgui/inventorywindow.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4cba7a0ae..6a2d3ff83 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -255,6 +255,19 @@ namespace MWGui } } + // If we unequip weapon during attack, it can lead to unexpected behaviour + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPtr)) + { + bool isWeapon = item.mBase.getTypeName() == typeid(ESM::Weapon).name(); + MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); + + if (isWeapon && invStore.isEquipped(item.mBase)) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sCantEquipWeapWarning}"); + return; + } + } + if (count > 1 && !shift) { CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); From 1aaa8a76c5d9654669bf5c7ff0a408df5c3ef5a0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 31 Aug 2017 16:14:48 +0400 Subject: [PATCH 099/521] Allow to play only one copy of given sound at time (bug #3647) --- apps/openmw/mwsound/soundmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 811797369..15b95b233 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -579,6 +579,9 @@ namespace MWSound if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return MWBase::SoundPtr(); + // Only one copy of given sound can be played at time on ptr, so stop previous copy + stopSound3D(ptr, soundId); + if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) { sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); From b9931fb71cb028aa8f8bb9eefb611ecb23ec096e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 31 Aug 2017 21:39:21 +0000 Subject: [PATCH 100/521] Set the shader on the node containing the StateSet --- components/shader/shadervisitor.cpp | 21 +++++++++++---------- components/shader/shadervisitor.hpp | 7 +++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index d85b72203..2d5fdfb39 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -26,6 +26,7 @@ namespace Shader , mMaterialOverridden(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) + , mNode(NULL) { } @@ -69,7 +70,7 @@ namespace Shader { if (node.getStateSet()) { - pushRequirements(); + pushRequirements(node); applyStateSet(node.getStateSet(), node); traverse(node); popRequirements(); @@ -234,9 +235,10 @@ namespace Shader } } - void ShaderVisitor::pushRequirements() + void ShaderVisitor::pushRequirements(osg::Node& node) { mRequirements.push_back(mRequirements.back()); + mRequirements.back().mNode = &node; } void ShaderVisitor::popRequirements() @@ -244,8 +246,9 @@ namespace Shader mRequirements.pop_back(); } - void ShaderVisitor::createProgram(const ShaderRequirements &reqs, osg::Node& node) + void ShaderVisitor::createProgram(const ShaderRequirements &reqs) { + osg::Node& node = *reqs.mNode; osg::StateSet* writableStateSet = NULL; if (mAllowedToModifyStateSets) writableStateSet = node.getOrCreateStateSet(); @@ -305,9 +308,9 @@ namespace Shader void ShaderVisitor::apply(osg::Geometry& geometry) { bool needPop = (geometry.getStateSet() != NULL); - if (geometry.getStateSet()) + if (geometry.getStateSet()) // TODO: check if stateset affects shader permutation before pushing it { - pushRequirements(); + pushRequirements(geometry); applyStateSet(geometry.getStateSet(), geometry); } @@ -350,9 +353,8 @@ namespace Shader rig->setSourceGeometry(sourceGeometry); } - // TODO: find a better place for the stateset if (useShader) - createProgram(reqs, geometry); + createProgram(reqs); } if (needPop) @@ -366,16 +368,15 @@ namespace Shader if (drawable.getStateSet()) { - pushRequirements(); + pushRequirements(drawable); applyStateSet(drawable.getStateSet(), drawable); } if (!mRequirements.empty()) { const ShaderRequirements& reqs = mRequirements.back(); - // TODO: find a better place for the stateset if (reqs.mShaderRequired || mForceShaders) - createProgram(reqs, drawable); + createProgram(reqs); } if (needPop) diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 8f4597ff3..83f28e063 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -52,7 +52,7 @@ namespace Shader void applyStateSet(osg::ref_ptr stateset, osg::Node& node); - void pushRequirements(); + void pushRequirements(osg::Node& node); void popRequirements(); private: @@ -89,13 +89,16 @@ namespace Shader // -1 == no tangents required int mTexStageRequiringTangents; + + // the Node that requested these requirements + osg::Node* mNode; }; std::vector mRequirements; std::string mDefaultVsTemplate; std::string mDefaultFsTemplate; - void createProgram(const ShaderRequirements& reqs, osg::Node& node); + void createProgram(const ShaderRequirements& reqs); }; } From 45f7563a5579bcf3674cc44c5d9d3bd80b1c0e80 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 31 Aug 2017 21:40:35 +0000 Subject: [PATCH 101/521] Revert "Revert "Check for a Geometry node when attaching bodyparts"" Issue with shaders has been fixed with b9931fb71cb028aa8f8bb9eefb611ecb23ec096e This reverts commit a1e3fb7604a11307ed08f1ec84b31a359cb5ead5. --- components/nifosg/nifloader.cpp | 3 +++ components/sceneutil/attach.cpp | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 78186c439..b7d1c15b8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1130,6 +1130,8 @@ namespace NifOsg triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); } + geometry->setName(triShape->name); + if (geometry->getDataVariance() == osg::Object::DYNAMIC) { // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch @@ -1219,6 +1221,7 @@ namespace NifOsg osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); + rig->setName(triShape->name); const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 1385f771e..8634a4df6 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -32,29 +32,29 @@ namespace SceneUtil virtual void apply(osg::MatrixTransform& node) { - applyNode(node); - } - virtual void apply(osg::Geometry& node) - { - applyNode(node); + traverse(node); } virtual void apply(osg::Node& node) { - applyNode(node); + traverse(node); } virtual void apply(osg::Group& node) { - applyNode(node); + traverse(node); } - void applyNode(osg::Node& node) + virtual void apply(osg::Geometry& geom) { - std::string lowerName = Misc::StringUtils::lowerCase(node.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) - mToCopy.push_back(&node); - else - traverse(node); + { + osg::Node* node = &geom; + while (node && node->getNumParents() && !node->getStateSet()) + node = node->getParent(0); + if (node) + mToCopy.push_back(node); + } } void doCopy() From a8005c33d9ea82ffa49c30f40022908f7215261e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 31 Aug 2017 21:57:26 +0000 Subject: [PATCH 102/521] Revert unintended change to mOnGround variable that was somehow introduced with 38a2de3c51edd808e5a3acba9e94c8ed11d227dd --- apps/openmw/mwphysics/actor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index e5e36def8..79c6dcabf 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -18,7 +18,7 @@ namespace MWPhysics Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr shape, btCollisionWorld* world) : mCanWaterWalk(false), mWalkingOnWater(false) - , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(false), mOnSlope(false) + , mCollisionObject(nullptr), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false) , mInternalCollisionMode(true) , mExternalCollisionMode(true) , mCollisionWorld(world) From 5d14a2afcce241fe9b1677aa48e2b1b4a07a274f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 24 Aug 2017 17:12:15 -0400 Subject: [PATCH 103/521] Initial LTEX/LAND tables --- apps/opencs/model/prefs/state.cpp | 2 + apps/opencs/model/world/columnimp.hpp | 64 ++++++++++++++++++++++--- apps/opencs/model/world/columns.cpp | 4 +- apps/opencs/model/world/columns.hpp | 3 ++ apps/opencs/model/world/data.cpp | 14 ++++++ apps/opencs/model/world/universalid.cpp | 8 +++- apps/opencs/model/world/universalid.hpp | 4 ++ apps/opencs/view/doc/view.cpp | 20 ++++++++ apps/opencs/view/doc/view.hpp | 4 ++ apps/opencs/view/world/subviews.cpp | 2 + 10 files changed, 116 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 5c0b2e282..0101a432b 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -240,6 +240,8 @@ void CSMPrefs::State::declare() declareShortcut ("document-world-cells", "Open Cell List", QKeySequence()); declareShortcut ("document-world-referencables", "Open Object List", QKeySequence()); declareShortcut ("document-world-references", "Open Instance List", QKeySequence()); + declareShortcut ("document-world-lands", "Open Lands List", QKeySequence()); + declareShortcut ("document-world-landtextures", "Open Land Textures List", QKeySequence()); declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence()); declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence()); declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence()); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 154bdab82..a9a48ef0d 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -15,6 +15,9 @@ #include "columns.hpp" #include "info.hpp" +#include "land.hpp" +#include "landtexture.hpp" + namespace CSMWorld { /// \note Shares ID with VarValueColumn. A table can not have both. @@ -1499,9 +1502,9 @@ namespace CSMWorld template struct TopicColumn : public Column { - TopicColumn (bool journal) + TopicColumn (bool journal) : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, - journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) + journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) {} virtual QVariant get (const Record& record) const @@ -1755,7 +1758,7 @@ namespace CSMWorld return true; } }; - + template struct GenderNpcColumn : public Column { @@ -2198,8 +2201,8 @@ namespace CSMWorld struct EffectTextureColumn : public Column { EffectTextureColumn (Columns::ColumnId columnId) - : Column (columnId, - columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : Column (columnId, + columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture : ColumnBase::Display_Icon) { assert (this->mColumnId==Columns::ColumnId_Icon || @@ -2417,7 +2420,56 @@ namespace CSMWorld return true; } }; - + + template + struct TextureIndexColumn : public Column + { + TextureIndexColumn() + : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record& record) const + { + return record.get().mIndex; + } + + virtual bool isEditable() const + { + return false; + } + }; + + // TODO remove + template + struct PluginIndexColumn : public Column + { + PluginIndexColumn() + : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + {} + + QVariant get (const Record& record) const + { + return -1; + } + + virtual bool isEditable() const + { + return false; + } + }; + + template<> + inline QVariant PluginIndexColumn::get (const Record& record) const + { + return record.get().mPlugin; + } + + template<> + inline QVariant PluginIndexColumn::get (const Record& record) const + { + return record.get().mPluginIndex; + } + struct BodyPartRaceColumn : public RaceColumn { const MeshTypeColumn *mMeshType; diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index aeee0d208..cec11211c 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -124,7 +124,7 @@ namespace CSMWorld { ColumnId_Portable, "Portable" }, { ColumnId_NegativeLight, "Negative Light" }, { ColumnId_EmitterType, "Emitter Type" }, - + { ColumnId_Fire, "Fire" }, { ColumnId_OffByDefault, "Off by default" }, { ColumnId_IsKey, "Is Key" }, @@ -330,6 +330,8 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, + { ColumnId_PluginIndex, "Plugin Index" }, + { ColumnId_TextureIndex, "Texture Index" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b23d86367..1ff871c84 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,6 +329,9 @@ namespace CSMWorld ColumnId_Text = 297, + ColumnId_PluginIndex = 298, + ColumnId_TextureIndex = 299, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 007190e4a..456d2bccc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -412,6 +412,18 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight)); mMagicEffects.addColumn (new DescriptionColumn); + mLand.addColumn (new StringIdColumn); + mLand.addColumn (new RecordStateColumn); + mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); + mLand.addColumn (new PluginIndexColumn); + + mLandTextures.addColumn (new StringIdColumn); + mLandTextures.addColumn (new RecordStateColumn); + mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new PluginIndexColumn); + mLandTextures.addColumn (new TextureIndexColumn); + mLandTextures.addColumn (new TextureColumn); + mPathgrids.addColumn (new StringIdColumn); mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); @@ -531,6 +543,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); + addModel (new IdTable (&mLand), UniversalId::Type_Land); + addModel (new IdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 77db2be10..38386f6da 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -53,6 +53,8 @@ namespace { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "LandTextures", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 }, @@ -118,6 +120,8 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, @@ -364,8 +368,8 @@ std::vector CSMWorld::UniversalId::listTypes (int c for (int i=0; sIndexArg[i].mName; ++i) if (sIndexArg[i].mClass & classes) list.push_back (sIndexArg[i].mType); - - return list; + + return list; } CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type) diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index e9104fc22..accd1b78d 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -126,6 +126,10 @@ namespace CSMWorld Type_SoundGen, Type_MagicEffects, Type_MagicEffect, + Type_Lands, + Type_Land, + Type_LandTextures, + Type_LandTexture, Type_Pathgrids, Type_Pathgrid, Type_StartScripts, diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfbeea031..10de46e06 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -172,6 +172,16 @@ void CSVDoc::View::setupWorldMenu() setupShortcut("document-world-references", references); world->addAction (references); + QAction *lands = new QAction (tr ("Lands"), this); + connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView())); + setupShortcut("document-world-lands", lands); + world->addAction (lands); + + QAction *landTextures = new QAction (tr ("Land Textures"), this); + connect (landTextures, SIGNAL (triggered()), this, SLOT (addLandTexturesSubView())); + setupShortcut("document-world-landtextures", landTextures); + world->addAction (landTextures); + QAction *grid = new QAction (tr ("Pathgrid"), this); connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView())); setupShortcut("document-world-pathgrid", grid); @@ -876,6 +886,16 @@ void CSVDoc::View::addRunLogSubView() addSubView (CSMWorld::UniversalId::Type_RunLog); } +void CSVDoc::View::addLandsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Lands); +} + +void CSVDoc::View::addLandTexturesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_LandTextures); +} + void CSVDoc::View::addPathgridSubView() { addSubView (CSMWorld::UniversalId::Type_Pathgrids); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 834407be0..46aa87891 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -224,6 +224,10 @@ namespace CSVDoc void addRunLogSubView(); + void addLandsSubView(); + + void addLandTexturesSubView(); + void addPathgridSubView(); void addStartScriptsSubView(); diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 7c27bdf7a..b570397b7 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -43,6 +43,8 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_SoundGens, + CSMWorld::UniversalId::Type_Lands, + CSMWorld::UniversalId::Type_LandTextures, CSMWorld::UniversalId::Type_None // end marker }; From 9e41f1340ae3b7bd9ee3a598b11d7fb479bc36e5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 25 Aug 2017 19:51:30 -0400 Subject: [PATCH 104/521] Replace nonconst getId with setId, add template specialization and specialized derived classes for LandTexture --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 31 +++-- apps/opencs/model/world/columnimp.hpp | 43 ++++++- apps/opencs/model/world/columns.cpp | 1 + apps/opencs/model/world/columns.hpp | 5 +- apps/opencs/model/world/data.cpp | 5 +- apps/opencs/model/world/idtable.cpp | 31 +++++ apps/opencs/model/world/idtable.hpp | 15 +++ apps/opencs/model/world/landtexture.cpp | 17 +++ apps/opencs/model/world/landtexture.hpp | 5 + apps/opencs/view/world/landtexturecreator.cpp | 106 ++++++++++++++++++ apps/opencs/view/world/landtexturecreator.hpp | 49 ++++++++ apps/opencs/view/world/subviews.cpp | 15 ++- components/esm/loadltex.cpp | 2 +- components/esm/loadltex.hpp | 3 +- 15 files changed, 308 insertions(+), 22 deletions(-) create mode 100644 apps/opencs/view/world/landtexturecreator.cpp create mode 100644 apps/opencs/view/world/landtexturecreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0a146dc06..4207258db 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator + bodypartcreator landtexturecreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 16f5ce51f..9d867ff93 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -13,8 +14,8 @@ #include #include "columnbase.hpp" - #include "collectionbase.hpp" +#include "landtexture.hpp" namespace CSMWorld { @@ -22,15 +23,14 @@ namespace CSMWorld template struct IdAccessor { - std::string& getId (ESXRecordT& record); - + void setId(ESXRecordT& record, const std::string& id) const; const std::string getId (const ESXRecordT& record) const; }; template - std::string& IdAccessor::getId (ESXRecordT& record) + void IdAccessor::setId(ESXRecordT& record, const std::string& id) const { - return record.mId; + record.mId = id; } template @@ -39,6 +39,23 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor::setId (LandTexture& record, const std::string& id) const + { + int plugin = 0; + int index = 0; + + LandTexture::parseUniqueRecordId(id, plugin, index); + record.mPluginIndex = plugin; + record.mIndex = index; + } + + template<> + inline const std::string IdAccessor::getId (const LandTexture& record) const + { + return LandTexture::createUniqueRecordId(record.mPluginIndex, record.mIndex); + } + /// \brief Single-type record collection template > class Collection : public CollectionBase @@ -213,7 +230,7 @@ namespace CSMWorld Record copy; copy.mModified = getRecord(origin).get(); copy.mState = RecordBase::State_ModifiedOnly; - copy.get().mId = destination; + IdAccessorT().setId(copy.get(), destination); insertRecord(copy, getAppendIndex(destination, type)); } @@ -366,7 +383,7 @@ namespace CSMWorld UniversalId::Type type) { ESXRecordT record; - IdAccessorT().getId (record) = id; + IdAccessorT().setId(record, id); record.blank(); Record record2; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a9a48ef0d..316fa4366 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -63,6 +63,13 @@ namespace CSMWorld } }; + template<> + inline QVariant StringIdColumn::get(const Record& record) const + { + const LandTexture& ltex = record.get(); + return QString::fromUtf8(std::string('L' + std::to_string(ltex.mPluginIndex) + '#' + std::to_string(ltex.mIndex)).c_str()); + } + template struct RecordStateColumn : public Column { @@ -2421,6 +2428,31 @@ namespace CSMWorld } }; + template + struct TextureHandleColumn : public Column + { + TextureHandleColumn() + : Column (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) + {} + + QVariant get(const Record& record) const override + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void set(Record& record, const QVariant& data) override + { + ESXRecordT copy = record.get(); + copy.mId = data.toString().toUtf8().constData(); + record.setModified(copy); + } + + bool isEditable() const override + { + return true; + } + }; + template struct TextureIndexColumn : public Column { @@ -2428,31 +2460,30 @@ namespace CSMWorld : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) {} - QVariant get (const Record& record) const + QVariant get(const Record& record) const override { return record.get().mIndex; } - virtual bool isEditable() const + bool isEditable() const override { return false; } }; - // TODO remove template struct PluginIndexColumn : public Column { PluginIndexColumn() - : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer) + : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) {} - QVariant get (const Record& record) const + QVariant get(const Record& record) const override { return -1; } - virtual bool isEditable() const + virtual bool isEditable() const override { return false; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index cec11211c..49935d40d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,6 +330,7 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, + { ColumnId_TextureHandle, "Texture Handle" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1ff871c84..c6e2a2a41 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,8 +329,9 @@ namespace CSMWorld ColumnId_Text = 297, - ColumnId_PluginIndex = 298, - ColumnId_TextureIndex = 299, + ColumnId_TextureHandle = 298, + ColumnId_PluginIndex = 299, + ColumnId_TextureIndex = 300, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 456d2bccc..b0ab73de1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -417,9 +417,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn); - mLandTextures.addColumn (new StringIdColumn); + mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); + mLandTextures.addColumn (new TextureHandleColumn); mLandTextures.addColumn (new PluginIndexColumn); mLandTextures.addColumn (new TextureIndexColumn); mLandTextures.addColumn (new TextureColumn); @@ -544,7 +545,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mLand), UniversalId::Type_Land); - addModel (new IdTable (&mLandTextures), UniversalId::Type_LandTexture); + addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTree (&mReferenceables, &mReferenceables, IdTable::Feature_Preview), diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 7975e05ea..078484aab 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -281,3 +281,34 @@ CSMWorld::CollectionBase *CSMWorld::IdTable::idCollection() const { return mIdCollection; } + +CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, unsigned int features) + : IdTable(idCollection, features) +{ +} + +QVariant CSMWorld::LandTextureIdTable::data(const QModelIndex& index, int role) const +{ + if (role==Qt::EditRole && !idCollection()->getRecord(index.row()).isModified()) + return QVariant(); + + return IdTable::data(index, role); +} + +bool CSMWorld::LandTextureIdTable::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (!idCollection()->getRecord(index.row()).isModified()) + return false; + else + return IdTable::setData(index, value, role); +} + +Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = IdTable::flags(index); + + if (!idCollection()->getRecord(index.row()).isModified()) + flags &= ~Qt::ItemIsEditable; + + return flags; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 9faf64d71..ecca269d3 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -93,6 +93,21 @@ namespace CSMWorld virtual CollectionBase *idCollection() const; }; + + /// An IdTable customized to handle the more unique needs of LandTextureId's which behave + /// differently from other records. + class LandTextureIdTable : public IdTable + { + public: + + LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); + + QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; + + bool setData(const QModelIndex& index, const QVariant& value, int role) override; + + Qt::ItemFlags flags (const QModelIndex & index) const override; + }; } #endif diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 266377d0f..4b82f8d73 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,5 +1,7 @@ #include "landtexture.hpp" +#include + #include namespace CSMWorld @@ -11,4 +13,19 @@ namespace CSMWorld mPluginIndex = esm.getIndex(); } + std::string LandTexture::createUniqueRecordId(int plugin, int index) + { + return 'L' + std::to_string(plugin) + '#' + std::to_string(index); + } + + void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) + { + size_t middle = id.find('#'); + + if (middle == std::string::npos || id[0] != 'L') + throw std::runtime_error("Invalid LandTexture ID"); + + plugin = std::stoi(id.substr(1,middle-1)); + index = std::stoi(id.substr(middle+1)); + } } diff --git a/apps/opencs/model/world/landtexture.hpp b/apps/opencs/model/world/landtexture.hpp index 91459eee2..a7376438c 100644 --- a/apps/opencs/model/world/landtexture.hpp +++ b/apps/opencs/model/world/landtexture.hpp @@ -13,6 +13,11 @@ namespace CSMWorld int mPluginIndex; void load (ESM::ESMReader &esm, bool &isDeleted); + + /// Returns a string identifier that will be unique to any LandTexture. + static std::string createUniqueRecordId(int plugin, int index); + /// Deconstructs a unique string identifier into plugin and index. + static void parseUniqueRecordId(const std::string& id, int& plugin, int& index); }; } diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp new file mode 100644 index 000000000..f79c08427 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -0,0 +1,106 @@ +#include "landtexturecreator.hpp" + +#include +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/landtexture.hpp" + +namespace CSVWorld +{ + LandTextureCreator::LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) + : GenericCreator(data, undoStack, id) + { + // One index is reserved for a default texture + const size_t MaxIndex = std::numeric_limits::max() - 1; + + setManualEditing(false); + + QLabel* nameLabel = new QLabel("Name"); + insertBeforeButtons(nameLabel, false); + + mNameEdit = new QLineEdit(this); + insertBeforeButtons(mNameEdit, true); + + QLabel* indexLabel = new QLabel("Index"); + insertBeforeButtons(indexLabel, false); + + QIntValidator* indexValidator = new QIntValidator(0, MaxIndex, this); + + mIndexEdit = new QLineEdit(this); + mIndexEdit->setValidator(indexValidator); + insertBeforeButtons(mIndexEdit, true); + + connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); + connect(mIndexEdit, SIGNAL(textChanged(const QString&)), this, SLOT(indexChanged(const QString&))); + } + + void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) + { + GenericCreator::cloneMode(originId, type); + + CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); + + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + + column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); + mIndexEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + } + + void LandTextureCreator::focus() + { + mIndexEdit->setFocus(); + } + + void LandTextureCreator::reset() + { + GenericCreator::reset(); + mNameEdit->setText(""); + mIndexEdit->setText(""); + } + + std::string LandTextureCreator::getErrors() const + { + std::string id = getId(); + + // TODO empty index edit? + if (getData().getLandTextures().searchId(getId()) >= 0) + { + return "Index is already in use"; + } + + return ""; + } + + void LandTextureCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const + { + GenericCreator::configureCreateCommand(command); + + CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + command.addValue(column, mName.c_str()); + } + + std::string LandTextureCreator::getId() const + { + return CSMWorld::LandTexture::createUniqueRecordId(0, mIndex); + } + + void LandTextureCreator::nameChanged(const QString& value) + { + mName = value.toUtf8().constData(); + update(); + } + + void LandTextureCreator::indexChanged(const QString& value) + { + mIndex = value.toInt(); + update(); + } +} diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp new file mode 100644 index 000000000..46388bf03 --- /dev/null +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_WORLD_LANDTEXTURECREATOR_H +#define CSV_WORLD_LANDTEXTURECREATOR_H + +#include + +#include "genericcreator.hpp" + +class QLineEdit; + +namespace CSVWorld +{ + class LandTextureCreator : public GenericCreator + { + Q_OBJECT + + public: + + LandTextureCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + + void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + + void focus() override; + + void reset() override; + + std::string getErrors() const override; + + protected: + + void configureCreateCommand(CSMWorld::CreateCommand& command) const override; + + std::string getId() const override; + + private slots: + + void nameChanged(const QString& val); + void indexChanged(const QString& val); + + private: + + QLineEdit* mNameEdit; + QLineEdit* mIndexEdit; + + std::string mName; + int mIndex; + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index b570397b7..a33802823 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -18,6 +18,7 @@ #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "bodypartcreator.hpp" +#include "landtexturecreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -43,8 +44,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, CSMWorld::UniversalId::Type_SoundGens, - CSMWorld::UniversalId::Type_Lands, - CSMWorld::UniversalId::Type_LandTextures, CSMWorld::UniversalId::Type_None // end marker }; @@ -83,6 +82,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrids, new CSVDoc::SubViewFactoryWithCreator); + manager.add (CSMWorld::UniversalId::Type_Lands, + new CSVDoc::SubViewFactoryWithCreator >); + + manager.add (CSMWorld::UniversalId::Type_LandTextures, + new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreator >); @@ -183,6 +188,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Pathgrid, new CSVDoc::SubViewFactoryWithCreator (false)); + manager.add (CSMWorld::UniversalId::Type_Land, + new CSVDoc::SubViewFactoryWithCreator >(false)); + + manager.add (CSMWorld::UniversalId::Type_LandTexture, + new CSVDoc::SubViewFactoryWithCreator >(false)); + manager.add (CSMWorld::UniversalId::Type_DebugProfile, new CSVDoc::SubViewFactoryWithCreator > (false)); diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 613b706e3..3e150f9c0 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -59,7 +59,7 @@ namespace ESM void LandTexture::blank() { + mId.clear(); mTexture.clear(); - mIndex = -1; } } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index 2cb5abf0c..1604e9281 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -31,14 +31,15 @@ struct LandTexture /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "LandTexture"; } + // mId is merely a user friendly name for the texture in the editor. std::string mId, mTexture; int mIndex; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; + /// Sets the record to the default state. Does not touch the index. Does touch mID. void blank(); - ///< Set record to default state (does not touch the ID). }; } #endif From 1d480015b46f78f747642d2d7b3b381b161119c9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Thu, 31 Aug 2017 22:01:38 -0400 Subject: [PATCH 105/521] Add ability to touch records, LAND records in particular --- apps/opencs/model/world/collection.hpp | 23 ++++++++++++ apps/opencs/model/world/collectionbase.hpp | 2 ++ apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/model/world/commands.cpp | 25 +++++++++++++ apps/opencs/model/world/commands.hpp | 19 ++++++++++ apps/opencs/model/world/data.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 20 +++++++++++ apps/opencs/model/world/idtable.hpp | 5 +++ apps/opencs/model/world/idtablebase.hpp | 6 ++-- apps/opencs/model/world/refidcollection.cpp | 6 ++++ apps/opencs/model/world/refidcollection.hpp | 2 ++ apps/opencs/view/world/table.cpp | 40 +++++++++++++++++++-- apps/opencs/view/world/table.hpp | 3 ++ 13 files changed, 149 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 9d867ff93..f69d06d78 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -125,6 +125,10 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); + virtual bool touchRecord(const std::string& id); + ///< Change the state of a record from base to modified, if it is not already. + /// \return True if the record was changed. + virtual int searchId (const std::string& id) const; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) @@ -235,6 +239,25 @@ namespace CSMWorld insertRecord(copy, getAppendIndex(destination, type)); } + template + bool Collection::touchRecord(const std::string& id) + { + int index = getIndex(id); + Record& record = mRecords.at(index); + if (record.isDeleted()) + { + throw std::runtime_error("attempt to touch deleted record"); + } + + if (!record.isModified() && !record.isDeleted() && !record.isErased()) + { + record.setModified(record.get()); + return true; + } + else + return false; + } + template Collection::Collection() {} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index ef826e31c..bac790c5d 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -78,6 +78,8 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type) = 0; + virtual bool touchRecord(const std::string& id) = 0; + virtual const RecordBase& getRecord (const std::string& id) const = 0; virtual const RecordBase& getRecord (int index) const = 0; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 316fa4366..92e899a45 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,7 +67,7 @@ namespace CSMWorld inline QVariant StringIdColumn::get(const Record& record) const { const LandTexture& ltex = record.get(); - return QString::fromUtf8(std::string('L' + std::to_string(ltex.mPluginIndex) + '#' + std::to_string(ltex.mIndex)).c_str()); + return QString(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); } template diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5f9422376..c6a56f7b8 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -15,6 +15,31 @@ #include "nestedtablewrapper.hpp" #include "pathgrid.hpp" +CSMWorld::TouchCommand::TouchCommand(IdTable& table, const std::string& id, QUndoCommand* parent) + : QUndoCommand(parent) + , mTable(table) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mTable.getRecord(mId).clone()); +} + +void CSMWorld::TouchCommand::redo() +{ + mChanged = mTable.touchRecord(mId); +} + +void CSMWorld::TouchCommand::undo() +{ + if (mChanged) + { + mTable.setRecord(mId, *mOld); + mChanged = false; + } +} + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index b54a1d5ac..4c9be7e8a 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -24,6 +25,24 @@ namespace CSMWorld struct RecordBase; struct NestedTableWrapperBase; + class TouchCommand : public QUndoCommand + { + public: + + TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr); + + virtual void redo(); + virtual void undo(); + + private: + + IdTable& mTable; + std::string mId; + std::unique_ptr mOld; + + bool mChanged; + }; + class ModifyCommand : public QUndoCommand { QAbstractItemModel *mModel; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b0ab73de1..27a914aeb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -544,7 +544,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); - addModel (new IdTable (&mLand), UniversalId::Type_Land); + addModel (new IdTable (&mLand, IdTable::Feature_AllowTouch), UniversalId::Type_Land); addModel (new LandTextureIdTable (&mLandTextures), UniversalId::Type_LandTexture); addModel (new IdTree (&mPathgrids, &mPathgrids), UniversalId::Type_Pathgrid); addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 078484aab..94eab3fc3 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -179,6 +179,26 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, endInsertRows(); } +bool CSMWorld::IdTable::touchRecord(const std::string& id) +{ + bool changed = mIdCollection->touchRecord(id); + + int row = mIdCollection->getIndex(id); + int column = mIdCollection->searchColumnIndex(Columns::ColumnId_RecordType); + if (changed && column != -1) + { + QModelIndex modelIndex = index(row, column); + emit dataChanged(modelIndex, modelIndex); + } + + return changed; +} + +std::string CSMWorld::IdTable::getId(int row) const +{ + return mIdCollection->getId(row); +} + ///This method can return only indexes to the top level table cells QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const { diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ecca269d3..5e5f9da4a 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -61,6 +61,11 @@ namespace CSMWorld const std::string& destination, UniversalId::Type type = UniversalId::Type_None); + bool touchRecord(const std::string& id); + ///< Will change the record state to modified, if it is not already. + + std::string getId(int row) const; + virtual QModelIndex getModelIndex (const std::string& id, int column) const; void setRecord (const std::string& id, const RecordBase& record, diff --git a/apps/opencs/model/world/idtablebase.hpp b/apps/opencs/model/world/idtablebase.hpp index 0d77d48ef..8b82f984b 100644 --- a/apps/opencs/model/world/idtablebase.hpp +++ b/apps/opencs/model/world/idtablebase.hpp @@ -32,7 +32,9 @@ namespace CSMWorld Feature_Preview = 8, /// Table can not be modified through ordinary means. - Feature_Constant = 16 + Feature_Constant = 16, + + Feature_AllowTouch = 32 }; private: @@ -61,7 +63,7 @@ namespace CSMWorld virtual bool isDeleted (const std::string& id) const = 0; virtual int getColumnId (int column) const = 0; - + unsigned int getFeatures() const; }; } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 31dae256e..44a6ce07d 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -813,6 +813,12 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, mData.insertRecord(*newRecord, type, destination); } +bool CSMWorld::RefIdCollection::touchRecord(const std::string& id) +{ + throw std::runtime_error("RefIdCollection::touchRecord is unimplemented"); + return false; +} + void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, UniversalId::Type type) { diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index de5a709c6..48558d1c2 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -80,6 +80,8 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); + virtual bool touchRecord(const std::string& id); + virtual void appendBlankRecord (const std::string& id, UniversalId::Type type); ///< \param type Will be ignored, unless the collection supports multiple record types diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 30dba4241..580d27a24 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -60,6 +60,9 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) menu.addAction(mCloneAction); } + if (mTouchAction) + menu.addAction (mTouchAction); + if (mCreateAction) menu.addAction (mCreateAction); @@ -226,8 +229,8 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) -: DragRecordTable(document), mCreateAction (0), - mCloneAction(0), mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) + : DragRecordTable(document), mCreateAction (nullptr), mCloneAction(nullptr), mTouchAction(nullptr), + mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) { mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); @@ -302,6 +305,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, cloneShortcut->associateAction(mCloneAction); } + if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) + { + mTouchAction = new QAction(tr("Touch Record"), this); + connect(mTouchAction, SIGNAL(triggered()), this, SLOT(touchRecord())); + addAction(mTouchAction); + CSMPrefs::Shortcut* touchShortcut = new CSMPrefs::Shortcut("table-touch", this); + touchShortcut->associateAction(mTouchAction); + } + mRevertAction = new QAction (tr ("Revert Record"), this); connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert())); addAction (mRevertAction); @@ -442,6 +454,30 @@ void CSVWorld::Table::cloneRecord() } } +void CSVWorld::Table::touchRecord() +{ + if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) + { + if (CSMWorld::IdTable* table = dynamic_cast(mModel)) + { + QUndoCommand* touchRecords = new QUndoCommand(); + touchRecords->setText("Touch records"); + + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + { + QModelIndex index = mProxyModel->mapToSource(mProxyModel->index(it->row(),0)); + std::string id = table->getId(index.row()); + + // command is a child of touchRecords + QUndoCommand* command = new CSMWorld::TouchCommand(*table, id, touchRecords); + } + + mDocument.getUndoStack().push(touchRecords); + } + } +} + void CSVWorld::Table::moveUpRecord() { if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 26f6e7899..d6fa17ef9 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -56,6 +56,7 @@ namespace CSVWorld QAction *mEditAction; QAction *mCreateAction; QAction *mCloneAction; + QAction *mTouchAction; QAction *mRevertAction; QAction *mDeleteAction; QAction *mMoveUpAction; @@ -129,6 +130,8 @@ namespace CSVWorld void cloneRecord(); + void touchRecord(); + void moveUpRecord(); void moveDownRecord(); From 0d7279ea2a6086232bc8235597924579f1aecd3f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Sep 2017 08:59:05 +0400 Subject: [PATCH 106/521] Fixes a regression with bound weapons equipping (bug #4050) --- apps/openmw/mwclass/weapon.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 62a9b6d0f..9fb4a9767 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -374,7 +374,9 @@ namespace MWClass if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0) return std::make_pair(0, "#{sInventoryMessage1}"); - if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc)) + // Do not allow equip weapons from inventory during attack + if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(npc) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) return std::make_pair(0, "#{sCantEquipWeapWarning}"); std::pair, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr); From a5b01fefec97ca69e07872034853f2bd7f24b9c4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Sep 2017 09:34:15 +0400 Subject: [PATCH 107/521] Allow to interrupt an attack, if attack button is held --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++++- apps/openmw/mwmechanics/actors.cpp | 10 ++++++++++ apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 ++ 8 files changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7e1059d06..84d43156e 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -247,6 +247,7 @@ namespace MWBase virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; + virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0; virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; }; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5f3e3152d..e4fa8fc2b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -948,7 +948,11 @@ namespace MWInput if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"]) return; - if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) + // We want to interrupt animation only if attack is prepairing, but still is not triggered + // Otherwise we will get a "speedshooting" exploit, when player can skip reload animation by hitting "Toggle Weapon" key twice + if (MWBase::Environment::get().getMechanicsManager()->isAttackPrepairing(mPlayer->getPlayer())) + mPlayer->setAttackingOrSpell(false); + else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer())) return; MWMechanics::DrawState_ state = mPlayer->getDrawState(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fba8d1a4d..ed510e616 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -802,6 +802,16 @@ namespace MWMechanics } } + bool Actors::isAttackPrepairing(const MWWorld::Ptr& ptr) + { + PtrActorMap::iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + CharacterController* ctrl = it->second->getCharacterController(); + + return ctrl->isAttackPrepairing(); + } + bool Actors::isRunning(const MWWorld::Ptr& ptr) { PtrActorMap::iterator it = mActors.find(ptr); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 052bf4920..6eb3a2955 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -107,6 +107,7 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + bool isAttackPrepairing(const MWWorld::Ptr& ptr); bool isRunning(const MWWorld::Ptr& ptr); bool isSneaking(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index e9f42476b..51dc37e18 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2218,6 +2218,12 @@ void CharacterController::setAttackTypeBasedOnMovement() mAttackType = "chop"; } +bool CharacterController::isAttackPrepairing() const +{ + return mUpperBodyState == UpperCharState_StartToMinAttack || + mUpperBodyState == UpperCharState_MinAttackToMaxAttack; +} + bool CharacterController::isReadyToBlock() const { return updateCarriedLeftVisible(mWeaponType); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index bde64cdfb..9bcad0994 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -263,6 +263,7 @@ public: void forceStateUpdate(); + bool isAttackPrepairing() const; bool isReadyToBlock() const; bool isKnockedOut() const; bool isSneaking() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 83780e9f8..5f3dd58af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -423,6 +423,11 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr) + { + return mActors.isAttackPrepairing(ptr); + } + bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr) { return mActors.isRunning(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 47dc6e6a2..adad21916 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -210,8 +210,10 @@ namespace MWMechanics virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count); + virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr); virtual bool isRunning(const MWWorld::Ptr& ptr); virtual bool isSneaking(const MWWorld::Ptr& ptr); + private: void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); From 7f5f5458d448fbc8eaa422047d14d6c0762b6733 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 1 Sep 2017 18:03:23 +0400 Subject: [PATCH 108/521] Reset player attack animation when unequip weapon or tool --- apps/openmw/mwrender/npcanimation.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 73927e0ab..e4d0abf7b 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -23,6 +23,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" @@ -919,6 +920,9 @@ void NpcAnimation::showWeapons(bool showWeapon) else { removeIndividualPart(ESM::PRT_Weapon); + // If we remove/hide weapon from player, we should reset attack animation as well + if (mPtr == MWMechanics::getPlayer()) + MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); } } From 132ac6001b36c91f59465204f8e799c32346ae89 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 18:24:48 +0200 Subject: [PATCH 109/521] Fix bug of Animation::mSkeleton not being assigned This bug resulted in deactivating a Skeleton not working properly for creatures (that are out of processing range), therefore reduced performance. --- apps/openmw/mwrender/animation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98d29bfc9..22bafaa71 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1192,6 +1192,9 @@ namespace MWRender mObjectRoot->addChild(created); mInsert->addChild(mObjectRoot); } + osg::ref_ptr skel = dynamic_cast(mObjectRoot.get()); + if (skel) + mSkeleton = skel.get(); } else { From 209e139aa89015cad87b39dc160f9a5af0998040 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 18:27:00 +0200 Subject: [PATCH 110/521] Move double buffering implementation inside RigGeometry The double buffering is an implementation detail so it should be handled as such, rather than mandating the scene graph to be structured in a certain way. Override accept(NodeVisitor&) instead of using callbacks. --- components/nifosg/nifloader.cpp | 13 +- components/sceneutil/attach.cpp | 6 +- components/sceneutil/riggeometry.cpp | 193 +++++++++++---------------- components/sceneutil/riggeometry.hpp | 20 +-- components/sceneutil/serialize.cpp | 2 +- components/sceneutil/skeleton.cpp | 17 +-- components/sceneutil/skeleton.hpp | 2 - 7 files changed, 97 insertions(+), 156 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index b7d1c15b8..6b603cc9e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1236,7 +1236,6 @@ namespace NifOsg SceneUtil::RigGeometry::BoneInfluence influence; const std::vector &weights = data->bones[i].weights; - //influence.mWeights.reserve(weights.size()); for(size_t j = 0;j < weights.size();j++) { std::pair indexWeight = std::make_pair(weights[j].vertex, weights[j].weight); @@ -1249,17 +1248,7 @@ namespace NifOsg } rig->setInfluenceMap(map); - // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch - // This is so we can set the DataVariance as STATIC, giving a huge performance boost - rig->setDataVariance(osg::Object::STATIC); - - osg::ref_ptr frameswitch = new FrameSwitch; - - SceneUtil::RigGeometry* rig2 = osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES); - frameswitch->addChild(rig); - frameswitch->addChild(rig2); - - parentNode->addChild(frameswitch); + parentNode->addChild(rig); } osg::BlendFunc::BlendFuncMode getBlendMode(int mode) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 8634a4df6..1df1be27f 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -43,13 +43,13 @@ namespace SceneUtil traverse(node); } - virtual void apply(osg::Geometry& geom) + virtual void apply(osg::Drawable& drawable) { - std::string lowerName = Misc::StringUtils::lowerCase(geom.getName()); + std::string lowerName = Misc::StringUtils::lowerCase(drawable.getName()); if ((lowerName.size() >= mFilter.size() && lowerName.compare(0, mFilter.size(), mFilter) == 0) || (lowerName.size() >= mFilter2.size() && lowerName.compare(0, mFilter2.size(), mFilter2) == 0)) { - osg::Node* node = &geom; + osg::Node* node = &drawable; while (node && node->getNumParents() && !node->getStateSet()) node = node->getParent(0); if (node) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 9adfdcddb..ec01f62d0 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -10,73 +10,17 @@ namespace SceneUtil { -class UpdateRigBounds : public osg::Drawable::UpdateCallback -{ -public: - UpdateRigBounds() - { - } - - UpdateRigBounds(const UpdateRigBounds& copy, const osg::CopyOp& copyop) - : osg::Drawable::UpdateCallback(copy, copyop) - { - } - - META_Object(SceneUtil, UpdateRigBounds) - - void update(osg::NodeVisitor* nv, osg::Drawable* drw) - { - RigGeometry* rig = static_cast(drw); - - rig->updateBounds(nv); - } -}; - -// TODO: make threadsafe for multiple cull threads -class UpdateRigGeometry : public osg::Drawable::CullCallback -{ -public: - UpdateRigGeometry() - { - } - - UpdateRigGeometry(const UpdateRigGeometry& copy, const osg::CopyOp& copyop) - : osg::Drawable::CullCallback(copy, copyop) - { - } - - META_Object(SceneUtil, UpdateRigGeometry) - - virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* drw, osg::State*) const - { - RigGeometry* geom = static_cast(drw); - geom->update(nv); - return false; - } -}; - -// We can't compute the bounds without a NodeVisitor, since we need the current geomToSkelMatrix. -// So we return nothing. Bounds are updated every frame in the UpdateCallback. -class DummyComputeBoundCallback : public osg::Drawable::ComputeBoundingBoxCallback -{ -public: - virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return osg::BoundingBox(); } -}; - RigGeometry::RigGeometry() : mSkeleton(NULL) , mLastFrameNumber(0) , mBoundsFirstFrame(true) { - setCullCallback(new UpdateRigGeometry); - setUpdateCallback(new UpdateRigBounds); - setSupportsDisplayList(false); - setUseVertexBufferObjects(true); - setComputeBoundingBoxCallback(new DummyComputeBoundCallback); + setUpdateCallback(new osg::Callback); // dummy to make sure getNumChildrenRequiringUpdateTraversal() is correct + // update done in accept(NodeVisitor&) } RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) - : osg::Geometry(copy, copyop) + : Drawable(copy, copyop) , mSkeleton(NULL) , mInfluenceMap(copy.mInfluenceMap) , mLastFrameNumber(0) @@ -89,57 +33,47 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) { mSourceGeometry = sourceGeometry; - osg::Geometry& from = *sourceGeometry; - - if (from.getStateSet()) - setStateSet(from.getStateSet()); - - // shallow copy primitive sets & vertex attributes that we will not modify - setPrimitiveSetList(from.getPrimitiveSetList()); - setColorArray(from.getColorArray()); - setSecondaryColorArray(from.getSecondaryColorArray()); - setFogCoordArray(from.getFogCoordArray()); - - // need to copy over texcoord list manually due to a missing null pointer check in setTexCoordArrayList(), this has been fixed in OSG 3.5 - osg::Geometry::ArrayList& texCoordList = from.getTexCoordArrayList(); - for (unsigned int i=0; i vbo (new osg::VertexBufferObject); - vbo->setUsage(GL_DYNAMIC_DRAW_ARB); - - osg::ref_ptr vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); - if (vertexArray) - { - vertexArray->setVertexBufferObject(vbo); - setVertexArray(vertexArray); - } - - if (osg::Array* normals = from.getNormalArray()) + for (unsigned int i=0; i<2; ++i) { - osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); - if (normalArray) + osg::Geometry& from = *sourceGeometry; + mGeometry[i] = new osg::Geometry(from, osg::CopyOp::SHALLOW_COPY); + osg::Geometry& to = *mGeometry[i]; + to.setSupportsDisplayList(false); + to.setUseVertexBufferObjects(true); + to.setCullingActive(false); // make sure to disable culling since that's handled by this class + + // vertices and normals are modified every frame, so we need to deep copy them. + // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO. + osg::ref_ptr vbo (new osg::VertexBufferObject); + vbo->setUsage(GL_DYNAMIC_DRAW_ARB); + + osg::ref_ptr vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); + if (vertexArray) { - normalArray->setVertexBufferObject(vbo); - setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + vertexArray->setVertexBufferObject(vbo); + to.setVertexArray(vertexArray); } - } + if (osg::Array* normals = from.getNormalArray()) + { + osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); + if (normalArray) + { + normalArray->setVertexBufferObject(vbo); + to.setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + } + } - if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) - { - mSourceTangents = tangents; - osg::ref_ptr tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); - tangentArray->setVertexBufferObject(vbo); - setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX); + if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) + { + mSourceTangents = tangents; + osg::ref_ptr tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); + tangentArray->setVertexBufferObject(vbo); + to.setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX); + } + else + mSourceTangents = NULL; } - else - mSourceTangents = NULL; } osg::ref_ptr RigGeometry::getSourceGeometry() @@ -228,7 +162,7 @@ void accumulateMatrix(const osg::Matrixf& invBindMatrix, const osg::Matrixf& mat ptrresult[14] += ptr[14] * weight; } -void RigGeometry::update(osg::NodeVisitor* nv) +void RigGeometry::cull(osg::NodeVisitor* nv) { if (!mSkeleton) { @@ -238,23 +172,24 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } - if (!mSkeleton->getActive() && mLastFrameNumber != 0) - return; - - if (mLastFrameNumber == nv->getTraversalNumber()) + if ((!mSkeleton->getActive() && mLastFrameNumber != 0) || mLastFrameNumber == nv->getTraversalNumber()) + { + nv->apply(*getGeometry(mLastFrameNumber)); return; + } mLastFrameNumber = nv->getTraversalNumber(); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); mSkeleton->updateBoneMatrices(nv->getTraversalNumber()); // skinning - osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); - osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); - osg::Vec4Array* tangentSrc = mSourceTangents; + const osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); + const osg::Vec3Array* normalSrc = static_cast(mSourceGeometry->getNormalArray()); + const osg::Vec4Array* tangentSrc = mSourceTangents; - osg::Vec3Array* positionDst = static_cast(getVertexArray()); - osg::Vec3Array* normalDst = static_cast(getNormalArray()); - osg::Vec4Array* tangentDst = static_cast(getTexCoordArray(7)); + osg::Vec3Array* positionDst = static_cast(geom.getVertexArray()); + osg::Vec3Array* normalDst = static_cast(geom.getNormalArray()); + osg::Vec4Array* tangentDst = static_cast(geom.getTexCoordArray(7)); for (Bone2VertexMap::const_iterator it = mBone2VertexMap.begin(); it != mBone2VertexMap.end(); ++it) { @@ -294,6 +229,10 @@ void RigGeometry::update(osg::NodeVisitor* nv) normalDst->dirty(); if (tangentDst) tangentDst->dirty(); + + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); } void RigGeometry::updateBounds(osg::NodeVisitor *nv) @@ -365,5 +304,29 @@ void RigGeometry::setInfluenceMap(osg::ref_ptr influenceMap) mInfluenceMap = influenceMap; } +void RigGeometry::accept(osg::NodeVisitor &nv) +{ + if (!nv.validNodeMask(*this)) + return; + + nv.pushOntoNodePath(this); + + if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + cull(&nv); + else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + updateBounds(&nv); + else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) + nv.apply(*getGeometry(mLastFrameNumber)); + else + nv.apply(*this); + + nv.popFromNodePath(); +} + +osg::Geometry* RigGeometry::getGeometry(unsigned int frame) const +{ + return mGeometry[frame%2].get(); +} + } diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 39829bcb0..097e7ea69 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -13,10 +13,9 @@ namespace SceneUtil /// @brief Mesh skinning implementation. /// @note A RigGeometry may be attached directly to a Skeleton, or somewhere below a Skeleton. /// Note though that the RigGeometry ignores any transforms below the Skeleton, so the attachment point is not that important. - /// @note To avoid race conditions, the rig geometry needs to be double buffered. This can be done - /// using a FrameSwitch node that has two RigGeometry children. In the future we may want to consider implementing - /// the double buffering inside RigGeometry. - class RigGeometry : public osg::Geometry + /// @note The internal Geometry used for rendering is double buffered, this allows updates to be done in a thread safe way while + /// not compromising rendering performance. This is crucial when using osg's default threading model of DrawThreadPerContext. + class RigGeometry : public osg::Drawable { public: RigGeometry(); @@ -24,6 +23,9 @@ namespace SceneUtil META_Object(SceneUtil, RigGeometry) + // At this point compileGLObjects() remains unimplemented, hard to avoid race conditions + // and there is limited value in compiling anyway since the data will change again for the next frame + struct BoneInfluence { osg::Matrixf mInvBindMatrix; @@ -45,13 +47,15 @@ namespace SceneUtil osg::ref_ptr getSourceGeometry(); - // Called automatically by our CullCallback - void update(osg::NodeVisitor* nv); + virtual void accept(osg::NodeVisitor &nv); - // Called automatically by our UpdateCallback + private: + void cull(osg::NodeVisitor* nv); void updateBounds(osg::NodeVisitor* nv); - private: + osg::ref_ptr mGeometry[2]; + osg::Geometry* getGeometry(unsigned int frame) const; + osg::ref_ptr mSourceGeometry; osg::ref_ptr mSourceTangents; Skeleton* mSkeleton; diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 64094275c..177d700b2 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -50,7 +50,7 @@ class RigGeometrySerializer : public osgDB::ObjectWrapper { public: RigGeometrySerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable osg::Geometry SceneUtil::RigGeometry") + : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") { } }; diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 49bc5b70f..116edfdb4 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -38,8 +38,6 @@ Skeleton::Skeleton() , mNeedToUpdateBoneMatrices(true) , mActive(true) , mLastFrameNumber(0) - , mTraversedEvenFrame(false) - , mTraversedOddFrame(false) { } @@ -50,8 +48,6 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) , mNeedToUpdateBoneMatrices(true) , mActive(copy.mActive) , mLastFrameNumber(0) - , mTraversedEvenFrame(false) - , mTraversedOddFrame(false) { } @@ -115,11 +111,6 @@ void Skeleton::updateBoneMatrices(unsigned int traversalNumber) mLastFrameNumber = traversalNumber; - if (mLastFrameNumber % 2 == 0) - mTraversedEvenFrame = true; - else - mTraversedOddFrame = true; - if (mNeedToUpdateBoneMatrices) { if (mRootBone.get()) @@ -144,18 +135,14 @@ bool Skeleton::getActive() const void Skeleton::markDirty() { - mTraversedEvenFrame = false; - mTraversedOddFrame = false; + mLastFrameNumber = 0; mBoneCache.clear(); mBoneCacheInit = false; } void Skeleton::traverse(osg::NodeVisitor& nv) { - if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR - // need to process at least 2 frames before shutting off update, since we need to have both frame-alternating RigGeometries initialized - // this would be more naturally handled if the double-buffering was implemented in RigGeometry itself rather than in a FrameSwitch decorator node - && mLastFrameNumber != 0 && mTraversedEvenFrame && mTraversedOddFrame) + if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0) return; osg::Group::traverse(nv); } diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index 542471ff1..245e3522c 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -74,8 +74,6 @@ namespace SceneUtil bool mActive; unsigned int mLastFrameNumber; - bool mTraversedEvenFrame; - bool mTraversedOddFrame; }; } From 4c5992a0d5b58ca18ed00a116f33d78b9b12aeec Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 21:45:18 +0200 Subject: [PATCH 111/521] Warn if removing a node fails --- apps/openmw/mwrender/animation.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 22bafaa71..df9b8545a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -182,7 +182,10 @@ namespace void remove() { for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - it->second->removeChild(it->first); + { + if (!it->second->removeChild(it->first)) + std::cerr << "error removing " << it->first->getName() << std::endl; + } } protected: From f1ebb129c139690450a74abbc7ae46674dcaef62 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 22:01:50 +0200 Subject: [PATCH 112/521] Fix ShaderVisitor to deal with the fact RigGeometry no longer derives from Geometry --- components/shader/shadervisitor.cpp | 81 +++++++++++++++-------------- components/shader/shadervisitor.hpp | 1 + 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 2d5fdfb39..2c0b9f0e3 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -248,6 +248,9 @@ namespace Shader void ShaderVisitor::createProgram(const ShaderRequirements &reqs) { + if (!reqs.mShaderRequired && !mForceShaders) + return; + osg::Node& node = *reqs.mNode; osg::StateSet* writableStateSet = NULL; if (mAllowedToModifyStateSets) @@ -305,6 +308,36 @@ namespace Shader } } + bool ShaderVisitor::adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs) + { + bool useShader = reqs.mShaderRequired || mForceShaders; + bool generateTangents = reqs.mTexStageRequiringTangents != -1; + bool changed = false; + + if (mAllowedToModifyStateSets && (useShader || generateTangents)) + { + // make sure that all UV sets are there + for (std::map::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it) + { + if (sourceGeometry.getTexCoordArray(it->first) == NULL) + { + sourceGeometry.setTexCoordArray(it->first, sourceGeometry.getTexCoordArray(0)); + changed = true; + } + } + + if (generateTangents) + { + osg::ref_ptr generator (new osgUtil::TangentSpaceGenerator); + generator->generate(&sourceGeometry, reqs.mTexStageRequiringTangents); + + sourceGeometry.setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX); + changed = true; + } + } + return changed; + } + void ShaderVisitor::apply(osg::Geometry& geometry) { bool needPop = (geometry.getStateSet() != NULL); @@ -318,43 +351,9 @@ namespace Shader { const ShaderRequirements& reqs = mRequirements.back(); - bool useShader = reqs.mShaderRequired || mForceShaders; - bool generateTangents = reqs.mTexStageRequiringTangents != -1; - - if (mAllowedToModifyStateSets && (useShader || generateTangents)) - { - osg::ref_ptr sourceGeometry = &geometry; - SceneUtil::RigGeometry* rig = dynamic_cast(&geometry); - if (rig) - sourceGeometry = rig->getSourceGeometry(); - - bool requiresSetGeometry = false; + adjustGeometry(geometry, reqs); - // make sure that all UV sets are there - for (std::map::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it) - { - if (sourceGeometry->getTexCoordArray(it->first) == NULL) - { - sourceGeometry->setTexCoordArray(it->first, sourceGeometry->getTexCoordArray(0)); - requiresSetGeometry = true; - } - } - - if (generateTangents) - { - osg::ref_ptr generator (new osgUtil::TangentSpaceGenerator); - generator->generate(sourceGeometry, reqs.mTexStageRequiringTangents); - - sourceGeometry->setTexCoordArray(7, generator->getTangentArray(), osg::Array::BIND_PER_VERTEX); - requiresSetGeometry = true; - } - - if (rig && requiresSetGeometry) - rig->setSourceGeometry(sourceGeometry); - } - - if (useShader) - createProgram(reqs); + createProgram(reqs); } if (needPop) @@ -375,8 +374,14 @@ namespace Shader if (!mRequirements.empty()) { const ShaderRequirements& reqs = mRequirements.back(); - if (reqs.mShaderRequired || mForceShaders) - createProgram(reqs); + createProgram(reqs); + + if (SceneUtil::RigGeometry* rig = dynamic_cast(&drawable)) + { + osg::ref_ptr sourceGeometry = rig->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + rig->setSourceGeometry(sourceGeometry); + } } if (needPop) diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 83f28e063..cb0538d9d 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -99,6 +99,7 @@ namespace Shader std::string mDefaultFsTemplate; void createProgram(const ShaderRequirements& reqs); + bool adjustGeometry(osg::Geometry& sourceGeometry, const ShaderRequirements& reqs); }; } From 5d524a6a10672c3800f5ac396272635ea1cc09a8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 22:56:09 +0200 Subject: [PATCH 113/521] Add custom version of MorphGeometry replacing osgAnimation Double buffering, custom bounding box and the update in the cull visitor (instead of update) are now all handled internally rather than needing hacks and/or callbacks. --- CMakeLists.txt | 2 +- components/CMakeLists.txt | 2 +- components/nifosg/controller.cpp | 9 +- components/nifosg/controller.hpp | 7 +- components/nifosg/nifloader.cpp | 186 +++--------------------- components/sceneutil/clone.cpp | 38 +---- components/sceneutil/morphgeometry.cpp | 187 +++++++++++++++++++++++++ components/sceneutil/morphgeometry.hpp | 81 +++++++++++ components/sceneutil/serialize.cpp | 15 +- components/shader/shadervisitor.cpp | 9 +- 10 files changed, 308 insertions(+), 228 deletions(-) create mode 100644 components/sceneutil/morphgeometry.cpp create mode 100644 components/sceneutil/morphgeometry.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ad2c64b6e..a78eac572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,7 +207,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6430dbfce..88de17903 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -49,7 +49,7 @@ add_component_dir (shader ) add_component_dir (sceneutil - clone attach visitor util statesetupdater controller skeleton riggeometry lightcontroller + clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer ) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 87a0b830e..262966e95 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -6,11 +6,10 @@ #include #include -#include - #include #include +#include #include "userdata.hpp" @@ -188,7 +187,7 @@ GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - osgAnimation::MorphGeometry* morphGeom = static_cast(drawable); + SceneUtil::MorphGeometry* morphGeom = static_cast(drawable); if (hasInput()) { if (mKeyFrames.size() <= 1) @@ -202,7 +201,7 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable val = it->interpKey(input); val = std::max(0.f, std::min(1.f, val)); - osgAnimation::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); + SceneUtil::MorphGeometry::MorphTarget& target = morphGeom->getMorphTarget(i); if (target.getWeight() != val) { target.setWeight(val); @@ -210,8 +209,6 @@ void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable } } } - - // morphGeometry::transformSoftwareMethod() done in cull callback i.e. only for visible morph geometries } UVController::UVController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 5fbb172f9..0e87af44f 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -31,11 +31,6 @@ namespace osgParticle class Emitter; } -namespace osgAnimation -{ - class MorphGeometry; -} - namespace NifOsg { @@ -172,7 +167,7 @@ namespace NifOsg virtual float getMaximum() const; }; - /// Must be set on an osgAnimation::MorphGeometry. + /// Must be set on a SceneUtil::MorphGeometry. class GeomMorpherController : public osg::Drawable::UpdateCallback, public SceneUtil::Controller { public: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6b603cc9e..8810f171a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -13,9 +13,6 @@ #include #include -// skel -#include - // particle #include #include @@ -39,6 +36,7 @@ #include #include #include +#include #include "particle.hpp" #include "userdata.hpp" @@ -83,35 +81,6 @@ namespace collectDrawableProperties(nifNode->parent, out); } - class FrameSwitch : public osg::Group - { - public: - FrameSwitch() - { - } - - FrameSwitch(const FrameSwitch& copy, const osg::CopyOp& copyop) - : osg::Group(copy, copyop) - { - } - - META_Object(NifOsg, FrameSwitch) - - virtual void traverse(osg::NodeVisitor& nv) - { - if (nv.getTraversalMode() != osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN && nv.getVisitorType() != osg::NodeVisitor::UPDATE_VISITOR) - osg::Group::traverse(nv); - else - { - for (unsigned int i=0; iaccept(nv); - } - } - } - }; - // NodeCallback used to have a node always oriented towards the camera. The node can have translation and scale // set just like a regular MatrixTransform, but the rotation set will be overridden in order to face the camera. // Must be set as a cull callback. @@ -154,70 +123,6 @@ namespace } }; - struct UpdateMorphGeometry : public osg::Drawable::CullCallback - { - UpdateMorphGeometry() - : mLastFrameNumber(0) - { - } - - UpdateMorphGeometry(const UpdateMorphGeometry& copy, const osg::CopyOp& copyop) - : osg::Drawable::CullCallback(copy, copyop) - , mLastFrameNumber(0) - { - } - - META_Object(NifOsg, UpdateMorphGeometry) - - virtual bool cull(osg::NodeVisitor* nv, osg::Drawable * drw, osg::State *) const - { - osgAnimation::MorphGeometry* geom = static_cast(drw); - if (!geom) - return false; - - if (mLastFrameNumber == nv->getTraversalNumber()) - return false; - mLastFrameNumber = nv->getTraversalNumber(); - - geom->transformSoftwareMethod(); - return false; - } - - private: - mutable unsigned int mLastFrameNumber; - }; - - // Callback to return a static bounding box for a MorphGeometry. The idea is to not recalculate the bounding box - // every time the morph weights change. To do so we return a maximum containing box that is big enough for all possible combinations of morph targets. - class StaticBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback - { - public: - StaticBoundingBoxCallback() - { - } - - StaticBoundingBoxCallback(const osg::BoundingBox& bounds) - : mBoundingBox(bounds) - { - } - - StaticBoundingBoxCallback(const StaticBoundingBoxCallback& copy, const osg::CopyOp& copyop) - : osg::Drawable::ComputeBoundingBoxCallback(copy, copyop) - , mBoundingBox(copy.mBoundingBox) - { - } - - META_Object(NifOsg, StaticBoundingBoxCallback) - - virtual osg::BoundingBox computeBound(const osg::Drawable&) const - { - return mBoundingBox; - } - - private: - osg::BoundingBox mBoundingBox; - }; - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) @@ -1107,108 +1012,49 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr geometry; + osg::ref_ptr drawable; for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) continue; if(ctrl->recType == Nif::RC_NiGeomMorpherController) { - geometry = handleMorphGeometry(static_cast(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); + drawable = handleMorphGeometry(static_cast(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); osg::ref_ptr morphctrl = new GeomMorpherController( static_cast(ctrl.getPtr())->data.getPtr()); setupController(ctrl.getPtr(), morphctrl, animflags); - geometry->setUpdateCallback(morphctrl); + drawable->setUpdateCallback(morphctrl); break; } } - if (!geometry.get()) + if (!drawable.get()) { - geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); + osg::ref_ptr geom (new osg::Geometry); + drawable = geom; + triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags); } - geometry->setName(triShape->name); - - if (geometry->getDataVariance() == osg::Object::DYNAMIC) - { - // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch - // This is so we can set the DataVariance as STATIC, giving a huge performance boost - geometry->setDataVariance(osg::Object::STATIC); - osg::ref_ptr frameswitch = new FrameSwitch; + drawable->setName(triShape->name); - osg::ref_ptr geom2 = osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES); - frameswitch->addChild(geometry); - frameswitch->addChild(geom2); - - parentNode->addChild(frameswitch); - } - else - parentNode->addChild(geometry); + parentNode->addChild(drawable); } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { - osg::ref_ptr morphGeom = new osgAnimation::MorphGeometry; - morphGeom->setMethod(osgAnimation::MorphGeometry::RELATIVE); - // No normals available in the MorphData - morphGeom->setMorphNormals(false); - - morphGeom->setUpdateCallback(NULL); - morphGeom->setCullCallback(new UpdateMorphGeometry); - morphGeom->setUseVertexBufferObjects(true); + osg::ref_ptr morphGeom = new SceneUtil::MorphGeometry; - triShapeToGeometry(triShape, morphGeom, parentNode, composite, boundTextures, animflags); - - morphGeom->getOrCreateVertexBufferObject()->setUsage(GL_DYNAMIC_DRAW_ARB); + osg::ref_ptr sourceGeometry (new osg::Geometry); + triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags); + morphGeom->setSourceGeometry(sourceGeometry); const std::vector& morphs = morpher->data.getPtr()->mMorphs; if (morphs.empty()) return morphGeom; // Note we are not interested in morph 0, which just contains the original vertices for (unsigned int i = 1; i < morphs.size(); ++i) - { - osg::ref_ptr morphTarget = new osg::Geometry; - morphTarget->setVertexArray(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0])); - morphGeom->addMorphTarget(morphTarget, 0.f); - } - - // build the bounding box containing all possible morph combinations - - std::vector vertBounds(morphs[0].mVertices.size()); - - // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. - // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. - - // Start with zero offsets which will happen when no morphs are applied. - for (unsigned int i=0; igetBound(); - - // Now set up the callback so that we get properly enlarged bounds if/when the mesh starts animating - morphGeom->setComputeBoundingBoxCallback(new StaticBoundingBoxCallback(box)); + morphGeom->addMorphTarget(new osg::Vec3Array(morphs[i].mVertices.size(), &morphs[i].mVertices[0]), 0.f); return morphGeom; } diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 738c7a30d..08f36cfcf 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include @@ -49,46 +49,12 @@ namespace SceneUtil { if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable)) - { - osg::CopyOp copyop = *this; - copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_ARRAYS); - -#if OSG_VERSION_LESS_THAN(3,5,0) - /* - - Deep copy of primitives required to work around the following (bad?) code in osg::Geometry copy constructor: - - if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS)) - { - if (_useVertexBufferObjects) - { - // copying of arrays doesn't set up buffer objects so we'll need to force - // Geometry to assign these, we'll do this by switching off VBO's then renabling them. - setUseVertexBufferObjects(false); - setUseVertexBufferObjects(true); - } - } - - In case of DEEP_COPY_PRIMITIVES=Off, DEEP_COPY_ARRAYS=On, the above code makes a modification to the original const Geometry& we copied from, - causing problems if we relied on the original Geometry to remain static such as when it was added to an osgUtil::IncrementalCompileOperation. - Fixed in OSG 3.5 ( http://forum.openscenegraph.org/viewtopic.php?t=15217 ). - - */ - - copyop.setCopyFlags(copyop.getCopyFlags()|osg::CopyOp::DEEP_COPY_PRIMITIVES); -#endif - - osg::Drawable* cloned = osg::clone(drawable, copyop); - return cloned; - } - if (dynamic_cast(drawable)) + if (dynamic_cast(drawable) || dynamic_cast(drawable)) { return osg::clone(drawable, *this); } - return osg::CopyOp::operator()(drawable); } diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp new file mode 100644 index 000000000..5d55e75ec --- /dev/null +++ b/components/sceneutil/morphgeometry.cpp @@ -0,0 +1,187 @@ +#include "morphgeometry.hpp" + +#include + +namespace SceneUtil +{ + +MorphGeometry::MorphGeometry() + : mLastFrameNumber(0) + , mDirty(true) + , mMorphedBoundingBox(false) +{ + +} + +MorphGeometry::MorphGeometry(const MorphGeometry ©, const osg::CopyOp ©op) + : osg::Drawable(copy, copyop) + , mMorphTargets(copy.mMorphTargets) + , mLastFrameNumber(0) + , mDirty(true) + , mMorphedBoundingBox(false) +{ + setSourceGeometry(copy.getSourceGeometry()); +} + +void MorphGeometry::setSourceGeometry(osg::ref_ptr sourceGeom) +{ + mSourceGeometry = sourceGeom; + + for (unsigned int i=0; i<2; ++i) + { + mGeometry[i] = new osg::Geometry(*mSourceGeometry, osg::CopyOp::SHALLOW_COPY); + + osg::Geometry& from = *mSourceGeometry; + osg::Geometry& to = *mGeometry[i]; + to.setSupportsDisplayList(false); + to.setUseVertexBufferObjects(true); + to.setCullingActive(false); // make sure to disable culling since that's handled by this class + + // vertices are modified every frame, so we need to deep copy them. + // assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO. + osg::ref_ptr vbo (new osg::VertexBufferObject); + vbo->setUsage(GL_DYNAMIC_DRAW_ARB); + + osg::ref_ptr vertexArray = osg::clone(from.getVertexArray(), osg::CopyOp::DEEP_COPY_ALL); + if (vertexArray) + { + vertexArray->setVertexBufferObject(vbo); + to.setVertexArray(vertexArray); + } + } +} + +void MorphGeometry::addMorphTarget(osg::Vec3Array *offsets, float weight) +{ + mMorphTargets.push_back(MorphTarget(offsets, weight)); + mMorphedBoundingBox = false; + dirty(); +} + +void MorphGeometry::dirty() +{ + mDirty = true; + if (!mMorphedBoundingBox) + { + _boundingBoxComputed = false; + dirtyBound(); + } +} + +osg::ref_ptr MorphGeometry::getSourceGeometry() const +{ + return mSourceGeometry; +} + +void MorphGeometry::accept(osg::NodeVisitor &nv) +{ + if (!nv.validNodeMask(*this)) + return; + + nv.pushOntoNodePath(this); + + if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + cull(&nv); + else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) + nv.apply(*getGeometry(mLastFrameNumber)); + else + nv.apply(*this); + + nv.popFromNodePath(); +} + +osg::BoundingBox MorphGeometry::computeBoundingBox() const +{ + bool anyMorphTarget = false; + for (unsigned int i=0; i 0) + { + anyMorphTarget = true; + break; + } + + // before the MorphGeometry has started animating, we will use a regular bounding box (this is required + // for correct object placements, which uses the bounding box) + if (!mMorphedBoundingBox && !anyMorphTarget) + { + return mSourceGeometry->getBoundingBox(); + } + // once it animates, use a bounding box that encompasses all possible animations so as to avoid recalculating + else + { + mMorphedBoundingBox = true; + + osg::Vec3Array& sourceVerts = *static_cast(mSourceGeometry->getVertexArray()); + std::vector vertBounds(sourceVerts.size()); + + // Since we don't know what combinations of morphs are being applied we need to keep track of a bounding box for each vertex. + // The minimum/maximum of the box is the minimum/maximum offset the vertex can have from its starting position. + + // Start with zero offsets which will happen when no morphs are applied. + for (unsigned int i=0; igetTraversalNumber() || !mDirty) + { + nv->apply(*getGeometry(mLastFrameNumber)); + return; + } + + mDirty = false; + mLastFrameNumber = nv->getTraversalNumber(); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + + const osg::Vec3Array* positionSrc = static_cast(mSourceGeometry->getVertexArray()); + osg::Vec3Array* positionDst = static_cast(geom.getVertexArray()); + assert(positionSrc->size() == positionDst->size()); + for (unsigned int vertex=0; vertexsize(); ++vertex) + (*positionDst)[vertex] = (*positionSrc)[vertex]; + + for (unsigned int i=0; isize(); ++vertex) + (*positionDst)[vertex] += (*offsets)[vertex] * weight; + } + + positionDst->dirty(); + + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); +} + +osg::Geometry* MorphGeometry::getGeometry(unsigned int frame) const +{ + return mGeometry[frame%2]; +} + + +} diff --git a/components/sceneutil/morphgeometry.hpp b/components/sceneutil/morphgeometry.hpp new file mode 100644 index 000000000..1afef1895 --- /dev/null +++ b/components/sceneutil/morphgeometry.hpp @@ -0,0 +1,81 @@ +#ifndef OPENMW_COMPONENTS_MORPHGEOMETRY_H +#define OPENMW_COMPONENTS_MORPHGEOMETRY_H + +#include + +namespace SceneUtil +{ + + /// @brief Vertex morphing implementation. + /// @note The internal Geometry used for rendering is double buffered, this allows updates to be done in a thread safe way while + /// not compromising rendering performance. This is crucial when using osg's default threading model of DrawThreadPerContext. + class MorphGeometry : public osg::Drawable + { + public: + MorphGeometry(); + MorphGeometry(const MorphGeometry& copy, const osg::CopyOp& copyop); + + META_Object(SceneUtil, MorphGeometry) + + /// Initialize this geometry from the source geometry. + /// @note The source geometry will not be modified. + void setSourceGeometry(osg::ref_ptr sourceGeom); + + class MorphTarget + { + protected: + osg::ref_ptr mOffsets; + float mWeight; + public: + MorphTarget(osg::Vec3Array* offsets, float w = 1.0) : mOffsets(offsets), mWeight(w) {} + void setWeight(float weight) { mWeight = weight; } + float getWeight() const { return mWeight; } + osg::Vec3Array* getOffsets() { return mOffsets.get(); } + const osg::Vec3Array* getOffsets() const { return mOffsets.get(); } + void setOffsets(osg::Vec3Array* offsets) { mOffsets = offsets; } + }; + + typedef std::vector MorphTargetList; + + virtual void addMorphTarget( osg::Vec3Array* offsets, float weight = 1.0 ); + + /** Set the MorphGeometry dirty.*/ + void dirty(); + + /** Get the list of MorphTargets.*/ + const MorphTargetList& getMorphTargetList() const { return mMorphTargets; } + + /** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */ + MorphTargetList& getMorphTargetList() { return mMorphTargets; } + + /** Return the \c MorphTarget at position \c i.*/ + inline const MorphTarget& getMorphTarget( unsigned int i ) const { return mMorphTargets[i]; } + + /** Return the \c MorphTarget at position \c i.*/ + inline MorphTarget& getMorphTarget( unsigned int i ) { return mMorphTargets[i]; } + + osg::ref_ptr getSourceGeometry() const; + + virtual void accept(osg::NodeVisitor &nv); + + virtual osg::BoundingBox computeBoundingBox() const; + + private: + void cull(osg::NodeVisitor* nv); + + MorphTargetList mMorphTargets; + + osg::ref_ptr mSourceGeometry; + + osg::ref_ptr mGeometry[2]; + osg::Geometry* getGeometry(unsigned int frame) const; + + unsigned int mLastFrameNumber; + bool mDirty; // Have any morph targets changed? + + mutable bool mMorphedBoundingBox; + }; + +} + +#endif diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 177d700b2..ab0321532 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace SceneUtil { @@ -37,20 +38,20 @@ public: } }; -class FrameSwitchSerializer : public osgDB::ObjectWrapper +class RigGeometrySerializer : public osgDB::ObjectWrapper { public: - FrameSwitchSerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "NifOsg::FrameSwitch", "osg::Object osg::Node osg::Group NifOsg::FrameSwitch") + RigGeometrySerializer() + : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") { } }; -class RigGeometrySerializer : public osgDB::ObjectWrapper +class MorphGeometrySerializer : public osgDB::ObjectWrapper { public: - RigGeometrySerializer() - : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::RigGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometry") + MorphGeometrySerializer() + : osgDB::ObjectWrapper(createInstanceFunc, "SceneUtil::MorphGeometry", "osg::Object osg::Node osg::Drawable SceneUtil::MorphGeometry") { } }; @@ -95,8 +96,8 @@ void registerSerializers() osgDB::ObjectWrapperManager* mgr = osgDB::Registry::instance()->getObjectWrapperManager(); mgr->addWrapper(new PositionAttitudeTransformSerializer); mgr->addWrapper(new SkeletonSerializer); - mgr->addWrapper(new FrameSwitchSerializer); mgr->addWrapper(new RigGeometrySerializer); + mgr->addWrapper(new MorphGeometrySerializer); mgr->addWrapper(new LightManagerSerializer); mgr->addWrapper(new CameraRelativeTransformSerializer); diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 2c0b9f0e3..9b3876d6c 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "shadermanager.hpp" @@ -376,12 +377,18 @@ namespace Shader const ShaderRequirements& reqs = mRequirements.back(); createProgram(reqs); - if (SceneUtil::RigGeometry* rig = dynamic_cast(&drawable)) + if (auto rig = dynamic_cast(&drawable)) { osg::ref_ptr sourceGeometry = rig->getSourceGeometry(); if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) rig->setSourceGeometry(sourceGeometry); } + else if (auto morph = dynamic_cast(&drawable)) + { + osg::ref_ptr sourceGeometry = morph->getSourceGeometry(); + if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs)) + morph->setSourceGeometry(sourceGeometry); + } } if (needPop) From 4bef8260abcfe137bd206262e980b0249d041143 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 23:02:19 +0200 Subject: [PATCH 114/521] Add const qualifiers --- components/sceneutil/morphgeometry.cpp | 2 +- components/sceneutil/riggeometry.cpp | 6 +++--- components/sceneutil/riggeometry.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 5d55e75ec..4c53b68a5 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -31,7 +31,7 @@ void MorphGeometry::setSourceGeometry(osg::ref_ptr sourceGeom) { mGeometry[i] = new osg::Geometry(*mSourceGeometry, osg::CopyOp::SHALLOW_COPY); - osg::Geometry& from = *mSourceGeometry; + const osg::Geometry& from = *mSourceGeometry; osg::Geometry& to = *mGeometry[i]; to.setSupportsDisplayList(false); to.setUseVertexBufferObjects(true); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index ec01f62d0..f3eea1bbd 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -35,7 +35,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) for (unsigned int i=0; i<2; ++i) { - osg::Geometry& from = *sourceGeometry; + const osg::Geometry& from = *sourceGeometry; mGeometry[i] = new osg::Geometry(from, osg::CopyOp::SHALLOW_COPY); osg::Geometry& to = *mGeometry[i]; to.setSupportsDisplayList(false); @@ -54,7 +54,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) to.setVertexArray(vertexArray); } - if (osg::Array* normals = from.getNormalArray()) + if (const osg::Array* normals = from.getNormalArray()) { osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); if (normalArray) @@ -64,7 +64,7 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) } } - if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) + if (const osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) { mSourceTangents = tangents; osg::ref_ptr tangentArray = osg::clone(tangents, osg::CopyOp::DEEP_COPY_ALL); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 097e7ea69..638f53679 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -57,7 +57,7 @@ namespace SceneUtil osg::Geometry* getGeometry(unsigned int frame) const; osg::ref_ptr mSourceGeometry; - osg::ref_ptr mSourceTangents; + osg::ref_ptr mSourceTangents; Skeleton* mSkeleton; osg::ref_ptr mGeomToSkelMatrix; From 5e790b567e460de29bea43ec5410822db58a6e57 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 1 Sep 2017 22:12:40 +0000 Subject: [PATCH 115/521] Fix node path issue Needs to be set so that the 'cullingActive' flag of the node path's end can be checked --- components/sceneutil/morphgeometry.cpp | 5 ++++- components/sceneutil/riggeometry.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 4c53b68a5..98e5a92bc 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -147,7 +147,10 @@ void MorphGeometry::cull(osg::NodeVisitor *nv) { if (mLastFrameNumber == nv->getTraversalNumber() || !mDirty) { - nv->apply(*getGeometry(mLastFrameNumber)); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); return; } diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index f3eea1bbd..f52bca80c 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -174,7 +174,10 @@ void RigGeometry::cull(osg::NodeVisitor* nv) if ((!mSkeleton->getActive() && mLastFrameNumber != 0) || mLastFrameNumber == nv->getTraversalNumber()) { - nv->apply(*getGeometry(mLastFrameNumber)); + osg::Geometry& geom = *getGeometry(mLastFrameNumber); + nv->pushOntoNodePath(&geom); + nv->apply(geom); + nv->popFromNodePath(); return; } mLastFrameNumber = nv->getTraversalNumber(); From e0ffc94f3e7fc9922bda949b7d0184071e5ef91b Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 2 Sep 2017 18:07:12 -0500 Subject: [PATCH 116/521] Fix OpenMW-CS internal name --- apps/opencs/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0a146dc06..fc8930b71 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -199,7 +199,7 @@ if(APPLE) RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" OUTPUT_NAME ${OPENCS_BUNDLE_NAME} MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" - MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" + MACOSX_BUNDLE_BUNDLE_NAME "OpenMW-CS" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_SHORT_VERSION_STRING ${OPENMW_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${OPENMW_VERSION} From 10fff499a2103b2c0ca6e15172155e2b61a245b5 Mon Sep 17 00:00:00 2001 From: Thunderforge Date: Sat, 2 Sep 2017 19:02:55 -0500 Subject: [PATCH 117/521] Adding that Reflect Actors can be toggled in the video panel --- docs/source/reference/modding/settings/water.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/reference/modding/settings/water.rst b/docs/source/reference/modding/settings/water.rst index 2344222e5..a1c6c2068 100644 --- a/docs/source/reference/modding/settings/water.rst +++ b/docs/source/reference/modding/settings/water.rst @@ -56,7 +56,7 @@ Enabling this feature results in better visuals, and a marginally lower frame ra 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. +This setting can be toggled with the 'Refraction' button in the Water tab of the Video panel of the Options menu. reflect actors -------------- @@ -68,6 +68,8 @@ reflect actors 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. +This setting can be toggled with the 'Reflect actors' button in the Water tab of the Video panel of the Options menu. + small feature culling pixel size -------------------------------- From 2e58024f1c8adc44d02d42a4c2d20a31073d2ce4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 3 Sep 2017 16:02:40 +0200 Subject: [PATCH 118/521] Fix intersections with Rig/MorphGeometry, was caused by an issue in the LineSegmentIntersector not respecting the cullingActive flag of a drawable. --- components/sceneutil/morphgeometry.cpp | 7 +++++-- components/sceneutil/morphgeometry.hpp | 2 ++ components/sceneutil/riggeometry.cpp | 7 +++++-- components/sceneutil/riggeometry.hpp | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 98e5a92bc..2ffbace3b 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -82,14 +82,17 @@ void MorphGeometry::accept(osg::NodeVisitor &nv) if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR) cull(&nv); - else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) - nv.apply(*getGeometry(mLastFrameNumber)); else nv.apply(*this); nv.popFromNodePath(); } +void MorphGeometry::accept(osg::PrimitiveFunctor& func) const +{ + getGeometry(mLastFrameNumber)->accept(func); +} + osg::BoundingBox MorphGeometry::computeBoundingBox() const { bool anyMorphTarget = false; diff --git a/components/sceneutil/morphgeometry.hpp b/components/sceneutil/morphgeometry.hpp index 1afef1895..122c1456c 100644 --- a/components/sceneutil/morphgeometry.hpp +++ b/components/sceneutil/morphgeometry.hpp @@ -57,6 +57,8 @@ namespace SceneUtil osg::ref_ptr getSourceGeometry() const; virtual void accept(osg::NodeVisitor &nv); + virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } + virtual void accept(osg::PrimitiveFunctor&) const; virtual osg::BoundingBox computeBoundingBox() const; diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index f52bca80c..7f148cf5e 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -318,14 +318,17 @@ void RigGeometry::accept(osg::NodeVisitor &nv) cull(&nv); else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) updateBounds(&nv); - else if (nv.getVisitorType() == osg::NodeVisitor::INTERSECTION_VISITOR) - nv.apply(*getGeometry(mLastFrameNumber)); else nv.apply(*this); nv.popFromNodePath(); } +void RigGeometry::accept(osg::PrimitiveFunctor& func) const +{ + getGeometry(mLastFrameNumber)->accept(func); +} + osg::Geometry* RigGeometry::getGeometry(unsigned int frame) const { return mGeometry[frame%2].get(); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 638f53679..64f4bf312 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -48,6 +48,8 @@ namespace SceneUtil osg::ref_ptr getSourceGeometry(); virtual void accept(osg::NodeVisitor &nv); + virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } + virtual void accept(osg::PrimitiveFunctor&) const; private: void cull(osg::NodeVisitor* nv); From 30ba1d4c2599822730c5e6a204d383517c3206ed Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 3 Sep 2017 16:41:54 -0400 Subject: [PATCH 119/521] Move touch command to creator, to allow customization and not break abstraction --- apps/opencs/view/world/creator.hpp | 3 +++ apps/opencs/view/world/genericcreator.cpp | 17 +++++++++++++++++ apps/opencs/view/world/genericcreator.hpp | 2 ++ apps/opencs/view/world/table.cpp | 22 +++++++--------------- apps/opencs/view/world/table.hpp | 2 ++ apps/opencs/view/world/tablebottombox.cpp | 11 ++++++++--- apps/opencs/view/world/tablebottombox.hpp | 1 + apps/opencs/view/world/tablesubview.cpp | 3 +++ 8 files changed, 43 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 320bbf6ae..0020fd3c8 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -31,6 +31,9 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) = 0; + /// Touches a record, if the creator supports it. + virtual void touch(const std::vector& ids) = 0; + virtual void setEditLock (bool locked) = 0; virtual void toggleWidgets(bool active = true) = 0; diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bf4c4967f..bde523a09 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -254,6 +254,23 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId, mClonedType = type; } +void CSVWorld::GenericCreator::touch(const std::vector& ids) +{ + // Combine multiple touch commands into one "macro" command + std::unique_ptr macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& table = dynamic_cast(*mData.getTableModel(mListId)); + for (const CSMWorld::UniversalId& uid : ids) + { + // This is not leaked, touchCmd is a child of macro and managed by Qt + CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId(), macro.get()); + } + + // Execute + mUndoStack.push(macro.release()); +} + void CSVWorld::GenericCreator::toggleWidgets(bool active) { } diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 60d487bc1..d708c1047 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -103,6 +103,8 @@ namespace CSVWorld virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); + virtual void touch(const std::vector& ids); + virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 580d27a24..3cccaaa22 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -458,23 +458,15 @@ void CSVWorld::Table::touchRecord() { if (!mEditLock && mModel->getFeatures() & CSMWorld::IdTableBase::Feature_AllowTouch) { - if (CSMWorld::IdTable* table = dynamic_cast(mModel)) - { - QUndoCommand* touchRecords = new QUndoCommand(); - touchRecords->setText("Touch records"); - - QModelIndexList selectedRows = selectionModel()->selectedRows(); - for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) - { - QModelIndex index = mProxyModel->mapToSource(mProxyModel->index(it->row(),0)); - std::string id = table->getId(index.row()); - - // command is a child of touchRecords - QUndoCommand* command = new CSMWorld::TouchCommand(*table, id, touchRecords); - } + std::vector touchIds; - mDocument.getUndoStack().push(touchRecords); + QModelIndexList selectedRows = selectionModel()->selectedRows(); + for (auto it = selectedRows.begin(); it != selectedRows.end(); ++it) + { + touchIds.push_back(getUniversalId(it->row())); } + + emit touchRequest(touchIds); } } diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index d6fa17ef9..02f9023e7 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -116,6 +116,8 @@ namespace CSVWorld void cloneRequest(const CSMWorld::UniversalId&); + void touchRequest(const std::vector& ids); + void closeRequest(); void extendedDeleteConfigRequest(const std::vector &selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.cpp b/apps/opencs/view/world/tablebottombox.cpp index 5a25bbc53..cfde5c694 100644 --- a/apps/opencs/view/world/tablebottombox.cpp +++ b/apps/opencs/view/world/tablebottombox.cpp @@ -72,9 +72,9 @@ void CSVWorld::TableBottomBox::extendedConfigRequest(CSVWorld::ExtendedCommandCo mExtendedConfigurator->setFocus(); } -CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, - CSMDoc::Document& document, - const CSMWorld::UniversalId& id, +CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory, + CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) : QWidget (parent), mShowStatusBar (false), mEditMode(EditMode_None), mHasPosition(false), mRow(0), mColumn(0) { @@ -249,6 +249,11 @@ void CSVWorld::TableBottomBox::cloneRequest(const std::string& id, mCreator->focus(); } +void CSVWorld::TableBottomBox::touchRequest(const std::vector& ids) +{ + mCreator->touch(ids); +} + void CSVWorld::TableBottomBox::extendedDeleteConfigRequest(const std::vector &selectedIds) { extendedConfigRequest(ExtendedCommandConfigurator::Mode_Delete, selectedIds); diff --git a/apps/opencs/view/world/tablebottombox.hpp b/apps/opencs/view/world/tablebottombox.hpp index 781cccc9e..5402c466e 100644 --- a/apps/opencs/view/world/tablebottombox.hpp +++ b/apps/opencs/view/world/tablebottombox.hpp @@ -102,6 +102,7 @@ namespace CSVWorld void createRequest(); void cloneRequest(const std::string& id, const CSMWorld::UniversalId::Type type); + void touchRequest(const std::vector&); void extendedDeleteConfigRequest(const std::vector &selectedIds); void extendedRevertConfigRequest(const std::vector &selectedIds); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 6664a3771..12e29995d 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -69,6 +69,9 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)), mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type))); + connect (mTable, SIGNAL(touchRequest(const std::vector&)), + mBottom, SLOT(touchRequest(const std::vector&))); + connect (mTable, SIGNAL(extendedDeleteConfigRequest(const std::vector &)), mBottom, SLOT(extendedDeleteConfigRequest(const std::vector &))); connect (mTable, SIGNAL(extendedRevertConfigRequest(const std::vector &)), From 7cc95a11a47721cd9c3f70d6acf9b0d595f576ba Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 3 Sep 2017 20:00:19 -0400 Subject: [PATCH 120/521] Add more land table columns --- apps/opencs/model/world/columnimp.cpp | 234 ++++++++++++++++++++++++-- apps/opencs/model/world/columnimp.hpp | 45 +++++ apps/opencs/model/world/columns.hpp | 5 + apps/opencs/model/world/data.cpp | 5 + components/esm/loadland.hpp | 4 +- 5 files changed, 274 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index dc3d39edb..65d2fecd2 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,28 +1,226 @@ #include "columnimp.hpp" -CSMWorld::BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) - : mMeshType(meshType) -{} - -QVariant CSMWorld::BodyPartRaceColumn::get(const Record &record) const +namespace CSMWorld { - if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + /* LandMapLodColumn */ + LandMapLodColumn::LandMapLodColumn() + : Column(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) { - return QString::fromUtf8(record.get().mRace.c_str()); } - return QVariant(QVariant::UserType); -} -void CSMWorld::BodyPartRaceColumn::set(Record &record, const QVariant &data) -{ - ESM::BodyPart record2 = record.get(); + QVariant LandMapLodColumn::get(const Record& record) const + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&record.get().mWnam[0]); + return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + } + + void LandMapLodColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast(array.data()); - record2.mRace = data.toString().toUtf8().constData(); + assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); - record.setModified(record2); -} + for (int i = 0; i < array.count(); ++i) + { + copy.mWnam[i] = rawData[i]; + } -bool CSMWorld::BodyPartRaceColumn::isEditable() const -{ - return true; + record.setModified(copy); + } + + bool LandMapLodColumn::isEditable() const + { + return true; + } + + /* LandNormalsColumn */ + LandNormalsColumn::LandNormalsColumn() + : Column(Columns::ColumnId_LandNormalsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandNormalsColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is signed + const char* rawData = reinterpret_cast(&landData->mNormals[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandNormalsColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const signed char* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * 3); + + for (int i = 0; i < array.count(); ++i) + { + landData->mNormals[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandNormalsColumn::isEditable() const + { + return true; + } + + /* LandHeightsColumn */ + LandHeightsColumn::LandHeightsColumn() + : Column(Columns::ColumnId_LandHeightsIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandHeightsColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is float + const char* rawData = reinterpret_cast(&landData->mHeights[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + } + + void LandHeightsColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const float* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + + for (int i = 0; i < array.count(); ++i) + { + landData->mHeights[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandHeightsColumn::isEditable() const + { + return true; + } + + /* LandColoursColumn */ + LandColoursColumn::LandColoursColumn() + : Column(Columns::ColumnId_LandColoursIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandColoursColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is unsigned char + const char* rawData = reinterpret_cast(&landData->mColours[0]); + return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + } + + void LandColoursColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const unsigned char* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_VERTS * 3); + + for (int i = 0; i < array.count(); ++i) + { + landData->mColours[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandColoursColumn::isEditable() const + { + return true; + } + + /* LandTexturesColumn */ + LandTexturesColumn::LandTexturesColumn() + : Column(Columns::ColumnId_LandTexturesIndex, ColumnBase::Display_String, 0) + { + } + + QVariant LandTexturesColumn::get(const Record& record) const + { + const Land::LandData* landData = record.get().getLandData(); + assert(landData); + + // Note: original data is uint16_t + const char* rawData = reinterpret_cast(&landData->mTextures[0]); + return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + } + + void LandTexturesColumn::set(Record& record, const QVariant& data) + { + Land copy = record.get(); + Land::LandData* landData = copy.getLandData(); + assert (landData); + + QByteArray array = data.toByteArray(); + const uint16_t* rawData = reinterpret_cast(array.data()); + + assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + + for (int i = 0; i < array.count(); ++i) + { + landData->mTextures[i] = rawData[i]; + } + + record.setModified(copy); + } + + bool LandTexturesColumn::isEditable() const + { + return true; + } + + /* BodyPartRaceColumn */ + BodyPartRaceColumn::BodyPartRaceColumn(const MeshTypeColumn *meshType) + : mMeshType(meshType) + {} + + QVariant BodyPartRaceColumn::get(const Record &record) const + { + if (mMeshType != NULL && mMeshType->get(record) == ESM::BodyPart::MT_Skin) + { + return QString::fromUtf8(record.get().mRace.c_str()); + } + return QVariant(QVariant::UserType); + } + + void BodyPartRaceColumn::set(Record &record, const QVariant &data) + { + ESM::BodyPart record2 = record.get(); + + record2.mRace = data.toString().toUtf8().constData(); + + record.setModified(record2); + } + + bool BodyPartRaceColumn::isEditable() const + { + return true; + } } diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 92e899a45..f58a35bc4 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2501,6 +2501,51 @@ namespace CSMWorld return record.get().mPluginIndex; } + struct LandMapLodColumn : public Column + { + LandMapLodColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandNormalsColumn : public Column + { + LandNormalsColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandHeightsColumn : public Column + { + LandHeightsColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandColoursColumn : public Column + { + LandColoursColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + + struct LandTexturesColumn : public Column + { + LandTexturesColumn(); + + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; + }; + struct BodyPartRaceColumn : public RaceColumn { const MeshTypeColumn *mMeshType; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index c6e2a2a41..432597105 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -332,6 +332,11 @@ namespace CSMWorld ColumnId_TextureHandle = 298, ColumnId_PluginIndex = 299, ColumnId_TextureIndex = 300, + ColumnId_LandMapLodIndex = 301, + ColumnId_LandNormalsIndex = 302, + ColumnId_LandHeightsIndex = 303, + ColumnId_LandColoursIndex = 304, + ColumnId_LandTexturesIndex = 305, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 27a914aeb..3284d9b05 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -416,6 +416,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new RecordStateColumn); mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); mLand.addColumn (new PluginIndexColumn); + mLand.addColumn (new LandMapLodColumn); + mLand.addColumn (new LandNormalsColumn); + mLand.addColumn (new LandHeightsColumn); + mLand.addColumn (new LandColoursColumn); + mLand.addColumn (new LandTexturesColumn); mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 9f33c37da..a7b97a465 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -64,6 +64,8 @@ struct Land //total number of textures per land static const int LAND_NUM_TEXTURES = LAND_TEXTURE_SIZE * LAND_TEXTURE_SIZE; + static const int LAND_GLOBAL_MAP_LOD_SIZE = 81; + #pragma pack(push,1) struct VHGT { @@ -109,7 +111,7 @@ struct Land }; // low-LOD heightmap (used for rendering the global map) - signed char mWnam[81]; + signed char mWnam[LAND_GLOBAL_MAP_LOD_SIZE]; void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; From 90c485104a8e13e9f1e876b40b7b1b539bf73c9f Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 01:06:58 -0400 Subject: [PATCH 121/521] Land creator --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/collection.hpp | 86 ++++++++++++++++++++++---- apps/opencs/model/world/land.cpp | 20 +++++- apps/opencs/model/world/land.hpp | 3 + apps/opencs/view/world/landcreator.cpp | 79 +++++++++++++++++++++++ apps/opencs/view/world/landcreator.hpp | 42 +++++++++++++ apps/opencs/view/world/subviews.cpp | 5 +- 7 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/view/world/landcreator.cpp create mode 100644 apps/opencs/view/world/landcreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4207258db..36ff8cf67 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,7 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator - bodypartcreator landtexturecreator + bodypartcreator landtexturecreator landcreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index f69d06d78..fccbebd43 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -15,6 +15,7 @@ #include "columnbase.hpp" #include "collectionbase.hpp" +#include "land.hpp" #include "landtexture.hpp" namespace CSMWorld @@ -39,6 +40,18 @@ namespace CSMWorld return record.mId; } + template<> + inline void IdAccessor::setId (Land& record, const std::string& id) const + { + int x=0, y=0; + + Land::parseUniqueRecordId(id, x, y); + record.mX = x; + record.mY = y; + // TODO check for uses of mId and remove them + record.mId = id; + } + template<> inline void IdAccessor::setId (LandTexture& record, const std::string& id) const { @@ -50,6 +63,12 @@ namespace CSMWorld record.mIndex = index; } + template<> + inline const std::string IdAccessor::getId (const Land& record) const + { + return Land::createUniqueRecordId(record.mX, record.mY); + } + template<> inline const std::string IdAccessor::getId (const LandTexture& record) const { @@ -86,6 +105,13 @@ namespace CSMWorld /// /// \return Success? + int cloneRecordImp (const std::string& origin, const std::string& dest, + UniversalId::Type type); + ///< Returns the index of the clone. + + int touchRecordImp (const std::string& id); + ///< Returns the index of the record on success, -1 on failure. + public: Collection(); @@ -227,20 +253,22 @@ namespace CSMWorld } template - void Collection::cloneRecord(const std::string& origin, - const std::string& destination, - const UniversalId::Type type) + int Collection::cloneRecordImp(const std::string& origin, + const std::string& destination, UniversalId::Type type) { - Record copy; - copy.mModified = getRecord(origin).get(); - copy.mState = RecordBase::State_ModifiedOnly; - IdAccessorT().setId(copy.get(), destination); + Record copy; + copy.mModified = getRecord(origin).get(); + copy.mState = RecordBase::State_ModifiedOnly; + IdAccessorT().setId(copy.get(), destination); - insertRecord(copy, getAppendIndex(destination, type)); + int index = getAppendIndex(destination, type); + insertRecord(copy, getAppendIndex(destination, type)); + + return index; } template - bool Collection::touchRecord(const std::string& id) + int Collection::touchRecordImp(const std::string& id) { int index = getIndex(id); Record& record = mRecords.at(index); @@ -249,13 +277,47 @@ namespace CSMWorld throw std::runtime_error("attempt to touch deleted record"); } - if (!record.isModified() && !record.isDeleted() && !record.isErased()) + if (!record.isModified()) { record.setModified(record.get()); + return index; + } + + return -1; + } + + template + void Collection::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + cloneRecordImp(origin, destination, type); + } + + template<> + inline void Collection >::cloneRecord(const std::string& origin, + const std::string& destination, const UniversalId::Type type) + { + int index = cloneRecordImp(origin, destination, type); + mRecords.at(index).get().mPlugin = 0; + } + + template + bool Collection::touchRecord(const std::string& id) + { + return touchRecordImp(id) != -1; + } + + template<> + inline bool Collection >::touchRecord(const std::string& id) + { + int index = touchRecordImp(id); + if (index >= 0) + { + mRecords.at(index).get().mPlugin = 0; return true; } - else - return false; + + return false; } template diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 80f86c746..22fc96599 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -8,8 +8,24 @@ namespace CSMWorld { ESM::Land::load(esm, isDeleted); + mId = createUniqueRecordId(mX, mY); + } + + std::string Land::createUniqueRecordId(int x, int y) + { std::ostringstream stream; - stream << "#" << mX << " " << mY; - mId = stream.str(); + stream << "#" << x << " " << y; + return stream.str(); + } + + void Land::parseUniqueRecordId(const std::string& id, int& x, int& y) + { + size_t mid = id.find(' '); + + if (mid == std::string::npos || id[0] != '#') + throw std::runtime_error("Invalid Land ID"); + + x = std::stoi(id.substr(1, mid - 1)); + y = std::stoi(id.substr(mid + 1)); } } diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index e5f25c1d3..cc7e914af 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -16,6 +16,9 @@ namespace CSMWorld /// Loads the metadata and ID void load (ESM::ESMReader &esm, bool &isDeleted); + + static std::string createUniqueRecordId(int x, int y); + static void parseUniqueRecordId(const std::string& id, int& x, int& y); }; } diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp new file mode 100644 index 000000000..34599b2c4 --- /dev/null +++ b/apps/opencs/view/world/landcreator.cpp @@ -0,0 +1,79 @@ +#include "landcreator.hpp" + +#include + +#include "../../model/world/land.hpp" + +namespace CSVWorld +{ + LandCreator::LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) + : GenericCreator(data, undoStack, id) + , mXLabel(nullptr) + , mYLabel(nullptr) + , mX(nullptr) + , mY(nullptr) + { + const int MaxInt = std::numeric_limits::max(); + const int MinInt = std::numeric_limits::min(); + + setManualEditing(false); + + mXLabel = new QLabel("X: "); + mX = new QSpinBox(); + mX->setMinimum(MinInt); + mX->setMaximum(MaxInt); + insertBeforeButtons(mXLabel, false); + insertBeforeButtons(mX, true); + + mYLabel = new QLabel("Y: "); + mY = new QSpinBox(); + mY->setMinimum(MinInt); + mY->setMaximum(MaxInt); + insertBeforeButtons(mYLabel, false); + insertBeforeButtons(mY, true); + + connect (mX, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int))); + connect (mY, SIGNAL(valueChanged(int)), this, SLOT(coordChanged(int))); + } + + void LandCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) + { + GenericCreator::cloneMode(originId, type); + + int x = 0, y = 0; + CSMWorld::Land::parseUniqueRecordId(originId, x, y); + + mX->setValue(x); + mY->setValue(y); + } + + void LandCreator::focus() + { + mX->setFocus(); + } + + void LandCreator::reset() + { + GenericCreator::reset(); + mX->setValue(0); + mY->setValue(0); + } + + std::string LandCreator::getErrors() const + { + if (getData().getLand().searchId(getId()) >= 0) + return "A land with that name already exists."; + + return ""; + } + + std::string LandCreator::getId() const + { + return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value()); + } + + void LandCreator::coordChanged(int value) + { + update(); + } +} diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp new file mode 100644 index 000000000..aea202dcd --- /dev/null +++ b/apps/opencs/view/world/landcreator.hpp @@ -0,0 +1,42 @@ +#ifndef CSV_WORLD_LANDCREATOR_H +#define CSV_WORLD_LANDCREATOR_H + +#include +#include + +#include "genericcreator.hpp" + +namespace CSVWorld +{ + class LandCreator : public GenericCreator + { + Q_OBJECT + + QLabel* mXLabel; + QLabel* mYLabel; + QSpinBox* mX; + QSpinBox* mY; + + public: + + LandCreator(CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + + void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + + void focus() override; + + void reset() override; + + std::string getErrors() const override; + + private slots: + + void coordChanged(int value); + + protected: + + std::string getId() const override; + }; +} + +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index a33802823..3e72f9a9e 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -18,6 +18,7 @@ #include "pathgridcreator.hpp" #include "previewsubview.hpp" #include "bodypartcreator.hpp" +#include "landcreator.hpp" #include "landtexturecreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) @@ -83,7 +84,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_Lands, - new CSVDoc::SubViewFactoryWithCreator >); + new CSVDoc::SubViewFactoryWithCreator >); manager.add (CSMWorld::UniversalId::Type_LandTextures, new CSVDoc::SubViewFactoryWithCreator >); @@ -189,7 +190,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator (false)); manager.add (CSMWorld::UniversalId::Type_Land, - new CSVDoc::SubViewFactoryWithCreator >(false)); + new CSVDoc::SubViewFactoryWithCreator >(false)); manager.add (CSMWorld::UniversalId::Type_LandTexture, new CSVDoc::SubViewFactoryWithCreator >(false)); From d3014cf39424972a3b86bc61bfe92cf54551d7b2 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 15:13:45 -0400 Subject: [PATCH 122/521] Temporary fix for adding new lands, cloned lands will still reference old data though --- apps/opencs/view/render/terrainstorage.cpp | 21 ++++----- components/esm/loadland.cpp | 52 +++++++++++++++++++++- components/esm/loadland.hpp | 6 ++- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/render/terrainstorage.cpp b/apps/opencs/view/render/terrainstorage.cpp index c63d41be3..51c9dd009 100644 --- a/apps/opencs/view/render/terrainstorage.cpp +++ b/apps/opencs/view/render/terrainstorage.cpp @@ -1,5 +1,8 @@ #include "terrainstorage.hpp" +#include "../../model/world/land.hpp" +#include "../../model/world/landtexture.hpp" + namespace CSVRender { @@ -11,12 +14,9 @@ namespace CSVRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - std::ostringstream stream; - stream << "#" << cellX << " " << cellY; - // The cell isn't guaranteed to have Land. This is because the terrain implementation // has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell - int index = mData.getLand().searchId(stream.str()); + int index = mData.getLand().searchId(CSMWorld::Land::createUniqueRecordId(cellX, cellY)); if (index == -1) return NULL; @@ -26,16 +26,11 @@ namespace CSVRender const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) { - int numRecords = mData.getLandTextures().getSize(); - - for (int i=0; imIndex == index && ltex->mPluginIndex == plugin) - return ltex; - } + int row = mData.getLandTextures().searchId(CSMWorld::LandTexture::createUniqueRecordId(plugin, index)); + if (row == -1) + return nullptr; - return NULL; + return &mData.getLandTextures().getRecord(row).get(); } void TerrainStorage::getBounds(float &minX, float &maxX, float &minY, float &maxY) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 72c3eb98d..7d48dd037 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -15,6 +15,7 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) + , mNoFile(false) , mDataTypes(0) , mLandData(NULL) { @@ -175,6 +176,47 @@ namespace ESM } + void Land::blank() + { + if (mLandData) + { + delete mLandData; + } + + mPlugin = 0; + + for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i) + mWnam[0] = 0; + + mLandData = new LandData; + mLandData->mHeightOffset = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + mLandData->mHeights[i] = 0; + mLandData->mMinHeight = 0; + mLandData->mMaxHeight = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + { + mLandData->mNormals[i*3+0] = 0; + mLandData->mNormals[i*3+1] = -1; + mLandData->mNormals[i*3+2] = 0; + } + for (int i = 0; i < LAND_NUM_TEXTURES; ++i) + mLandData->mTextures[i] = 0; + for (int i = 0; i < LAND_NUM_VERTS; ++i) + { + mLandData->mColours[i*3+0] = -1; + mLandData->mColours[i*3+1] = -1; + mLandData->mColours[i*3+2] = -1; + } + mLandData->mUnk1 = 0; + mLandData->mUnk2 = 0; + mLandData->mDataLoaded = Land::DATA_VNML | Land::DATA_VHGT | Land::DATA_WNAM | + Land::DATA_VCLR | Land::DATA_VTEX; + mDataTypes = mLandData->mDataLoaded; + + mNoFile = true; + } + void Land::loadData(int flags, LandData* target) const { // Create storage if nothing is loaded @@ -193,6 +235,13 @@ namespace ESM return; } + // Copy data to target if no file + if (mNoFile) + { + *target = *mLandData; + return; + } + ESM::ESMReader reader; reader.restoreContext(mContext); @@ -271,7 +320,7 @@ namespace ESM Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mContext (land.mContext), mDataTypes (land.mDataTypes), + mContext (land.mContext), mNoFile(land.mNoFile), mDataTypes (land.mDataTypes), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -288,6 +337,7 @@ namespace ESM std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); std::swap (mContext, land.mContext); + std::swap (mNoFile, land.mNoFile); std::swap (mDataTypes, land.mDataTypes); std::swap (mLandData, land.mLandData); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index a7b97a465..223b7975a 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -33,6 +33,10 @@ struct Land // location later when we are ready to load the full data set. ESM_Context mContext; + // In the editor, a new Land is not associated with a file, thus mContext should not be accessed + // when land data is being requested. Instead simply copy over the data. + bool mNoFile; + int mDataTypes; enum @@ -116,7 +120,7 @@ struct Land void load(ESMReader &esm, bool &isDeleted); void save(ESMWriter &esm, bool isDeleted = false) const; - void blank() {} + void blank(); /** * Actually loads data into target From 5c3e90da881948ff1f2fde5dd595fe7e2a0882e9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 15:14:42 -0400 Subject: [PATCH 123/521] Fix includes --- apps/opencs/model/world/land.cpp | 1 + apps/opencs/model/world/landtexture.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 22fc96599..2b12b55fe 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,6 +1,7 @@ #include "land.hpp" #include +#include namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 4b82f8d73..63ebbc11f 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,7 @@ #include "landtexture.hpp" #include +#include #include From dca31b7ffa4fc4c8f2b15fcf0491f9e9ef4cde23 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 4 Sep 2017 19:34:26 +0000 Subject: [PATCH 124/521] Remove redundant _boundingBoxComputed which no longer exists in osg master (Fixes #4075) --- components/sceneutil/morphgeometry.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/sceneutil/morphgeometry.cpp b/components/sceneutil/morphgeometry.cpp index 2ffbace3b..1b7e4ca93 100644 --- a/components/sceneutil/morphgeometry.cpp +++ b/components/sceneutil/morphgeometry.cpp @@ -62,10 +62,7 @@ void MorphGeometry::dirty() { mDirty = true; if (!mMorphedBoundingBox) - { - _boundingBoxComputed = false; dirtyBound(); - } } osg::ref_ptr MorphGeometry::getSourceGeometry() const From 97d0fd756a2dff3ac73bd308a1ad7f88c3e4e13d Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 4 Sep 2017 19:31:09 -0400 Subject: [PATCH 125/521] LTEX importing --- apps/opencs/model/world/commands.cpp | 85 +++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 25 +++++++- apps/opencs/model/world/idtable.cpp | 57 +++++++++++++++++ apps/opencs/model/world/idtable.hpp | 16 ++++- apps/opencs/model/world/land.cpp | 2 +- apps/opencs/model/world/landtexture.cpp | 2 +- apps/opencs/view/world/landcreator.cpp | 20 ++++++ apps/opencs/view/world/landcreator.hpp | 2 + 8 files changed, 204 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index c6a56f7b8..c98f52777 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -40,6 +41,90 @@ void CSMWorld::TouchCommand::undo() } } +CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, QUndoCommand* parent) + : QUndoCommand(parent) + , mLands(landTable) + , mLtexs(ltexTable) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mLands.getRecord(mId).clone()); +} + +void CSMWorld::TouchLandCommand::redo() +{ + int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); + int oldPlugin = mLands.data(mLands.getModelIndex(mId, pluginColumn)).toInt(); + + mChanged = mLands.touchRecord(mId); + if (mChanged) + { + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + QByteArray textureByteArray = mLands.data(mLands.getModelIndex(mId, textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast(textureByteArray.data()); + + // Need to make a copy so the old values can be looked up + QByteArray newTextureByteArray(textureByteArray.data(), textureByteArray.size()); + uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + + // Find all indices used + std::unordered_set texIndices; + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + // All indices are offset by 1 for a default texture + if (textureData[i] > 0) + texIndices.insert(textureData[i] - 1); + } + + std::vector oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } + + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); + mCreatedTextures = std::move(results.createdRecords); + for (const auto& it : results.recordMapping) + { + int plugin = 0, newIndex = 0, oldIndex = 0; + LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); + LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); + + if (newIndex != oldIndex) + { + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + { + // All indices are offset by 1 for a default texture + if (textureData[i] == oldIndex) + newTextureData[i] = newIndex + 1; + } + } + } + + mLands.setData(mLands.getModelIndex(mId, textureColumn), newTextureByteArray); + } +} + +void CSMWorld::TouchLandCommand::undo() +{ + if (mChanged) + { + mLands.setRecord(mId, *mOld); + mChanged = false; + + for (const std::string& id : mCreatedTextures) + { + int row = mLtexs.getModelIndex(id, 0).row(); + mLtexs.removeRows(row, 1); + } + mCreatedTextures.clear(); + } +} + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 4c9be7e8a..5f4259cb8 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -31,8 +31,8 @@ namespace CSMWorld TouchCommand(IdTable& model, const std::string& id, QUndoCommand* parent=nullptr); - virtual void redo(); - virtual void undo(); + void redo() override; + void undo() override; private: @@ -43,6 +43,27 @@ namespace CSMWorld bool mChanged; }; + class TouchLandCommand : public QUndoCommand + { + public: + + TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, + QUndoCommand* parent = nullptr); + + void redo() override; + void undo() override; + + private: + + IdTable& mLands; + IdTable& mLtexs; + std::string mId; + std::unique_ptr mOld; + std::vector mCreatedTextures; + + bool mChanged; + }; + class ModifyCommand : public QUndoCommand { QAbstractItemModel *mModel; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 94eab3fc3..5543fc13f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,11 +1,13 @@ #include "idtable.hpp" +#include #include #include #include "collectionbase.hpp" #include "columnbase.hpp" +#include "landtexture.hpp" CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) : IdTableBase (features), mIdCollection (idCollection) @@ -332,3 +334,58 @@ Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) cons return flags; } + +CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector& ids) +{ + ImportResults results; + + for (const std::string& id : ids) + { + int plugin, index; + + LandTexture::parseUniqueRecordId(id, plugin, index); + int oldRow = idCollection()->searchId(id); + + // If it does not exist or it is in the current plugin, it can be skipped. + if (oldRow <= 0 || plugin == 0) + { + results.recordMapping.push_back(std::make_pair(id, id)); + continue; + } + + // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. + // Iteration is deterministic to avoid duplicates. + do { + std::string newId = LandTexture::createUniqueRecordId(0, index); + int newRow = idCollection()->searchId(newId); + + if (newRow < 0) + { + // Id not taken, clone it + cloneRecord(id, newId, UniversalId::Type_LandTexture); + results.createdRecords.push_back(newId); + results.recordMapping.push_back(std::make_pair(id, newId)); + break; + } + + // Id is taken, check if same handle and texture. Note that mId is the handle. + const LandTexture& oldLtex = dynamic_cast&>(idCollection()->getRecord(oldRow)).get(); + const LandTexture& newLtex = dynamic_cast&>(idCollection()->getRecord(newRow)).get(); + if (oldLtex.mId == newLtex.mId && oldLtex.mTexture == newLtex.mTexture) + { + // It's a match + results.recordMapping.push_back(std::make_pair(id, newId)); + break; + } + + // Determine next index. Spread out the indices to reduce conflicts. + size_t MaxIndex = std::numeric_limits::max(); + size_t Prime = (1 << 19) - 1; // A mersenne prime + size_t K = 2154; + + index = ((K * index) % Prime) % MaxIndex; + } while (true); + } + + return results; +} diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 5e5f9da4a..ccc5ac404 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -100,11 +100,22 @@ namespace CSMWorld }; /// An IdTable customized to handle the more unique needs of LandTextureId's which behave - /// differently from other records. + /// differently from other records. The major difference is that base records cannot be + /// modified. class LandTextureIdTable : public IdTable { public: + struct ImportResults + { + using StringPair = std::pair; + + /// The newly added records + std::vector createdRecords; + /// The 1st string is the original id, the 2nd is the mapped id + std::vector recordMapping; + }; + LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; @@ -112,6 +123,9 @@ namespace CSMWorld bool setData(const QModelIndex& index, const QVariant& value, int role) override; Qt::ItemFlags flags (const QModelIndex & index) const override; + + /// Finds and maps/recreates the specified ids. + ImportResults importTextures(const std::vector& ids); }; } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 2b12b55fe..74833d7ef 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -1,7 +1,7 @@ #include "land.hpp" #include -#include +#include namespace CSMWorld { diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 63ebbc11f..32bab1e6d 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,7 +1,7 @@ #include "landtexture.hpp" #include -#include +#include #include diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 34599b2c4..08b8b3620 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,8 @@ #include +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" #include "../../model/world/land.hpp" namespace CSVWorld @@ -47,6 +49,24 @@ namespace CSVWorld mY->setValue(y); } + void LandCreator::touch(const std::vector& ids) + { + // Combine multiple touch commands into one "macro" command + std::unique_ptr macro(new QUndoCommand()); + macro->setText("Touch records"); + + CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + for (const CSMWorld::UniversalId& uid : ids) + { + // This is not leaked, touchCmd is a child of macro and managed by Qt + CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId(), macro.get()); + } + + // Execute + getUndoStack().push(macro.release()); + } + void LandCreator::focus() { mX->setFocus(); diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index aea202dcd..ef8cf60d5 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -23,6 +23,8 @@ namespace CSVWorld void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) override; + void touch(const std::vector& ids) override; + void focus() override; void reset() override; From 99e90ef808ec95d3c5e22e3e72d99ef10e58b0d9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Tue, 5 Sep 2017 19:29:07 -0400 Subject: [PATCH 126/521] Cleanup. Also modify ltex index generation. --- apps/opencs/model/prefs/state.cpp | 1 + apps/opencs/model/world/collection.hpp | 2 -- apps/opencs/model/world/columnimp.hpp | 9 ++++++- apps/opencs/model/world/columns.cpp | 5 ++++ apps/opencs/model/world/idtable.cpp | 8 +++--- apps/opencs/model/world/land.cpp | 2 -- apps/opencs/model/world/land.hpp | 2 -- apps/opencs/model/world/landtexture.cpp | 6 +++-- apps/opencs/view/world/landcreator.cpp | 3 +++ apps/opencs/view/world/landcreator.hpp | 6 ++--- apps/opencs/view/world/landtexturecreator.cpp | 27 ++++++++----------- apps/opencs/view/world/landtexturecreator.hpp | 6 ++--- 12 files changed, 42 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 0101a432b..1f84c5a87 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -278,6 +278,7 @@ void CSMPrefs::State::declare() declareShortcut ("table-edit", "Edit Record", QKeySequence()); declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A)); declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D)); + declareShortcut ("touch-record", "Touch Record", QKeySequence()); declareShortcut ("table-revert", "Revert Record", QKeySequence()); declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete)); declareShortcut ("table-moveup", "Move Record Up", QKeySequence()); diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index fccbebd43..80117d0c6 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -48,8 +48,6 @@ namespace CSMWorld Land::parseUniqueRecordId(id, x, y); record.mX = x; record.mY = y; - // TODO check for uses of mId and remove them - record.mId = id; } template<> diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index f58a35bc4..8e5908bd3 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -63,6 +63,13 @@ namespace CSMWorld } }; + template<> + inline QVariant StringIdColumn::get(const Record& record) const + { + const Land& land = record.get(); + return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + } + template<> inline QVariant StringIdColumn::get(const Record& record) const { @@ -2483,7 +2490,7 @@ namespace CSMWorld return -1; } - virtual bool isEditable() const override + bool isEditable() const override { return false; } diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 49935d40d..63ccb6017 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -333,6 +333,11 @@ namespace CSMWorld { ColumnId_TextureHandle, "Texture Handle" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, + { ColumnId_LandMapLodIndex, "Land map height LOD" }, + { ColumnId_LandNormalsIndex, "Land normals" }, + { ColumnId_LandHeightsIndex, "Land heights" }, + { ColumnId_LandColoursIndex, "Land colors" }, + { ColumnId_LandTexturesIndex, "Land textures" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 5543fc13f..127ffde2c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,6 @@ #include "idtable.hpp" +#include #include #include @@ -379,11 +380,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import } // Determine next index. Spread out the indices to reduce conflicts. - size_t MaxIndex = std::numeric_limits::max(); - size_t Prime = (1 << 19) - 1; // A mersenne prime - size_t K = 2154; + size_t MaxIndex = std::numeric_limits::max() - 1; + size_t Prime = (1 << 13) - 1; // A mersenne prime - index = ((K * index) % Prime) % MaxIndex; + index = (index + Prime) % MaxIndex; } while (true); } diff --git a/apps/opencs/model/world/land.cpp b/apps/opencs/model/world/land.cpp index 74833d7ef..bfa927444 100644 --- a/apps/opencs/model/world/land.cpp +++ b/apps/opencs/model/world/land.cpp @@ -8,8 +8,6 @@ namespace CSMWorld void Land::load(ESM::ESMReader &esm, bool &isDeleted) { ESM::Land::load(esm, isDeleted); - - mId = createUniqueRecordId(mX, mY); } std::string Land::createUniqueRecordId(int x, int y) diff --git a/apps/opencs/model/world/land.hpp b/apps/opencs/model/world/land.hpp index cc7e914af..e604f1311 100644 --- a/apps/opencs/model/world/land.hpp +++ b/apps/opencs/model/world/land.hpp @@ -12,8 +12,6 @@ namespace CSMWorld /// \todo Add worldspace support to the Land record. struct Land : public ESM::Land { - std::string mId; - /// Loads the metadata and ID void load (ESM::ESMReader &esm, bool &isDeleted); diff --git a/apps/opencs/model/world/landtexture.cpp b/apps/opencs/model/world/landtexture.cpp index 32bab1e6d..43deb64a4 100644 --- a/apps/opencs/model/world/landtexture.cpp +++ b/apps/opencs/model/world/landtexture.cpp @@ -1,6 +1,6 @@ #include "landtexture.hpp" -#include +#include #include #include @@ -16,7 +16,9 @@ namespace CSMWorld std::string LandTexture::createUniqueRecordId(int plugin, int index) { - return 'L' + std::to_string(plugin) + '#' + std::to_string(index); + std::stringstream ss; + ss << 'L' << plugin << '#' << index; + return ss.str(); } void LandTexture::parseUniqueRecordId(const std::string& id, int& plugin, int& index) diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index 08b8b3620..a227a6a87 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/land.hpp" diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index ef8cf60d5..9674a2b58 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -1,11 +1,11 @@ #ifndef CSV_WORLD_LANDCREATOR_H #define CSV_WORLD_LANDCREATOR_H -#include -#include - #include "genericcreator.hpp" +class QLabel; +class QSpinBox; + namespace CSVWorld { class LandCreator : public GenericCreator diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index f79c08427..fdabfb281 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -3,9 +3,9 @@ #include #include -#include #include #include +#include #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" @@ -30,14 +30,13 @@ namespace CSVWorld QLabel* indexLabel = new QLabel("Index"); insertBeforeButtons(indexLabel, false); - QIntValidator* indexValidator = new QIntValidator(0, MaxIndex, this); - - mIndexEdit = new QLineEdit(this); - mIndexEdit->setValidator(indexValidator); - insertBeforeButtons(mIndexEdit, true); + mIndexBox = new QSpinBox(this); + mIndexBox->setMinimum(0); + mIndexBox->setMaximum(MaxIndex); + insertBeforeButtons(mIndexBox, true); connect(mNameEdit, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&))); - connect(mIndexEdit, SIGNAL(textChanged(const QString&)), this, SLOT(indexChanged(const QString&))); + connect(mIndexBox, SIGNAL(valueChanged(int)), this, SLOT(indexChanged(int))); } void LandTextureCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) @@ -50,26 +49,23 @@ namespace CSVWorld mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); - mIndexEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); + mIndexBox->setValue((table.data(table.getModelIndex(originId, column)).toInt())); } void LandTextureCreator::focus() { - mIndexEdit->setFocus(); + mIndexBox->setFocus(); } void LandTextureCreator::reset() { GenericCreator::reset(); mNameEdit->setText(""); - mIndexEdit->setText(""); + mIndexBox->setValue(0); } std::string LandTextureCreator::getErrors() const { - std::string id = getId(); - - // TODO empty index edit? if (getData().getLandTextures().searchId(getId()) >= 0) { return "Index is already in use"; @@ -89,7 +85,7 @@ namespace CSVWorld std::string LandTextureCreator::getId() const { - return CSMWorld::LandTexture::createUniqueRecordId(0, mIndex); + return CSMWorld::LandTexture::createUniqueRecordId(0, mIndexBox->value()); } void LandTextureCreator::nameChanged(const QString& value) @@ -98,9 +94,8 @@ namespace CSVWorld update(); } - void LandTextureCreator::indexChanged(const QString& value) + void LandTextureCreator::indexChanged(int value) { - mIndex = value.toInt(); update(); } } diff --git a/apps/opencs/view/world/landtexturecreator.hpp b/apps/opencs/view/world/landtexturecreator.hpp index 46388bf03..b11c47758 100644 --- a/apps/opencs/view/world/landtexturecreator.hpp +++ b/apps/opencs/view/world/landtexturecreator.hpp @@ -6,6 +6,7 @@ #include "genericcreator.hpp" class QLineEdit; +class QSpinBox; namespace CSVWorld { @@ -34,15 +35,14 @@ namespace CSVWorld private slots: void nameChanged(const QString& val); - void indexChanged(const QString& val); + void indexChanged(int val); private: QLineEdit* mNameEdit; - QLineEdit* mIndexEdit; + QSpinBox* mIndexBox; std::string mName; - int mIndex; }; } From 7559d2531773a256ef83a803938d8e9110c6693c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Sep 2017 15:11:47 +0400 Subject: [PATCH 127/521] Update alchemy effects after every created potion (#4079) --- apps/openmw/mwmechanics/alchemy.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 124468641..48705dc72 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -262,22 +262,16 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord(const ESM::Potion& toFind) co void MWMechanics::Alchemy::removeIngredients() { - bool needsUpdate = false; - for (TIngredientsContainer::iterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) if (!iter->isEmpty()) { iter->getContainerStore()->remove(*iter, 1, mAlchemist); if (iter->getRefData().getCount()<1) - { - needsUpdate = true; *iter = MWWorld::Ptr(); - } } - if (needsUpdate) - updateEffects(); + updateEffects(); } void MWMechanics::Alchemy::addPotion (const std::string& name) From 538498230b97f478532441c75e2afe125cee43c8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 6 Sep 2017 15:59:54 +0400 Subject: [PATCH 128/521] Declare mClient variable --- components/widgets/windowcaption.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/widgets/windowcaption.hpp b/components/widgets/windowcaption.hpp index bdd4c0a2e..b45da2d1c 100644 --- a/components/widgets/windowcaption.hpp +++ b/components/widgets/windowcaption.hpp @@ -23,6 +23,7 @@ namespace Gui private: MyGUI::Widget* mLeft; MyGUI::Widget* mRight; + MyGUI::Widget* mClient; void align(); }; From dc0313a36f7c01952c0f10f89566441bc05a8cac Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 7 Sep 2017 21:06:10 +0400 Subject: [PATCH 129/521] Use base skill value when calculating rank requirements --- apps/openmw/mwmechanics/npcstats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 595635206..f0fc7fb6e 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -380,7 +380,7 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int for (int i=0; i<7; ++i) { if (faction.mData.mSkills[i] != -1) - skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getModified())); + skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getBase())); } if (skills.empty()) From ab607f302834c1409e1f0d72caa0dc68be83361c Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 00:51:46 -0400 Subject: [PATCH 130/521] Tweaks to land loading, land cloning, terrain signals, placeholder land update handling --- apps/opencs/model/world/collection.hpp | 2 + apps/opencs/model/world/commands.cpp | 170 ++++++++++++------ apps/opencs/model/world/commands.hpp | 54 +++++- apps/opencs/view/render/cell.cpp | 72 ++++++-- apps/opencs/view/render/cell.hpp | 14 ++ .../view/render/pagedworldspacewidget.cpp | 81 +++++++++ .../view/render/pagedworldspacewidget.hpp | 8 + apps/opencs/view/world/genericcreator.cpp | 5 + apps/opencs/view/world/genericcreator.hpp | 2 + apps/opencs/view/world/landcreator.cpp | 19 ++ apps/opencs/view/world/landcreator.hpp | 11 +- components/esm/loadland.cpp | 9 +- components/esm/loadland.hpp | 6 +- 13 files changed, 363 insertions(+), 90 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 80117d0c6..6e74a1726 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -297,6 +297,7 @@ namespace CSMWorld { int index = cloneRecordImp(origin, destination, type); mRecords.at(index).get().mPlugin = 0; + mRecords.at(index).get().mContext.filename.clear(); } template @@ -312,6 +313,7 @@ namespace CSMWorld if (index >= 0) { mRecords.at(index).get().mPlugin = 0; + mRecords.at(index).get().mContext.filename.clear(); return true; } diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index c98f52777..5bfcd6846 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -41,87 +41,145 @@ void CSMWorld::TouchCommand::undo() } } -CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, QUndoCommand* parent) +CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTable, + IdTable& ltexTable, QUndoCommand* parent) : QUndoCommand(parent) , mLands(landTable) , mLtexs(ltexTable) - , mId(id) - , mOld(nullptr) - , mChanged(false) + , mOldState(0) { - setText(("Touch " + mId).c_str()); - mOld.reset(mLands.getRecord(mId).clone()); + setText("Import land textures"); } -void CSMWorld::TouchLandCommand::redo() +void CSMWorld::ImportLandTexturesCommand::redo() { int pluginColumn = mLands.findColumnIndex(Columns::ColumnId_PluginIndex); - int oldPlugin = mLands.data(mLands.getModelIndex(mId, pluginColumn)).toInt(); + int oldPlugin = mLands.data(mLands.getModelIndex(getOriginId(), pluginColumn)).toInt(); - mChanged = mLands.touchRecord(mId); - if (mChanged) + // Original data + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); + const uint16_t* textureData = reinterpret_cast(mOld.data()); + + // Need to make a copy so the old values can be looked up + QByteArray newTextureByteArray(mOld.data(), mOld.size()); + uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + + // Perform touch/copy/etc... + onRedo(); + + // Find all indices used + std::unordered_set texIndices; + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { - // Original data - int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - QByteArray textureByteArray = mLands.data(mLands.getModelIndex(mId, textureColumn)).toByteArray(); - const uint16_t* textureData = reinterpret_cast(textureByteArray.data()); - - // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(textureByteArray.data(), textureByteArray.size()); - uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); - - // Find all indices used - std::unordered_set texIndices; - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (textureData[i] > 0) - texIndices.insert(textureData[i] - 1); - } + // All indices are offset by 1 for a default texture + if (textureData[i] > 0) + texIndices.insert(textureData[i] - 1); + } - std::vector oldTextures; - for (int index : texIndices) - { - oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); - } + std::vector oldTextures; + for (int index : texIndices) + { + oldTextures.push_back(LandTexture::createUniqueRecordId(oldPlugin, index)); + } - // Import the textures, replace old values - LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); - mCreatedTextures = std::move(results.createdRecords); - for (const auto& it : results.recordMapping) - { - int plugin = 0, newIndex = 0, oldIndex = 0; - LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); - LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); + // Import the textures, replace old values + LandTextureIdTable::ImportResults results = dynamic_cast(mLtexs).importTextures(oldTextures); + mCreatedTextures = std::move(results.createdRecords); + for (const auto& it : results.recordMapping) + { + int plugin = 0, newIndex = 0, oldIndex = 0; + LandTexture::parseUniqueRecordId(it.first, plugin, oldIndex); + LandTexture::parseUniqueRecordId(it.second, plugin, newIndex); - if (newIndex != oldIndex) + if (newIndex != oldIndex) + { + for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) - { - // All indices are offset by 1 for a default texture - if (textureData[i] == oldIndex) - newTextureData[i] = newIndex + 1; - } + // All indices are offset by 1 for a default texture + if (textureData[i] == oldIndex + 1) + newTextureData[i] = newIndex + 1; } } + } - mLands.setData(mLands.getModelIndex(mId, textureColumn), newTextureByteArray); + // Apply modification + int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); + + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), newTextureByteArray); +} + +void CSMWorld::ImportLandTexturesCommand::undo() +{ + // Restore to previous + int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), mOld); + + int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); + mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState); + + // Undo copy/touch/etc... + onUndo(); + + for (const std::string& id : mCreatedTextures) + { + int row = mLtexs.getModelIndex(id, 0).row(); + mLtexs.removeRows(row, 1); } + mCreatedTextures.clear(); } -void CSMWorld::TouchLandCommand::undo() +CSMWorld::CopyLandTexturesCommand::CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& origin, const std::string& dest, QUndoCommand* parent) + : ImportLandTexturesCommand(landTable, ltexTable, parent) + , mOriginId(origin) + , mDestId(dest) +{ +} + +const std::string& CSMWorld::CopyLandTexturesCommand::getOriginId() const +{ + return mOriginId; +} + +const std::string& CSMWorld::CopyLandTexturesCommand::getDestinationId() const +{ + return mDestId; +} + +CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& id, QUndoCommand* parent) + : ImportLandTexturesCommand(landTable, ltexTable, parent) + , mId(id) + , mOld(nullptr) + , mChanged(false) +{ + setText(("Touch " + mId).c_str()); + mOld.reset(mLands.getRecord(mId).clone()); +} + +const std::string& CSMWorld::TouchLandCommand::getOriginId() const +{ + return mId; +} + +const std::string& CSMWorld::TouchLandCommand::getDestinationId() const +{ + return mId; +} + +void CSMWorld::TouchLandCommand::onRedo() +{ + mChanged = mLands.touchRecord(mId); +} + +void CSMWorld::TouchLandCommand::onUndo() { if (mChanged) { mLands.setRecord(mId, *mOld); mChanged = false; - - for (const std::string& id : mCreatedTextures) - { - int row = mLtexs.getModelIndex(id, 0).row(); - mLtexs.removeRows(row, 1); - } - mCreatedTextures.clear(); } } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 5f4259cb8..aab0c5410 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -43,23 +43,67 @@ namespace CSMWorld bool mChanged; }; - class TouchLandCommand : public QUndoCommand + class ImportLandTexturesCommand : public QUndoCommand { public: - TouchLandCommand(IdTable& landTable, IdTable& ltexTable, const std::string& id, - QUndoCommand* parent = nullptr); + ImportLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, + QUndoCommand* parent); void redo() override; void undo() override; - private: + protected: + + virtual const std::string& getOriginId() const = 0; + virtual const std::string& getDestinationId() const = 0; + + virtual void onRedo() = 0; + virtual void onUndo() = 0; IdTable& mLands; IdTable& mLtexs; + QByteArray mOld; + int mOldState; + std::vector mCreatedTextures; + }; + + class CopyLandTexturesCommand : public ImportLandTexturesCommand + { + public: + + CopyLandTexturesCommand(IdTable& landTable, IdTable& ltexTable, const std::string& origin, + const std::string& dest, QUndoCommand* parent = nullptr); + + private: + + const std::string& getOriginId() const override; + const std::string& getDestinationId() const override; + + void onRedo() override {} + void onUndo() override {} + + std::string mOriginId; + std::string mDestId; + }; + + class TouchLandCommand : public ImportLandTexturesCommand + { + public: + + TouchLandCommand(IdTable& landTable, IdTable& ltexTable, + const std::string& id, QUndoCommand* parent = nullptr); + + private: + + const std::string& getOriginId() const override; + const std::string& getDestinationId() const override; + + void onRedo() override; + void onUndo() override; + std::string mId; std::unique_ptr mOld; - std::vector mCreatedTextures; bool mChanged; }; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 765c5b316..51279cac4 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -75,6 +75,31 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } +void CSVRender::Cell::createLand() +{ + if (mDeleted) + { + mTerrain.reset(); + return; + } + + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) + { + const ESM::Land& esmLand = land.getRecord(mId).get(); + + if (esmLand.getLandData (ESM::Land::DATA_VHGT)) + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + mTerrain->loadCell(esmLand.mX, esmLand.mY); + + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); + } + } +} + CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), @@ -99,22 +124,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) - { - const ESM::Land& esmLand = land.getRecord(mId).get(); - - if (esmLand.getLandData (ESM::Land::DATA_VHGT)) - { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, data.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); - mTerrain->loadCell(esmLand.mX, - esmLand.mY); - - mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); - mCellBorder->buildShape(esmLand); - } - } + createLand(); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); @@ -285,6 +295,36 @@ void CSVRender::Cell::pathgridRemoved() mPathgrid->removeGeometry(); } +void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + createLand(); +} + +void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + createLand(); +} + +void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + +void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) +{ + createLand(); +} + void CSVRender::Cell::reloadAssets() { for (std::map::const_iterator iter (mObjects.begin()); diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f53f61973..f6db475d7 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -72,6 +72,8 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); + void createLand(); + public: enum Selection @@ -118,6 +120,18 @@ namespace CSVRender void pathgridRemoved(); + void landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void landAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void landAdded (const QModelIndex& parent, int start, int end); + + void landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + void landTextureAdded (const QModelIndex& parent, int start, int end); + void reloadAssets(); void setSelection (int elementMask, Selection mode); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b1077139c..b224ac1c4 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -351,6 +351,69 @@ void CSVRender::PagedWorldspaceWidget::pathgridAdded(const QModelIndex& parent, } } +void CSVRender::PagedWorldspaceWidget::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + for (int r = topLeft.row(); r <= bottomRight.row(); ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landDataChanged(topLeft, bottomRight); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + for (int r = start; r <= end; ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landAboutToBeRemoved(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landAdded (const QModelIndex& parent, int start, int end) +{ + for (int r = start; r <= end; ++r) + { + std::string id = mDocument.getData().getLand().getId(r); + + auto cellIt = mCells.find(CSMWorld::CellCoordinates::fromId(id).first); + if (cellIt != mCells.end()) + { + cellIt->second->landAdded(parent, start, end); + flagAsModified(); + } + } +} + +void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureChanged(topLeft, bottomRight); +} + +void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureAboutToBeRemoved(parent, start, end); +} + +void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end) +{ + for (auto cellIt : mCells) + cellIt.second->landTextureAdded(parent, start, end); +} + std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { @@ -475,6 +538,24 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc connect (&document.getData(), SIGNAL (assetTablesChanged ()), this, SLOT (assetTablesChanged ())); + QAbstractItemModel *lands = document.getData().getTableModel (CSMWorld::UniversalId::Type_Lands); + + connect (lands, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (landDataChanged (const QModelIndex&, const QModelIndex&))); + connect (lands, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (landAboutToBeRemoved (const QModelIndex&, int, int))); + connect (lands, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (landAdded (const QModelIndex&, int, int))); + + QAbstractItemModel *ltexs = document.getData().getTableModel (CSMWorld::UniversalId::Type_LandTextures); + + connect (ltexs, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (landTextureDataChanged (const QModelIndex&, const QModelIndex&))); + connect (ltexs, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (landTextureAboutToBeRemoved (const QModelIndex&, int, int))); + connect (ltexs, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + this, SLOT (landTextureAdded (const QModelIndex&, int, int))); + // Shortcuts CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this); connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell())); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 8c41df51e..6672c2268 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -155,6 +155,14 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + virtual void landDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight); + virtual void landAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void landAdded (const QModelIndex& parent, int start, int end); + + virtual void landTextureDataChanged (const QModelIndex& topLeft, const QModelIndex& botomRight); + virtual void landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void landTextureAdded (const QModelIndex& parent, int start, int end); + void assetTablesChanged (); void loadCameraCell(); diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bde523a09..bd3da230d 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -51,6 +51,11 @@ std::string CSVWorld::GenericCreator::getId() const return mId->text().toUtf8().constData(); } +std::string CSVWorld::GenericCreator::getClonedId() const +{ + return mClonedId; +} + std::string CSVWorld::GenericCreator::getIdValidatorResult() const { std::string errors; diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index d708c1047..3baacfc06 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -64,6 +64,8 @@ namespace CSVWorld virtual std::string getId() const; + std::string getClonedId() const; + virtual std::string getIdValidatorResult() const; /// Allow subclasses to add additional data to \a command. diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index a227a6a87..dd7bfe68d 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -95,6 +95,25 @@ namespace CSVWorld return CSMWorld::Land::createUniqueRecordId(mX->value(), mY->value()); } + void LandCreator::pushCommand(std::unique_ptr command, const std::string& id) + { + if (mCloneMode) + { + CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); + CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); + + getUndoStack().beginMacro(("Clone " + id).c_str()); + getUndoStack().push(command.release()); + + CSMWorld::CopyLandTexturesCommand* ltexCopy = new CSMWorld::CopyLandTexturesCommand(lands, ltexs, getClonedId(), getId()); + getUndoStack().push(ltexCopy); + + getUndoStack().endMacro(); + } + else + getUndoStack().push (command.release()); + } + void LandCreator::coordChanged(int value) { update(); diff --git a/apps/opencs/view/world/landcreator.hpp b/apps/opencs/view/world/landcreator.hpp index 9674a2b58..e0c5577e4 100644 --- a/apps/opencs/view/world/landcreator.hpp +++ b/apps/opencs/view/world/landcreator.hpp @@ -31,13 +31,16 @@ namespace CSVWorld std::string getErrors() const override; - private slots: - - void coordChanged(int value); - protected: std::string getId() const override; + + void pushCommand(std::unique_ptr command, + const std::string& id) override; + + private slots: + + void coordChanged(int value); }; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 7d48dd037..c81675556 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -15,7 +15,6 @@ namespace ESM , mX(0) , mY(0) , mPlugin(0) - , mNoFile(false) , mDataTypes(0) , mLandData(NULL) { @@ -214,7 +213,8 @@ namespace ESM Land::DATA_VCLR | Land::DATA_VTEX; mDataTypes = mLandData->mDataLoaded; - mNoFile = true; + // No file associated with the land now + mContext.filename.clear(); } void Land::loadData(int flags, LandData* target) const @@ -236,7 +236,7 @@ namespace ESM } // Copy data to target if no file - if (mNoFile) + if (mContext.filename.empty()) { *target = *mLandData; return; @@ -320,7 +320,7 @@ namespace ESM Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), - mContext (land.mContext), mNoFile(land.mNoFile), mDataTypes (land.mDataTypes), + mContext (land.mContext), mDataTypes (land.mDataTypes), mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) {} @@ -337,7 +337,6 @@ namespace ESM std::swap (mY, land.mY); std::swap (mPlugin, land.mPlugin); std::swap (mContext, land.mContext); - std::swap (mNoFile, land.mNoFile); std::swap (mDataTypes, land.mDataTypes); std::swap (mLandData, land.mLandData); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 223b7975a..d7b736f99 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -31,12 +31,10 @@ struct Land // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. + // In the editor, there may not be a file associated with the Land, + // in which case the filename will be empty. ESM_Context mContext; - // In the editor, a new Land is not associated with a file, thus mContext should not be accessed - // when land data is being requested. Instead simply copy over the data. - bool mNoFile; - int mDataTypes; enum From ac2f20f983ca9be113e36d147e9fec9f226b0b91 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 8 Sep 2017 19:42:06 +0400 Subject: [PATCH 131/521] Update a disposition bar when a dialogue widget is disabled, but visible --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f478dad7e..2e80301d2 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -634,7 +634,7 @@ namespace MWGui void DialogueWindow::onFrame() { - if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(mMainWidget->getVisible() && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); From 3c0ec0d6d02d9ccd882e283e5973876259c42bfc Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 17:26:46 +0100 Subject: [PATCH 132/521] If CMake supports it, sets the debugger working directory for Visual Studio --- apps/bsatool/CMakeLists.txt | 6 ++++++ apps/esmtool/CMakeLists.txt | 6 ++++++ apps/essimporter/CMakeLists.txt | 6 ++++++ apps/launcher/CMakeLists.txt | 6 +++++- apps/mwiniimporter/CMakeLists.txt | 6 ++++++ apps/niftest/CMakeLists.txt | 6 ++++++ apps/opencs/CMakeLists.txt | 4 ++++ apps/openmw/CMakeLists.txt | 4 ++++ apps/openmw_test_suite/CMakeLists.txt | 6 ++++++ apps/wizard/CMakeLists.txt | 6 ++++++ 10 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 27baff815..19c9558cf 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -18,3 +18,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(bsatool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 1d5e662d8..b0c67d8fa 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -21,3 +21,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(esmtool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 93f53d0e8..a7c25ca2e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -46,3 +46,9 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") endif(WIN32) + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-essimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 8cbe18d51..5d70aa917 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -110,4 +110,8 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() - +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-launcher PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 4bd661685..071137556 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -33,3 +33,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-iniimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index d7f0200d2..efe440ae7 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -17,3 +17,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) endif() + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(niftest PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index fc8930b71..65c1d8ed8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -260,6 +260,10 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-cs PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 89b94ce12..3ef62dfa3 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -215,6 +215,10 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) + + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) if (WIN32) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index ea4b1209c..7d6898367 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -24,6 +24,12 @@ if (GTEST_FOUND) if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) endif() + + if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw_test_suite PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (MSVC) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index d2b9ab0f6..2d9a11c51 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -143,3 +143,9 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) + +if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(openmw-wizard PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) +endif (MSVC) \ No newline at end of file From 2eacc2f093e921c983047308eaf0a400b5294889 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 14:37:03 -0400 Subject: [PATCH 133/521] Changes to land creation, add ability to specifically clear terrain cache --- apps/opencs/view/render/cell.cpp | 36 ++++++++++++++++--- apps/opencs/view/render/cell.hpp | 1 + .../view/render/pagedworldspacewidget.cpp | 3 ++ components/terrain/world.cpp | 6 ++++ components/terrain/world.hpp | 4 +++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 51279cac4..18614a85f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -77,27 +77,55 @@ bool CSVRender::Cell::addObjects (int start, int end) void CSVRender::Cell::createLand() { + // Cell is deleted if (mDeleted) { - mTerrain.reset(); + unloadLand(); return; } + // Setup land if available const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); - if (landIndex != -1) + if (landIndex != -1 && !land.getRecord(mId).isDeleted()) { const ESM::Land& esmLand = land.getRecord(mId).get(); if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { - mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + if (mTerrain) + { + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + mTerrain->clearAssociatedCaches(); + } + else + { + mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, + mData.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); + } + mTerrain->loadCell(esmLand.mX, esmLand.mY); - mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + if (!mCellBorder) + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); + + return; } } + + // No land data + unloadLand(); +} + +void CSVRender::Cell::unloadLand() +{ + if (mTerrain) + mTerrain->unloadCell(mCoordinates.getX(), mCoordinates.getY()); + + if (mCellBorder) + mCellBorder.reset(); } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index f6db475d7..6418ed249 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -73,6 +73,7 @@ namespace CSVRender bool addObjects (int start, int end); void createLand(); + void unloadLand(); public: diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b224ac1c4..4a745195b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -400,18 +400,21 @@ void CSVRender::PagedWorldspaceWidget::landTextureDataChanged (const QModelIndex { for (auto cellIt : mCells) cellIt.second->landTextureChanged(topLeft, bottomRight); + flagAsModified(); } void CSVRender::PagedWorldspaceWidget::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { for (auto cellIt : mCells) cellIt.second->landTextureAboutToBeRemoved(parent, start, end); + flagAsModified(); } void CSVRender::PagedWorldspaceWidget::landTextureAdded (const QModelIndex& parent, int start, int end) { for (auto cellIt : mCells) cellIt.second->landTextureAdded(parent, start, end); + flagAsModified(); } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index b7cc0ae01..22c65b62c 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -75,4 +75,10 @@ void World::updateTextureFiltering() mTextureManager->updateTextureFiltering(); } +void World::clearAssociatedCaches() +{ + mTextureManager->clearCache(); + mChunkManager->clearCache(); +} + } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index d0576fbd3..e1c3828fc 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -63,6 +63,10 @@ namespace Terrain float getHeightAt (const osg::Vec3f& worldPos); + /// Clears the cached land and landtexture data. + /// @note Thread safe. + virtual void clearAssociatedCaches(); + /// Load a terrain cell at maximum LOD and store it in the View for later use. /// @note Thread safe. virtual void cacheCell(View* view, int x, int y) {} From 1e585ac71a4b6caea25bd6f24b02d70d165e3582 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 8 Sep 2017 22:50:07 +0200 Subject: [PATCH 134/521] Log a warning in case of missing bookart instead of showing a pink rectangle (Fixes #3826) --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/formatting.cpp | 18 +++++++++++++----- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d7ccfa3e4..4560ab270 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -360,7 +360,7 @@ namespace MWBase // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path) = 0; - virtual std::string correctBookartPath(const std::string& path, int width, int height) = 0; + virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr) = 0; virtual std::string correctTexturePath(const std::string& path) = 0; virtual bool textureExists(const std::string& path) = 0; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 72e1c09f3..cf4a5b589 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -275,8 +275,6 @@ namespace MWGui { case BookTextParser::Event_ImgTag: { - pag.setIgnoreLeadingEmptyLines(false); - const BookTextParser::Attributes & attr = parser.getAttributes(); if (attr.find("src") == attr.end() || attr.find("width") == attr.end() || attr.find("height") == attr.end()) @@ -286,8 +284,19 @@ namespace MWGui int width = MyGUI::utility::parseInt(attr.at("width")); int height = MyGUI::utility::parseInt(attr.at("height")); + bool exists; + std::string correctedSrc = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, height, &exists); + + if (!exists) + { + std::cerr << "Warning: Could not find \"" << src << "\" referenced by an tag." << std::endl; + break; + } + + pag.setIgnoreLeadingEmptyLines(false); + ImageElement elem(paper, pag, mBlockStyle, - src, width, height); + correctedSrc, width, height); elem.paginate(); break; } @@ -471,8 +480,7 @@ namespace MWGui MyGUI::IntCoord(left, pag.getCurrentTop(), width, mImageHeight), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - std::string image = MWBase::Environment::get().getWindowManager()->correctBookartPath(src, width, mImageHeight); - mImageBox->setImageTexture(image); + mImageBox->setImageTexture(src); mImageBox->setProperty("NeedMouse", "false"); } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 33ba58cc7..4b7b3c387 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2090,9 +2090,12 @@ namespace MWGui return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); } - std::string WindowManager::correctBookartPath(const std::string& path, int width, int height) + std::string WindowManager::correctBookartPath(const std::string& path, int width, int height, bool* exists) { - return Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + std::string corrected = Misc::ResourceHelpers::correctBookartPath(path, width, height, mResourceSystem->getVFS()); + if (exists) + *exists = mResourceSystem->getVFS()->exists(corrected); + return corrected; } std::string WindowManager::correctTexturePath(const std::string& path) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ceb6f62b7..4f06afb7d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -388,7 +388,7 @@ namespace MWGui // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path); - virtual std::string correctBookartPath(const std::string& path, int width, int height); + virtual std::string correctBookartPath(const std::string& path, int width, int height, bool* exists = nullptr); virtual std::string correctTexturePath(const std::string& path); virtual bool textureExists(const std::string& path); From 5ce34f1cbfe0527a3e4b03a6b459b7a52324e067 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:17:42 +0100 Subject: [PATCH 135/521] Move new behaviour into macro to reduce code duplication --- apps/bsatool/CMakeLists.txt | 10 ++-------- apps/esmtool/CMakeLists.txt | 10 ++-------- apps/essimporter/CMakeLists.txt | 10 ++-------- apps/launcher/CMakeLists.txt | 10 ++-------- apps/mwiniimporter/CMakeLists.txt | 10 ++-------- apps/niftest/CMakeLists.txt | 10 ++-------- apps/opencs/CMakeLists.txt | 6 +----- apps/openmw/CMakeLists.txt | 6 +----- apps/openmw_test_suite/CMakeLists.txt | 8 +------- apps/wizard/CMakeLists.txt | 8 +------- cmake/OpenMWMacros.cmake | 9 +++++++++ 11 files changed, 25 insertions(+), 72 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 19c9558cf..167ab9d2c 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -4,7 +4,7 @@ set(BSATOOL source_group(apps\\bsatool FILES ${BSATOOL}) # Main executable -add_executable(bsatool +openmw_add_executable(bsatool ${BSATOOL} ) @@ -17,10 +17,4 @@ target_link_libraries(bsatool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(bsatool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index b0c67d8fa..90964f2d7 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -8,7 +8,7 @@ set(ESMTOOL source_group(apps\\esmtool FILES ${ESMTOOL}) # Main executable -add_executable(esmtool +openmw_add_executable(esmtool ${ESMTOOL} ) @@ -20,10 +20,4 @@ target_link_libraries(esmtool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(esmtool PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index a7c25ca2e..69200583e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -28,7 +28,7 @@ set(ESSIMPORTER_FILES convertplayer.cpp ) -add_executable(openmw-essimporter +openmw_add_executable(openmw-essimporter ${ESSIMPORTER_FILES} ) @@ -45,10 +45,4 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") -endif(WIN32) - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-essimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif(WIN32) \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 5d70aa917..70a6708a8 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -78,7 +78,7 @@ if(NOT WIN32) endif(NOT WIN32) # Main executable -add_executable(openmw-launcher +openmw_add_executable(openmw-launcher ${GUI_TYPE} ${LAUNCHER} ${LAUNCHER_HEADER} @@ -108,10 +108,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-launcher PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 071137556..f1717a4c3 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -9,7 +9,7 @@ set(MWINIIMPORT_HEADER source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER}) -add_executable(openmw-iniimporter +openmw_add_executable(openmw-iniimporter ${MWINIIMPORT} ) @@ -32,10 +32,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-iniimporter PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index efe440ae7..10119d7d7 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -4,7 +4,7 @@ set(NIFTEST source_group(components\\nif\\tests FILES ${NIFTEST}) # Main executable -add_executable(niftest +openmw_add_executable(niftest ${NIFTEST} ) @@ -16,10 +16,4 @@ target_link_libraries(niftest if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) -endif() - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(niftest PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file +endif() \ No newline at end of file diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 65c1d8ed8..281921c81 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -174,7 +174,7 @@ else() set (OPENCS_OPENMW_CFG "") endif(APPLE) -add_executable(openmw-cs +openmw_add_executable(openmw-cs MACOSX_BUNDLE ${OPENCS_SRC} ${OPENCS_UI_HDR} @@ -260,10 +260,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-cs PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3ef62dfa3..134953f3d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -99,7 +99,7 @@ add_openmw_dir (mwbase # Main executable if (NOT ANDROID) - add_executable(openmw + openmw_add_executable(openmw ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -215,10 +215,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) endif (MSVC) if (WIN32) diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 7d6898367..9b09bc41f 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -17,19 +17,13 @@ if (GTEST_FOUND) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) - add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) + openmw_add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) target_link_libraries(openmw_test_suite ${GTEST_BOTH_LIBRARIES} components) # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) endif() - - if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw_test_suite PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) - endif (MSVC) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 2d9a11c51..5f7338e52 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -96,7 +96,7 @@ if (OPENMW_USE_UNSHIELD) include_directories(${LIBUNSHIELD_INCLUDE_DIRS}) endif() -add_executable(openmw-wizard +openmw_add_executable(openmw-wizard ${GUI_TYPE} ${WIZARD} ${WIZARD_HEADER} @@ -143,9 +143,3 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) - -if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) - set_target_properties(openmw-wizard PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) -endif (MSVC) \ No newline at end of file diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index c5669fa70..9a1722dab 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -142,3 +142,12 @@ foreach (u ${ARGN}) add_hdr (OPENCS ${dir} ${u}) endforeach (u) endmacro (opencs_hdrs_noqt) + +macro (openmw_add_executable target) + add_executable(${target} ${ARGN}) + if (MSVC) + if (CMAKE_VERSION VERSION_GREATER 3.8) + set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") + endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (MSVC) +endmacro (openmw_add_executable) From 8c74f16247b1888f359ba79740e4cf97d9b8b5f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:20:04 +0100 Subject: [PATCH 136/521] Restore trailing new lines to shrink PR --- apps/bsatool/CMakeLists.txt | 2 +- apps/esmtool/CMakeLists.txt | 2 +- apps/essimporter/CMakeLists.txt | 2 +- apps/launcher/CMakeLists.txt | 3 ++- apps/mwiniimporter/CMakeLists.txt | 2 +- apps/niftest/CMakeLists.txt | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 167ab9d2c..ec0615ff9 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries(bsatool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 90964f2d7..122ca2f3a 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -20,4 +20,4 @@ target_link_libraries(esmtool if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 69200583e..82182b7fa 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -45,4 +45,4 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") -endif(WIN32) \ No newline at end of file +endif(WIN32) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 70a6708a8..70281910f 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -108,4 +108,5 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-launcher gcov) -endif() \ No newline at end of file +endif() + diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index f1717a4c3..e83656708 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -32,4 +32,4 @@ endif() if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-iniimporter gcov) -endif() \ No newline at end of file +endif() diff --git a/apps/niftest/CMakeLists.txt b/apps/niftest/CMakeLists.txt index 10119d7d7..3cbee2b7e 100644 --- a/apps/niftest/CMakeLists.txt +++ b/apps/niftest/CMakeLists.txt @@ -16,4 +16,4 @@ target_link_libraries(niftest if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(niftest gcov) -endif() \ No newline at end of file +endif() From a9b95596bc55deba7daeec8249c811cd75cfa746 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 8 Sep 2017 22:21:00 +0100 Subject: [PATCH 137/521] Add a missed trailing new line. --- apps/launcher/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 70281910f..aac076404 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -110,3 +110,4 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() + From 72cb405de220d5cfe706c5c1c0e57358c32ab2dc Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 8 Sep 2017 21:03:52 -0400 Subject: [PATCH 138/521] Some bug fixes, changes to land load code. --- apps/opencs/model/world/columnimp.cpp | 6 ++++-- apps/opencs/model/world/data.cpp | 14 +------------- apps/opencs/model/world/idcollection.hpp | 17 +++++++++++++++++ components/esm/loadland.cpp | 4 ++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 65d2fecd2..e6b406864 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -103,7 +103,8 @@ namespace CSMWorld assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); - for (int i = 0; i < array.count(); ++i) + int count = array.count() / sizeof(float); + for (int i = 0; i < count; ++i) { landData->mHeights[i] = rawData[i]; } @@ -183,7 +184,8 @@ namespace CSMWorld assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); - for (int i = 0; i < array.count(); ++i) + int count = array.count() / sizeof(uint16_t); + for (int i = 0; i < count; ++i) { landData->mTextures[i] = rawData[i]; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 3284d9b05..0ffe5fa21 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -1013,19 +1013,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; - case ESM::REC_LAND: - { - int index = mLand.load(*mReader, mBase); - - // Load all land data for now. A future optimisation may only load non-base data - // if a suitable mechanism for avoiding race conditions can be established. - if (index!=-1/* && !mBase*/) - mLand.getRecord (index).get().loadData ( - ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | - ESM::Land::DATA_VTEX); - - break; - } + case ESM::REC_LAND: mLand.load(*mReader, mBase); break; case ESM::REC_CELL: { diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index ea6eefb88..7849aab92 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -4,6 +4,7 @@ #include #include "collection.hpp" +#include "land.hpp" namespace CSMWorld { @@ -39,6 +40,22 @@ namespace CSMWorld record.load (reader, isDeleted); } + template<> + inline void IdCollection >::loadRecord (Land& record, + ESM::ESMReader& reader, bool& isDeleted) + { + record.load (reader, isDeleted); + + // Load all land data for now. A future optimisation may only load non-base data + // if a suitable mechanism for avoiding race conditions can be established. + int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | + ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX; + record.loadData (flags); + + // Prevent data from being reloaded. + record.mContext.filename.clear(); + } + template int IdCollection::load (ESM::ESMReader& reader, bool base) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index c81675556..6f118c1ab 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -196,8 +196,8 @@ namespace ESM for (int i = 0; i < LAND_NUM_VERTS; ++i) { mLandData->mNormals[i*3+0] = 0; - mLandData->mNormals[i*3+1] = -1; - mLandData->mNormals[i*3+2] = 0; + mLandData->mNormals[i*3+1] = 0; + mLandData->mNormals[i*3+2] = 127; } for (int i = 0; i < LAND_NUM_TEXTURES; ++i) mLandData->mTextures[i] = 0; From c9f099ce07eb0da9df1d84d15e0993f63a6ec33e Mon Sep 17 00:00:00 2001 From: krizd Date: Sat, 9 Sep 2017 03:06:03 +0100 Subject: [PATCH 139/521] Change CMake version check to include 3.8 --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 9a1722dab..460751445 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -146,8 +146,8 @@ endmacro (opencs_hdrs_noqt) macro (openmw_add_executable target) add_executable(${target} ${ARGN}) if (MSVC) - if (CMAKE_VERSION VERSION_GREATER 3.8) + if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") - endif (CMAKE_VERSION VERSION_GREATER 3.8) + endif (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) endif (MSVC) endmacro (openmw_add_executable) From d030b595f8460e92eea09052805fbfcd2fdaeef9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 11:48:13 -0400 Subject: [PATCH 140/521] Fix potential segfault, cleanup, get rid of warnings. --- apps/opencs/model/world/collection.hpp | 2 -- apps/opencs/view/render/cell.cpp | 16 ++++++++-------- apps/opencs/view/render/cell.hpp | 2 +- apps/opencs/view/world/genericcreator.cpp | 9 ++++----- apps/opencs/view/world/landcreator.cpp | 9 ++++----- components/esm/loadland.cpp | 6 +++++- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 6e74a1726..80117d0c6 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -297,7 +297,6 @@ namespace CSMWorld { int index = cloneRecordImp(origin, destination, type); mRecords.at(index).get().mPlugin = 0; - mRecords.at(index).get().mContext.filename.clear(); } template @@ -313,7 +312,6 @@ namespace CSMWorld if (index >= 0) { mRecords.at(index).get().mPlugin = 0; - mRecords.at(index).get().mContext.filename.clear(); return true; } diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 18614a85f..1c1d496bb 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -75,7 +75,7 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -void CSVRender::Cell::createLand() +void CSVRender::Cell::updateLand() { // Cell is deleted if (mDeleted) @@ -152,7 +152,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st addObjects (0, rows-1); - createLand(); + updateLand(); mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); @@ -325,32 +325,32 @@ void CSVRender::Cell::pathgridRemoved() void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - createLand(); + updateLand(); } void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) { - createLand(); + updateLand(); } void CSVRender::Cell::reloadAssets() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 6418ed249..101aebd58 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -72,7 +72,7 @@ namespace CSVRender /// \return Have any objects been added? bool addObjects (int start, int end); - void createLand(); + void updateLand(); void unloadLand(); public: diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index bd3da230d..5e2118e9b 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -262,18 +262,17 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId, void CSVWorld::GenericCreator::touch(const std::vector& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr macro(new QUndoCommand()); - macro->setText("Touch records"); + mUndoStack.beginMacro("Touch Records"); CSMWorld::IdTable& table = dynamic_cast(*mData.getTableModel(mListId)); for (const CSMWorld::UniversalId& uid : ids) { - // This is not leaked, touchCmd is a child of macro and managed by Qt - CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId(), macro.get()); + CSMWorld::TouchCommand* touchCmd = new CSMWorld::TouchCommand(table, uid.getId()); + mUndoStack.push(touchCmd); } // Execute - mUndoStack.push(macro.release()); + mUndoStack.endMacro(); } void CSVWorld::GenericCreator::toggleWidgets(bool active) diff --git a/apps/opencs/view/world/landcreator.cpp b/apps/opencs/view/world/landcreator.cpp index dd7bfe68d..2ebfe1869 100644 --- a/apps/opencs/view/world/landcreator.cpp +++ b/apps/opencs/view/world/landcreator.cpp @@ -55,19 +55,18 @@ namespace CSVWorld void LandCreator::touch(const std::vector& ids) { // Combine multiple touch commands into one "macro" command - std::unique_ptr macro(new QUndoCommand()); - macro->setText("Touch records"); + getUndoStack().beginMacro("Touch records"); CSMWorld::IdTable& lands = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); CSMWorld::IdTable& ltexs = dynamic_cast(*getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); for (const CSMWorld::UniversalId& uid : ids) { - // This is not leaked, touchCmd is a child of macro and managed by Qt - CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId(), macro.get()); + CSMWorld::TouchLandCommand* touchCmd = new CSMWorld::TouchLandCommand(lands, ltexs, uid.getId()); + getUndoStack().push(touchCmd); } // Execute - getUndoStack().push(macro.release()); + getUndoStack().endMacro(); } void LandCreator::focus() diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 6f118c1ab..f597defd7 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -238,7 +238,11 @@ namespace ESM // Copy data to target if no file if (mContext.filename.empty()) { - *target = *mLandData; + if (mLandData) + *target = *mLandData; + else + target = new LandData; + return; } From 33c77d7a2aefaad6219bba2c43fc76497ceb32e4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sat, 9 Sep 2017 17:22:55 +0100 Subject: [PATCH 141/521] Try using cmake_parse_arguments to make the macro work --- cmake/OpenMWMacros.cmake | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 460751445..11f230ac6 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -143,8 +143,34 @@ add_hdr (OPENCS ${dir} ${u}) endforeach (u) endmacro (opencs_hdrs_noqt) +include(CMakeParseArguments) + macro (openmw_add_executable target) - add_executable(${target} ${ARGN}) + set(OMW_ADD_EXE_OPTIONS WIN32 MACOSX_BUNDLE EXCLUDE_FROM_ALL) + set(OMW_ADD_EXE_VALUES) + set(OMW_ADD_EXE_MULTI_VALUES) + cmake_parse_arguments(OMW_ADD_EXE "${OMW_ADD_EXE_OPTIONS}" "${OMW_ADD_EXE_VALUES}" "${OMW_ADD_EXE_MULTI_VALUES}" ${ARGN}) + + if (OMW_ADD_EXE_WIN32) + set(OMW_ADD_EXE_WIN32_VALUE WIN32) + endif (OMW_ADD_EXE_WIN32) + + if (OMW_ADD_EXE_MACOSX_BUNDLE) + set(OMW_ADD_EXE_MACOSX_BUNDLE_VALUE MACOSX_BUNDLE) + endif (OMW_ADD_EXE_MACOSX_BUNDLE) + + if (OMW_ADD_EXE_EXCLUDE_FROM_ALL) + set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) + endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) + + message("Target: " ${target}) + message("WIN32: ${OMW_ADD_EXE_WIN32_VALUE}") + message("MACOSX_BUNDLE: ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE}") + message("EXCLUDE_FROM_ALL: ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE}") + message("Unparsed: ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + + add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} "${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + if (MSVC) if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_target_properties(${target} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(TargetDir)") From 25d4a0370f7022c8c83b80d99741ad9d9345e5b1 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 15:37:52 -0400 Subject: [PATCH 142/521] Changes to land data access in tables, also update Land once per frame in scene view. --- apps/opencs/model/world/columnimp.cpp | 131 ++++++++++++++++---------- apps/opencs/model/world/idtable.cpp | 3 +- apps/opencs/view/render/cell.cpp | 51 ++++++++-- apps/opencs/view/render/cell.hpp | 3 + components/esm/loadland.cpp | 9 ++ components/esm/loadland.hpp | 3 + 6 files changed, 143 insertions(+), 57 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index e6b406864..1ee7f8a03 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -10,19 +10,31 @@ namespace CSMWorld QVariant LandMapLodColumn::get(const Record& record) const { - // Note: original data is signed - const char* rawData = reinterpret_cast(&record.get().mWnam[0]); - return QByteArray(rawData, Land::LAND_GLOBAL_MAP_LOD_SIZE); + const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE; + const Land& land = record.get(); + + if (land.isDataLoaded(Land::DATA_WNAM)) + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&land.mWnam[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandMapLodColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_WNAM); + for (int i = 0; i < array.count(); ++i) { copy.mWnam[i] = rawData[i]; @@ -44,28 +56,34 @@ namespace CSMWorld QVariant LandNormalsColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * 3; + const Land& land = record.get(); - // Note: original data is signed - const char* rawData = reinterpret_cast(&landData->mNormals[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + if (land.isDataLoaded(Land::DATA_VNML)) + { + // Note: original data is signed + const char* rawData = reinterpret_cast(&land.getLandData()->mNormals[0]); + return QByteArray(rawData, Size); + } + else + { + // Return a blank array + return QByteArray(Size, 0); + } } void LandNormalsColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VNML); + for (int i = 0; i < array.count(); ++i) { - landData->mNormals[i] = rawData[i]; + copy.getLandData()->mNormals[i] = rawData[i]; } record.setModified(copy); @@ -84,29 +102,34 @@ namespace CSMWorld QVariant LandHeightsColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * sizeof(float); + const Land& land = record.get(); - // Note: original data is float - const char* rawData = reinterpret_cast(&landData->mHeights[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * sizeof(float)); + if (land.isDataLoaded(Land::DATA_VHGT)) + { + // Note: original data is float + const char* rawData = reinterpret_cast(&land.getLandData()->mHeights[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandHeightsColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VHGT); + int count = array.count() / sizeof(float); for (int i = 0; i < count; ++i) { - landData->mHeights[i] = rawData[i]; + copy.getLandData()->mHeights[i] = rawData[i]; } record.setModified(copy); @@ -125,28 +148,33 @@ namespace CSMWorld QVariant LandColoursColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_VERTS * 3; + const Land& land = record.get(); - // Note: original data is unsigned char - const char* rawData = reinterpret_cast(&landData->mColours[0]); - return QByteArray(rawData, Land::LAND_NUM_VERTS * 3); + if (land.isDataLoaded(Land::DATA_VCLR)) + { + // Note: original data is unsigned char + const char* rawData = reinterpret_cast(&land.getLandData()->mColours[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandColoursColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const unsigned char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VCLR); + for (int i = 0; i < array.count(); ++i) { - landData->mColours[i] = rawData[i]; + copy.getLandData()->mColours[i] = rawData[i]; } record.setModified(copy); @@ -165,29 +193,34 @@ namespace CSMWorld QVariant LandTexturesColumn::get(const Record& record) const { - const Land::LandData* landData = record.get().getLandData(); - assert(landData); + const int Size = Land::LAND_NUM_TEXTURES * sizeof(uint16_t); + const Land& land = record.get(); - // Note: original data is uint16_t - const char* rawData = reinterpret_cast(&landData->mTextures[0]); - return QByteArray(rawData, Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + if (land.isDataLoaded(Land::DATA_VTEX)) + { + // Note: original data is uint16_t + const char* rawData = reinterpret_cast(&land.getLandData()->mTextures[0]); + return QByteArray(rawData, Size); + } + else + { + return QByteArray(Size, 0); + } } void LandTexturesColumn::set(Record& record, const QVariant& data) { - Land copy = record.get(); - Land::LandData* landData = copy.getLandData(); - assert (landData); - QByteArray array = data.toByteArray(); const uint16_t* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + Land copy = record.get(); + copy.setDataLoaded(Land::DATA_VTEX); + int count = array.count() / sizeof(uint16_t); for (int i = 0; i < count; ++i) { - landData->mTextures[i] = rawData[i]; + copy.getLandData()->mTextures[i] = rawData[i]; } record.setModified(copy); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 127ffde2c..b41eea8f8 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -356,6 +356,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. // Iteration is deterministic to avoid duplicates. + int startIndex = index; do { std::string newId = LandTexture::createUniqueRecordId(0, index); int newRow = idCollection()->searchId(newId); @@ -384,7 +385,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import size_t Prime = (1 << 13) - 1; // A mersenne prime index = (index + Prime) % MaxIndex; - } while (true); + } while (index != startIndex); } return results; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 1c1d496bb..552a54ac2 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -26,6 +26,33 @@ #include "terrainstorage.hpp" #include "object.hpp" +namespace CSVRender +{ + class CellNodeContainer : public osg::Referenced + { + public: + + CellNodeContainer(Cell* cell) : mCell(cell) {} + + Cell* getCell(){ return mCell; } + + private: + + Cell* mCell; + }; + + class CellNodeCallback : public osg::NodeCallback + { + public: + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + CellNodeContainer* container = static_cast(node->getUserData()); + container->getCell()->updateLand(); + } + }; +} + bool CSVRender::Cell::removeObject (const std::string& id) { std::map::iterator iter = @@ -77,6 +104,11 @@ bool CSVRender::Cell::addObjects (int start, int end) void CSVRender::Cell::updateLand() { + if (!mUpdateLand || mLandDeleted) + return; + + mUpdateLand = false; + // Cell is deleted if (mDeleted) { @@ -116,6 +148,7 @@ void CSVRender::Cell::updateLand() } // No land data + mLandDeleted = true; unloadLand(); } @@ -131,7 +164,7 @@ void CSVRender::Cell::unloadLand() CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), - mSubModeElementMask (0) + mSubModeElementMask (0), mUpdateLand(true), mLandDeleted(false) { std::pair result = CSMWorld::CellCoordinates::fromId (id); @@ -139,6 +172,8 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mCoordinates = result.first; mCellNode = new osg::Group; + mCellNode->setUserData(new CellNodeContainer(this)); + mCellNode->setUpdateCallback(new CellNodeCallback); rootNode->addChild(mCellNode); setCellMarker(); @@ -325,32 +360,34 @@ void CSVRender::Cell::pathgridRemoved() void CSVRender::Cell::landDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - updateLand(); + mLandDeleted = true; + unloadLand(); } void CSVRender::Cell::landAdded (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; + mLandDeleted = false; } void CSVRender::Cell::landTextureChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landTextureAboutToBeRemoved (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::landTextureAdded (const QModelIndex& parent, int start, int end) { - updateLand(); + mUpdateLand = true; } void CSVRender::Cell::reloadAssets() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 101aebd58..444608688 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -57,6 +57,7 @@ namespace CSVRender bool mDeleted; int mSubMode; unsigned int mSubModeElementMask; + bool mUpdateLand, mLandDeleted; /// Ignored if cell does not have an object with the given ID. /// @@ -160,6 +161,8 @@ namespace CSVRender /// Erase all overrides and restore the visual representation of the cell to its /// true state. void reset (unsigned int elementMask); + + friend class CellNodeCallback; }; } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index f597defd7..1d2cf7575 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -322,6 +322,15 @@ namespace ESM return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); } + void Land::setDataLoaded(int flags) + { + if (!mLandData) + mLandData = new LandData; + + mDataTypes |= flags; + mLandData->mDataLoaded |= flags; + } + Land::Land (const Land& land) : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), mContext (land.mContext), mDataTypes (land.mDataTypes), diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d7b736f99..7be954b3e 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -135,6 +135,9 @@ struct Land /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; + /// Sets the flags and creates a LandData if needed + void setDataLoaded(int flags); + Land (const Land& land); Land& operator= (Land land); From 9503d6186640a3c578e424c98ccf65f5c8ca3a76 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 9 Sep 2017 23:22:16 +0300 Subject: [PATCH 143/521] Use const nodeMap in creature animation --- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2ad362b33..735c0b66d 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -118,7 +118,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); const NodeMap& nodeMap = getNodeMap(); - NodeMap::const_iterator found = getNodeMap().find(Misc::StringUtils::lowerCase(bonename)); + NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); if (found == nodeMap.end()) throw std::runtime_error("Can't find attachment node " + bonename); osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, found->second.get()); From de14e436803ac3ddb8ad9836d7ce5d90e9a13b68 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 10 Sep 2017 03:18:22 +0100 Subject: [PATCH 144/521] Seemingly fix everything by setting policies that were unset upon entering the macro --- cmake/OpenMWMacros.cmake | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 11f230ac6..6686ea131 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -163,13 +163,11 @@ macro (openmw_add_executable target) set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) - message("Target: " ${target}) - message("WIN32: ${OMW_ADD_EXE_WIN32_VALUE}") - message("MACOSX_BUNDLE: ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE}") - message("EXCLUDE_FROM_ALL: ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE}") - message("Unparsed: ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + # AnyOldName3 says: I have no idea why or if it's even supposed to happen, but somehow entering this macro confuses CMake about which policies should be set. They are restored here. + cmake_policy(SET CMP0003 NEW) + cmake_policy(SET CMP0020 NEW) - add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} "${OMW_ADD_EXE_UNPARSED_ARGUMENTS}") + add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}) if (MSVC) if (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) From 09e645a0e094950891ec19a7a4dc210a0fd11ae5 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 9 Sep 2017 23:18:09 -0400 Subject: [PATCH 145/521] Fix careless mistake. --- components/esm/loadland.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 1d2cf7575..083f27cef 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -238,10 +238,9 @@ namespace ESM // Copy data to target if no file if (mContext.filename.empty()) { - if (mLandData) + // Make sure there is data, and that it doesn't point to the same object. + if (mLandData && mLandData != target) *target = *mLandData; - else - target = new LandData; return; } From 661232222f428598e5659f8a277a426434318551 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 15:26:48 +0400 Subject: [PATCH 146/521] Allow guards to attack fighting creatures only in fAlarmRadius range --- apps/openmw/mwmechanics/actors.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ed510e616..d15e1a1a5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -394,10 +394,15 @@ namespace MWMechanics aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } - + // Make guards go aggressive with creatures that are in combat, unless the creature is a follower or escorter if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc()) { + // Check if the creature is too far + static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get().find("fAlarmRadius")->getFloat(); + if (sqrDist > fAlarmRadius * fAlarmRadius) + return; + bool followerOrEscorter = false; for (std::list::const_iterator it = creatureStats2.getAiSequence().begin(); it != creatureStats2.getAiSequence().end(); ++it) { From afbdc27a34995e0bcef7386c4229cdedc3777f0c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 10 Sep 2017 18:30:10 +0100 Subject: [PATCH 147/521] Move calls to cmake_minimum_required as early in the CMake process as possible. --- CMakeLists.txt | 71 +++++++++++++++++++++------------------- cmake/OpenMWMacros.cmake | 4 --- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a78eac572..0050104cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,40 @@ +# Apps and tools +option(BUILD_OPENMW "build OpenMW" ON) +option(BUILD_BSATOOL "build BSA extractor" ON) +option(BUILD_ESMTOOL "build ESM inspector" ON) +option(BUILD_LAUNCHER "build Launcher" ON) +option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) +option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) +option(BUILD_OPENCS "build OpenMW Construction Set" ON) +option(BUILD_WIZARD "build Installation Wizard" ON) +option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) +option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BUILD_NIFTEST "build nif file tester" OFF) +option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) +option(BUILD_DOCS "build documentation." OFF ) + +if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) + set(USE_QT FALSE) +else() + set(USE_QT TRUE) +endif() + +if (USE_QT) + set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") + set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) +endif() + +if (APPLE) + # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db + cmake_minimum_required(VERSION 3.1.0) +elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) + # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. + cmake_minimum_required(VERSION 2.8.11) +else() + # We probably support older versions than this. + cmake_minimum_required(VERSION 2.6) +endif() + project(OpenMW) # If the user doesn't supply a CMAKE_BUILD_TYPE via command line, choose one for them. @@ -59,21 +96,6 @@ option(QT_STATIC "Link static build of QT into the binaries" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) -# Apps and tools -option(BUILD_OPENMW "build OpenMW" ON) -option(BUILD_BSATOOL "build BSA extractor" ON) -option(BUILD_ESMTOOL "build ESM inspector" ON) -option(BUILD_LAUNCHER "build Launcher" ON) -option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) -option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) -option(BUILD_OPENCS "build OpenMW Construction Set" ON) -option(BUILD_WIZARD "build Installation Wizard" ON) -option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) -option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) -option(BUILD_NIFTEST "build nif file tester" OFF) -option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) -option(BUILD_DOCS "build documentation." OFF ) - # what is necessary to build documentation IF( BUILD_DOCS ) # Builds the documentation. @@ -120,16 +142,8 @@ if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) endif() -if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) - set(USE_QT FALSE) -else() - set(USE_QT TRUE) -endif() - # Dependencies if (USE_QT) - set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)") - set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) message(STATUS "Using Qt${DESIRED_QT_VERSION}") if (DESIRED_QT_VERSION MATCHES 4) @@ -144,17 +158,6 @@ if (USE_QT) endif() endif() -if (APPLE) - # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db - cmake_minimum_required(VERSION 3.1.0) -elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) - # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. - cmake_minimum_required(VERSION 2.8.11) -else() - # We probably support older versions than this. - cmake_minimum_required(VERSION 2.6) -endif() - # Sound setup find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE) # Required for building the FFmpeg headers diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 6686ea131..6573265bd 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -163,10 +163,6 @@ macro (openmw_add_executable target) set(OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE EXCLUDE_FROM_ALL) endif (OMW_ADD_EXE_EXCLUDE_FROM_ALL) - # AnyOldName3 says: I have no idea why or if it's even supposed to happen, but somehow entering this macro confuses CMake about which policies should be set. They are restored here. - cmake_policy(SET CMP0003 NEW) - cmake_policy(SET CMP0020 NEW) - add_executable(${target} ${OMW_ADD_EXE_WIN32_VALUE} ${OMW_ADD_EXE_MACOSX_BUNDLE_VALUE} ${OMW_ADD_EXE_EXCLUDE_FROM_ALL_VALUE} ${OMW_ADD_EXE_UNPARSED_ARGUMENTS}) if (MSVC) From 97ff24b8d6ffcbbb80b52725358ed8a683712c28 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 10 Sep 2017 20:48:09 +0300 Subject: [PATCH 148/521] Change ctl to ctrl in OpenMW-CS shortcut manager --- apps/opencs/model/prefs/shortcutmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 6ae778fff..c4b46958d 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -132,7 +132,7 @@ namespace CSMPrefs if (mods && i == 0) { if (mods & Qt::ControlModifier) - result.append("Ctl+"); + result.append("Ctrl+"); if (mods & Qt::ShiftModifier) result.append("Shift+"); if (mods & Qt::AltModifier) @@ -196,7 +196,7 @@ namespace CSMPrefs std::string name = value.substr(start, end - start); - if (name == "Ctl") + if (name == "Ctrl") { mods |= Qt::ControlModifier; } From c6fd75bf42cd3a167282107329e79bef5053d51a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 14:21:05 +0400 Subject: [PATCH 149/521] Take in account elemental shields for GetResist and SetResist script commands (bug #4093) --- apps/openmw/mwscript/statsextensions.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 6b1953917..70910ec2f 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1189,6 +1189,14 @@ namespace MWScript if (mNegativeEffect != -1) currentValue -= effects.get(mNegativeEffect).getMagnitude(); + // GetResist* should take in account elemental shields + if (mPositiveEffect == ESM::MagicEffect::ResistFire) + currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistShock) + currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistFrost) + currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude(); + int ret = static_cast(currentValue); runtime.push(ret); } @@ -1215,6 +1223,14 @@ namespace MWScript if (mNegativeEffect != -1) currentValue -= effects.get(mNegativeEffect).getMagnitude(); + // SetResist* should take in account elemental shields + if (mPositiveEffect == ESM::MagicEffect::ResistFire) + currentValue += effects.get(ESM::MagicEffect::FireShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistShock) + currentValue += effects.get(ESM::MagicEffect::LightningShield).getMagnitude(); + if (mPositiveEffect == ESM::MagicEffect::ResistFrost) + currentValue += effects.get(ESM::MagicEffect::FrostShield).getMagnitude(); + int arg = runtime[0].mInteger; runtime.pop(); effects.modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); From 7760e4514c767e266bd72697567f4b9868653ed8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 10 Sep 2017 22:47:34 +0400 Subject: [PATCH 150/521] Allow to add levelup a description for levels > 20 --- apps/openmw/mwgui/levelupdialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 362ad3b1c..da8e93279 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -143,10 +143,10 @@ namespace MWGui mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level)); std::string levelupdescription; - if(level > 20) + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); + + if (levelupdescription == "") levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); - else - levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+MyGUI::utility::toString(level)); mLevelDescription->setCaption (levelupdescription); From 5904e5a267741c230cee1b2bb258693ed7781d48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Sep 2017 10:47:35 +0200 Subject: [PATCH 151/521] updated credits file --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index bb773c4ef..d9782ccf3 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -34,6 +34,7 @@ Programmers Ben Shealy (bentsherman) Bret Curtis (psi29a) Britt Mathis (galdor557) + Capostrophic cc9cii Chris Boyce (slothlife) Chris Robinson (KittyCat) From 7e83caab11c5ad3b1cc2935bf9fb71811b095c5c Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Wed, 13 Sep 2017 12:11:01 +0100 Subject: [PATCH 152/521] Manual modding - extend mod installation instructions (#1448) Add section on .bsa files Extend plugins to include .esm files Fix typo propper->proper. --- docs/source/manuals/openmw-cs/tour.rst | 2 -- docs/source/reference/modding/mod-install.rst | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index bb1097e0c..b1b147992 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -219,5 +219,3 @@ Subsection to come... ===================== - - diff --git a/docs/source/reference/modding/mod-install.rst b/docs/source/reference/modding/mod-install.rst index a72678173..e62c27fc1 100644 --- a/docs/source/reference/modding/mod-install.rst +++ b/docs/source/reference/modding/mod-install.rst @@ -9,7 +9,7 @@ Install #. Your mod probably comes in some kind of archive, such as ``.zip``, ``.rar``, ``.7z``, or something along those lines. Unpack this archive into its own folder. #. Ensure the structure of this folder is correct. - #. Locate the plugin files, ``.esp`` or ``.omwaddon``. The folder containing the plugin files we will call your *data folder* + #. Locate the plugin files, ``.esp`` or ``.omwaddon``, or possibly ``.esm``. The folder containing the plugin files we will call your *data folder* #. Check that all resource folders (``Meshes``, ``Textures``, etc.) containing additional resource files (the actual meshes, textures, etc.) are in the *data folder*. .. note:: @@ -18,9 +18,10 @@ Install #. Open your ``openmw.cfg`` file in your preferred plain text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory. #. Find or search for ``data=``. This is located very near the bottom of the file. If you are using Morrowind, this first entry should already point to your Morrowind data directory, ``Data Files``; otherwise it will point to your game file, ``.omwgame``. #. Create a new line underneath and type: ``data="path/to/your/data folder"`` Remember, the *data folder* is where your mod's plugin files are. The double quotes around this path name are *required*. +#. If your mod contains resources in a ``.bsa`` file, go to near the top of the file, locate the entries like ''fallback-archive=Morrowind.bsa'' and create a new line underneath and type: ``fallback-archive=.bsa''``. .. note:: - Some text editors, such as TextEdit on Mac, will autocorrect your double quotes to typographical "curly" quotes instead of leaving them as the propper neutral vertical quotes ``""``. + Some text editors, such as TextEdit on Mac, will autocorrect your double quotes to typographical "curly" quotes instead of leaving them as the proper neutral vertical quotes ``""``. #. Save your ``openmw.cfg`` file. From b9de4b1eac5b77708f36c71ca1185d89e7a9665a Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Wed, 13 Sep 2017 12:27:51 +0100 Subject: [PATCH 153/521] Update tour.rst --- docs/source/manuals/openmw-cs/tour.rst | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index b1b147992..fedd42462 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -218,4 +218,89 @@ actually modify the contents of the game. Subsection to come... ===================== +Adding to an npc +**************** + +The simplest way is probably to add it to the inventory of a shopkeeper. +An obvious candidate is Arrille in Seyda Neen - he's quick to find in a new game +and he's easy to find in the CS as his name comes early alphabetically. + +.. figure:: _static/images/chapter-1/Ring_to_Arrille.png + :alt: Putting the ring into Arrille's inventory + +Open the CS and open the *Objects* table (*World* → *Objects*). +Scroll down to Arrille, or use a filter like !string("ID","arrille"). + +Open another pane to edit him - either right click and select edit or use the +shortcut (default is shift double-click). Scroll down to the inventory section +and right click to add a new row. Type in the id of the ring (or find it in the +object pane, and drag and drop). Set the number of rings for him to stock - with +a negative number indicating that he will restock again to maintain that level. + +However, it's an attractive item, so he will probably wear it rather than sell it. +So set his stock level too high for him to wear them all (3 works, 2 might do). + +Another possibilty, again in Seyda Neen making it easy to access, would be for +Fargoth to give it to the player in exchange for his healing ring. + +.. figure:: _static/images/chapter-1/Ring_to_Fargoth_1.png + :alt: Editing Fargoth to give ring to player + +Open the *Topicinfo* Table (*Characters* → *Topic Infos*). Use a filter !string(Topic,ring) +and select the row with a response starting with "You found it!". Edit the record, +firstly by adding a bit more to the response, then by adding a line to the script +to give the ring to the player - the same as used earlier in the console +.. code:: + + player->AddItem "ring_night_vision" 1 + +.. figure:: _static/images/chapter-1/Ring_to_Fargoth_2.png + :alt: Editing Fargoth to give ring to player + +Navigation in the CS +==================== +This is probably a suitable place to start talking about how navigation differs from TESCS +in vanilla Morrowind. + +There is advice in Scripting for Dummies, the definitive manual for Morrowind Scripting: +"If you give your scripts a common tag, that will make it easier to jump between the +different scripts of your project, e.g. start every script name with AA_Scriptname +this will put them right at the beginning of the list and keep them neatly together." + +This is valid for the rather poorer navigation facilities there, but it's not sensible for +the OpenMW CS. Some modders took it further, and started script names and object id with numbers, +typically "1", to bring the items even earlier in the default alphabetical sorts. In fact +the CS won't allow names/ids to start with numbers or to include ".". + +There are better options available: + +Filtering, which isn't available at all in TESCS - put in a filter like + +!string("ID",".*ring.*") + +to find all IDs which contain the string "ring" + +Sorting, which is available in some parts of TESCS, but not for scripts (other than script names being +sorted in ascending order)- hence the recommendation +Typically the "Modified" column is useful here - most items will have "Base" status, unchanged from +the base game. + +"Added" status" will cover those items added in this addon. + +"Modified" status will cover items from the base game which have been modified in this addon. + +Click on the top of the column to toggle between ascending and descending order - thus between "Added" +and "Modified" at the top. Or put your desired modified status into a filter then sort alpabetically +on a different column. + + + +Checking your new addon +======================= + +Launch OpenMW and in the launcher under *Data Files* check your addon, if it's not +already checked. Load a game and make your way to Seyda Neen - or start a new game. + +Check whether Arrille has one (or more) for sale, and whether Fargoth give you one +when you return his healing ring. From b26887ef9bd49cf2fc3dab700605e16aea0a0811 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Sep 2017 13:52:05 +0200 Subject: [PATCH 154/521] add support for png and dds splashscreens to begin with. --- apps/openmw/mwgui/loadingscreen.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index c5836b653..946751f68 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -65,16 +65,26 @@ namespace MWGui const std::map& index = mVFS->getIndex(); std::string pattern = "Splash/"; mVFS->normalizeFilename(pattern); + std::list supported_extensions = {".tga", ".png", ".dds"}; /* priority given to the left */ - std::map::const_iterator found = index.lower_bound(pattern); + auto found = index.lower_bound(pattern); while (found != index.end()) { const std::string& name = found->first; if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) { size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".tga") == 0) - mSplashScreens.push_back(found->first); + if (pos != std::string::npos) + { + for(auto const extension: supported_extensions) + { + if (name.compare(pos, name.size() - pos, extension) == 0) + { + mSplashScreens.push_back(found->first); + break; /* based on priority */ + } + } + } } else break; From dff0a766a8b5435b5a01d3bc9771f6c62bf140d1 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 13 Sep 2017 15:30:22 +0200 Subject: [PATCH 155/521] adding 3 more extensions --- apps/openmw/mwgui/loadingscreen.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 946751f68..41d7efb41 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -65,7 +65,9 @@ namespace MWGui const std::map& index = mVFS->getIndex(); std::string pattern = "Splash/"; mVFS->normalizeFilename(pattern); - std::list supported_extensions = {".tga", ".png", ".dds"}; /* priority given to the left */ + + /* priority given to the left */ + std::list supported_extensions = {".tga", ".dds", ".png", ".bmp", ".jpeg", ".jpg"}; auto found = index.lower_bound(pattern); while (found != index.end()) From e517ad3f7b5630c342e60bcf2087da4165359baa Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 14 Sep 2017 10:06:36 +0200 Subject: [PATCH 156/521] add ktx support for splashscreens --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 41d7efb41..15d9d555f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -67,7 +67,7 @@ namespace MWGui mVFS->normalizeFilename(pattern); /* priority given to the left */ - std::list supported_extensions = {".tga", ".dds", ".png", ".bmp", ".jpeg", ".jpg"}; + std::list supported_extensions = {".tga", ".dds", ".ktx", ".png", ".bmp", ".jpeg", ".jpg"}; auto found = index.lower_bound(pattern); while (found != index.end()) From 6e869c3123cd4879348b25d1167c62a6ea90bca4 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 12 Sep 2017 21:11:30 +0200 Subject: [PATCH 157/521] ESS-Importer: Convert ballistic projectiles (Feature #2320) --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 84 ++++++++++++++++++++++++++-- apps/essimporter/converter.hpp | 12 ++++ apps/essimporter/importer.cpp | 14 +++++ apps/essimporter/importercontext.hpp | 10 ++++ apps/essimporter/importproj.cpp | 18 ++++++ apps/essimporter/importproj.h | 47 ++++++++++++++++ 7 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 apps/essimporter/importproj.cpp create mode 100644 apps/essimporter/importproj.h diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 82182b7fa..fc5fae72e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -16,6 +16,7 @@ set(ESSIMPORTER_FILES importjour.cpp importscri.cpp importscpt.cpp + importproj.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 68ee93c89..5c65332be 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "convertcrec.hpp" #include "convertcntc.hpp" @@ -53,6 +54,36 @@ namespace return true; return false; } + + void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId) + { + std::stringstream stream; + stream << std::hex << indexedRefId.substr(indexedRefId.size()-8,8); + stream >> refIndex; + + refId = indexedRefId.substr(0,indexedRefId.size()-8); + } + + int convertActorId(const std::string& indexedRefId, ESSImport::Context& context) + { + if (isIndexedRefId(indexedRefId)) + { + int refIndex; + std::string refId; + splitIndexedRefId(indexedRefId, refIndex, refId); + + auto it = context.mActorIdMap.find(std::make_pair(refIndex, refId)); + if (it == context.mActorIdMap.end()) + return -1; + return it->second; + } + else if (indexedRefId == "PlayerSaveGame") + { + return context.mPlayer.mObject.mCreatureStats.mActorId; + } + + return -1; + } } namespace ESSImport @@ -322,12 +353,9 @@ namespace ESSImport } else { - std::stringstream stream; - stream << std::hex << cellref.mIndexedRefId.substr(cellref.mIndexedRefId.size()-8,8); int refIndex; - stream >> refIndex; + splitIndexedRefId(cellref.mIndexedRefId, refIndex, out.mRefID); - out.mRefID = cellref.mIndexedRefId.substr(0,cellref.mIndexedRefId.size()-8); std::string idLower = Misc::StringUtils::lowerCase(out.mRefID); std::map, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find( @@ -347,6 +375,10 @@ namespace ESSImport convertNpcData(cellref, objstate.mNpcStats); convertNPCC(npccIt->second, objstate); convertCellRef(cellref, objstate); + + objstate.mCreatureStats.mActorId = mContext->generateActorId(); + mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId)); + esm.writeHNT ("OBJE", ESM::REC_NPC_); objstate.save(esm); continue; @@ -383,6 +415,10 @@ namespace ESSImport convertACSC(cellref.mACSC, objstate.mCreatureStats); convertCREC(crecIt->second, objstate); convertCellRef(cellref, objstate); + + objstate.mCreatureStats.mActorId = mContext->generateActorId(); + mContext->mActorIdMap.insert(std::make_pair(std::make_pair(refIndex, out.mRefID), objstate.mCreatureStats.mActorId)); + esm.writeHNT ("OBJE", ESM::REC_CREA); objstate.save(esm); continue; @@ -413,4 +449,44 @@ namespace ESSImport } } + void ConvertPROJ::read(ESM::ESMReader& esm) + { + mProj.load(esm); + } + + void ConvertPROJ::write(ESM::ESMWriter& esm) + { + for (const PROJ::PNAM& pnam : mProj.mProjectiles) + { + if (!pnam.isMagic()) + { + ESM::ProjectileState out; + out.mId = pnam.mArrowId.toString(); + out.mPosition = pnam.mPosition; + out.mOrientation.mValues[0] = out.mOrientation.mValues[1] = out.mOrientation.mValues[2] = 0.0f; + out.mOrientation.mValues[3] = 1.0f; + out.mActorId = convertActorId(pnam.mActorId.toString(), *mContext); + + out.mBowId = pnam.mBowId.toString(); + out.mVelocity = pnam.mVelocity; + out.mAttackStrength = pnam.mAttackStrength; + + esm.startRecord(ESM::REC_PROJ); + out.save(esm); + esm.endRecord(ESM::REC_PROJ); + } + else + { + // TODO: Implement magic projectile conversion. + + /*esm.startRecord(ESM::REC_MPRJ); + out.save(esm); + esm.endRecord(ESM::REC_MPRJ);*/ + + std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl; + continue; + } + } + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index e4985f993..a640d6756 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -35,6 +35,7 @@ #include "importques.hpp" #include "importjour.hpp" #include "importscpt.hpp" +#include "importproj.h" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -593,6 +594,17 @@ private: std::vector mScripts; }; +/// Projectile converter +class ConvertPROJ : public Converter +{ +public: + virtual int getStage() override { return 2; } + virtual void read(ESM::ESMReader& esm) override; + virtual void write(ESM::ESMWriter& esm) override; +private: + PROJ mProj; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index d38069d89..4c8222c56 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -303,6 +303,7 @@ namespace ESSImport converters[ESM::REC_QUES] = std::shared_ptr(new ConvertQUES()); converters[recJOUR ] = std::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = std::shared_ptr(new ConvertSCPT()); + converters[ESM::REC_PROJ] = std::shared_ptr(new ConvertPROJ()); // TODO: // - REGN (weather in certain regions?) @@ -420,6 +421,19 @@ namespace ESSImport context.mPlayer.save(writer); writer.endRecord(ESM::REC_PLAY); + writer.startRecord(ESM::REC_ACTC); + writer.writeHNT("COUN", context.mNextActorId); + writer.endRecord(ESM::REC_ACTC); + + // Stage 2 requires cell references to be written / actors IDs assigned + for (std::map >::const_iterator it = converters.begin(); + it != converters.end(); ++it) + { + if (it->second->getStage() != 2) + continue; + it->second->write(writer); + } + writer.startRecord (ESM::REC_DIAS); context.mDialogueState.save(writer); writer.endRecord(ESM::REC_DIAS); diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 0ad73c267..eb6ca9336 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -48,6 +48,9 @@ namespace ESSImport std::map, NPCC> mNpcChanges; std::map, CNTC> mContainerChanges; + std::map, int> mActorIdMap; + int mNextActorId; + std::map mCreatures; std::map mNpcs; @@ -56,6 +59,7 @@ namespace ESSImport , mMonth(0) , mYear(0) , mHour(0.f) + , mNextActorId(0) { mPlayer.mAutoMove = 0; ESM::CellId playerCellId; @@ -71,12 +75,18 @@ namespace ESSImport mPlayer.mObject.blank(); mPlayer.mObject.mEnabled = true; mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame + mPlayer.mObject.mCreatureStats.mActorId = generateActorId(); mGlobalMapState.mBounds.mMinX = 0; mGlobalMapState.mBounds.mMaxX = 0; mGlobalMapState.mBounds.mMinY = 0; mGlobalMapState.mBounds.mMaxY = 0; } + + int generateActorId() + { + return mNextActorId++; + } }; } diff --git a/apps/essimporter/importproj.cpp b/apps/essimporter/importproj.cpp new file mode 100644 index 000000000..b2dcf4e7d --- /dev/null +++ b/apps/essimporter/importproj.cpp @@ -0,0 +1,18 @@ +#include "importproj.h" + +#include + +namespace ESSImport +{ + +void ESSImport::PROJ::load(ESM::ESMReader& esm) +{ + while (esm.isNextSub("PNAM")) + { + PNAM pnam; + esm.getHT(pnam); + mProjectiles.push_back(pnam); + } +} + +} diff --git a/apps/essimporter/importproj.h b/apps/essimporter/importproj.h new file mode 100644 index 000000000..b8abab5fa --- /dev/null +++ b/apps/essimporter/importproj.h @@ -0,0 +1,47 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTPROJ_H +#define OPENMW_ESSIMPORT_IMPORTPROJ_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + +struct PROJ +{ + +#pragma pack(push) +#pragma pack(1) + struct PNAM // 184 bytes + { + float mAttackStrength; + float mSpeed; + unsigned char mUnknown[4*2]; + float mFlightTime; + int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles) + unsigned char mUnknown2[4]; + ESM::Vector3 mVelocity; + ESM::Vector3 mPosition; + unsigned char mUnknown3[4*9]; + ESM::NAME32 mActorId; // indexed refID (with the exception of "PlayerSaveGame") + ESM::NAME32 mArrowId; + ESM::NAME32 mBowId; + + bool isMagic() const { return mSplmIndex != 0; } + }; +#pragma pack(pop) + + std::vector mProjectiles; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif From a66d310a1d1d266da479b3e4fe7a3d35b94ce325 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 15 Sep 2017 00:21:02 +0200 Subject: [PATCH 158/521] ESS-Importer: Fix uninitialized paid crime ID --- apps/essimporter/importercontext.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index eb6ca9336..4896f5594 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -71,7 +71,8 @@ namespace ESSImport = mPlayer.mLastKnownExteriorPosition[2] = 0.0f; mPlayer.mHasMark = 0; - mPlayer.mCurrentCrimeId = 0; // TODO + mPlayer.mCurrentCrimeId = -1; // TODO + mPlayer.mPaidCrimeId = -1; mPlayer.mObject.blank(); mPlayer.mObject.mEnabled = true; mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame From 1fe60dd8e23ffe34c6ddad66b4829f3a4253e38f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 11 Sep 2017 21:33:18 -0700 Subject: [PATCH 159/521] Replace some shared_ptrs with pointers to deque entries --- apps/openmw/mwbase/soundmanager.hpp | 29 ++-- apps/openmw/mwsound/movieaudiofactory.cpp | 12 +- apps/openmw/mwsound/openal_output.cpp | 26 +-- apps/openmw/mwsound/openal_output.hpp | 33 ++-- apps/openmw/mwsound/sound.hpp | 46 +++-- apps/openmw/mwsound/sound_output.hpp | 29 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 202 ++++++++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 44 +++-- apps/openmw/mwworld/projectilemanager.cpp | 6 +- apps/openmw/mwworld/projectilemanager.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 8 +- apps/openmw/mwworld/weather.hpp | 2 +- 12 files changed, 262 insertions(+), 177 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9aa4bafdf..9986564cd 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -22,8 +22,8 @@ namespace MWSound namespace MWBase { - typedef std::shared_ptr SoundPtr; - typedef std::shared_ptr SoundStreamPtr; + using Sound = MWSound::Sound; + using SoundStream = MWSound::Stream; /// \brief Interface for sound manager (implemented in MWSound) class SoundManager @@ -106,34 +106,35 @@ namespace MWBase /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual SoundStreamPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; + virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(SoundStreamPtr stream) = 0; + virtual void stopTrack(SoundStream *stream) = 0; ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(SoundStreamPtr stream) = 0; + virtual double getTrackTimeDelay(SoundStream *stream) = 0; ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. - virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, - PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, - float offset=0) = 0; + virtual Sound *playSound(const std::string& soundId, float volume, float pitch, + PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, + float offset=0) = 0; ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0) = 0; + virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, + PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0) = 0; + virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, + PlayMode mode=Play_Normal, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. - virtual void stopSound(SoundPtr sound) = 0; + virtual void stopSound(Sound *sound) = 0; ///< Stop the given sound from playing virtual void stopSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId) = 0; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 2d7f3a969..9c9b442c7 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -37,7 +37,7 @@ namespace MWSound { public: MovieAudioDecoder(Video::VideoState *videoState) - : Video::MovieAudioDecoder(videoState) + : Video::MovieAudioDecoder(videoState), mAudioTrack(nullptr) { mDecoderBridge.reset(new MWSoundDecoderBridge(this)); } @@ -85,13 +85,13 @@ namespace MWSound public: ~MovieAudioDecoder() { - if(mAudioTrack.get()) + if(mAudioTrack) MWBase::Environment::get().getSoundManager()->stopTrack(mAudioTrack); - mAudioTrack.reset(); + mAudioTrack = nullptr; mDecoderBridge.reset(); } - MWBase::SoundStreamPtr mAudioTrack; + MWBase::SoundStream *mAudioTrack; std::shared_ptr mDecoderBridge; }; @@ -162,8 +162,8 @@ namespace MWSound decoder->setupFormat(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundStreamPtr sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); - if (!sound.get()) + MWBase::SoundStream *sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); + if (!sound) { decoder.reset(); return decoder; diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 042795a8c..0e000f8d8 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -841,7 +841,7 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m } -void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) +void OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) { ALuint source; @@ -871,7 +871,7 @@ void OpenAL_Output::playSound(MWBase::SoundPtr sound, Sound_Handle data, float o sound->mHandle = MAKE_PTRID(source); } -void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) +void OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) { ALuint source; @@ -902,7 +902,7 @@ void OpenAL_Output::playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float sound->mHandle = MAKE_PTRID(source); } -void OpenAL_Output::finishSound(MWBase::SoundPtr sound) +void OpenAL_Output::finishSound(Sound *sound) { if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); @@ -918,7 +918,7 @@ void OpenAL_Output::finishSound(MWBase::SoundPtr sound) mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); } -bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) +bool OpenAL_Output::isSoundPlaying(Sound *sound) { if(!sound->mHandle) return false; ALuint source = GET_PTRID(sound->mHandle); @@ -930,7 +930,7 @@ bool OpenAL_Output::isSoundPlaying(MWBase::SoundPtr sound) return state == AL_PLAYING || state == AL_PAUSED; } -void OpenAL_Output::updateSound(MWBase::SoundPtr sound) +void OpenAL_Output::updateSound(Sound *sound) { if(!sound->mHandle) return; ALuint source = GET_PTRID(sound->mHandle); @@ -940,7 +940,7 @@ void OpenAL_Output::updateSound(MWBase::SoundPtr sound) } -void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) +void OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound) { OpenAL_SoundStream *stream = 0; ALuint source; @@ -971,7 +971,7 @@ void OpenAL_Output::streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound sound->mHandle = stream; } -void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData) +void OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) { OpenAL_SoundStream *stream = 0; ALuint source; @@ -1002,7 +1002,7 @@ void OpenAL_Output::streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sou sound->mHandle = stream; } -void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound) +void OpenAL_Output::finishStream(Stream *sound) { if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1023,14 +1023,14 @@ void OpenAL_Output::finishStream(MWBase::SoundStreamPtr sound) delete stream; } -double OpenAL_Output::getStreamDelay(MWBase::SoundStreamPtr sound) +double OpenAL_Output::getStreamDelay(Stream *sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); return stream->getStreamDelay(); } -double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) +double OpenAL_Output::getStreamOffset(Stream *sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1038,7 +1038,7 @@ double OpenAL_Output::getStreamOffset(MWBase::SoundStreamPtr sound) return stream->getStreamOffset(); } -float OpenAL_Output::getStreamLoudness(MWBase::SoundStreamPtr sound) +float OpenAL_Output::getStreamLoudness(Stream *sound) { if(!sound->mHandle) return 0.0; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1046,7 +1046,7 @@ float OpenAL_Output::getStreamLoudness(MWBase::SoundStreamPtr sound) return stream->getCurrentLoudness(); } -bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) +bool OpenAL_Output::isStreamPlaying(Stream *sound) { if(!sound->mHandle) return false; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); @@ -1054,7 +1054,7 @@ bool OpenAL_Output::isStreamPlaying(MWBase::SoundStreamPtr sound) return stream->isPlaying(); } -void OpenAL_Output::updateStream(MWBase::SoundStreamPtr sound) +void OpenAL_Output::updateStream(Stream *sound) { if(!sound->mHandle) return; OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index ea3f393ff..cb943d87e 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -15,6 +15,7 @@ namespace MWSound { class SoundManager; class Sound; + class Stream; class OpenAL_Output : public Sound_Output { @@ -24,9 +25,9 @@ namespace MWSound typedef std::deque IDDq; IDDq mFreeSources; - typedef std::vector SoundVec; + typedef std::vector SoundVec; SoundVec mActiveSounds; - typedef std::vector StreamVec; + typedef std::vector StreamVec; StreamVec mActiveStreams; osg::Vec3f mListenerPos; @@ -56,20 +57,20 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset); - virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset); - virtual void finishSound(MWBase::SoundPtr sound); - virtual bool isSoundPlaying(MWBase::SoundPtr sound); - virtual void updateSound(MWBase::SoundPtr sound); - - virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound); - virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData); - virtual void finishStream(MWBase::SoundStreamPtr sound); - virtual double getStreamDelay(MWBase::SoundStreamPtr sound); - virtual double getStreamOffset(MWBase::SoundStreamPtr sound); - virtual float getStreamLoudness(MWBase::SoundStreamPtr sound); - virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound); - virtual void updateStream(MWBase::SoundStreamPtr sound); + virtual void playSound(Sound *sound, Sound_Handle data, float offset); + virtual void playSound3D(Sound *sound, Sound_Handle data, float offset); + virtual void finishSound(Sound *sound); + virtual bool isSoundPlaying(Sound *sound); + virtual void updateSound(Sound *sound); + + virtual void streamSound(DecoderPtr decoder, Stream *sound); + virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData); + virtual void finishStream(Stream *sound); + virtual double getStreamDelay(Stream *sound); + virtual double getStreamOffset(Stream *sound); + virtual float getStreamLoudness(Stream *sound); + virtual bool isStreamPlaying(Stream *sound); + virtual void updateStream(Stream *sound); virtual void startUpdate(); virtual void finishUpdate(); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 8c663fb1e..9a3fc4e75 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -54,15 +54,36 @@ namespace MWSound bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } - Sound(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : mPos(pos), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) - , mMinDistance(mindist), mMaxDistance(maxdist), mFlags(flags) - , mFadeOutTime(0.0f), mHandle(0) - { } - Sound(float vol, float basevol, float pitch, int flags) - : mPos(0.0f, 0.0f, 0.0f), mVolume(vol), mBaseVolume(basevol), mPitch(pitch) - , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(flags) - , mFadeOutTime(0.0f), mHandle(0) + void init(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + { + mPos = pos; + mVolume = vol; + mBaseVolume = basevol; + mPitch = pitch; + mMinDistance = mindist; + mMaxDistance = maxdist; + mFlags = flags; + mFadeOutTime = 0.0f; + mHandle = nullptr; + } + + void init(float vol, float basevol, float pitch, int flags) + { + mPos = osg::Vec3f(0.0f, 0.0f, 0.0f); + mVolume = vol; + mBaseVolume = basevol; + mPitch = pitch; + mMinDistance = 1.0f; + mMaxDistance = 1000.0f; + mFlags = flags; + mFadeOutTime = 0.0f; + mHandle = nullptr; + } + + Sound() + : mPos(0.0f, 0.0f, 0.0f), mVolume(1.0f), mBaseVolume(1.0f), mPitch(1.0f) + , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(0), mFadeOutTime(0.0f) + , mHandle(0) { } }; @@ -72,12 +93,7 @@ namespace MWSound Stream(const Stream &rhs); public: - Stream(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) - : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) - { } - Stream(float vol, float basevol, float pitch, int flags) - : Sound(vol, basevol, pitch, flags) - { } + Stream() { } }; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index e34d888ee..907a601b5 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -12,6 +12,7 @@ namespace MWSound class SoundManager; struct Sound_Decoder; class Sound; + class Stream; // An opaque handle for the implementation's sound buffers. typedef void *Sound_Handle; @@ -34,20 +35,20 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - virtual void playSound(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; - virtual void playSound3D(MWBase::SoundPtr sound, Sound_Handle data, float offset) = 0; - virtual void finishSound(MWBase::SoundPtr sound) = 0; - virtual bool isSoundPlaying(MWBase::SoundPtr sound) = 0; - virtual void updateSound(MWBase::SoundPtr sound) = 0; - - virtual void streamSound(DecoderPtr decoder, MWBase::SoundStreamPtr sound) = 0; - virtual void streamSound3D(DecoderPtr decoder, MWBase::SoundStreamPtr sound, bool getLoudnessData) = 0; - virtual void finishStream(MWBase::SoundStreamPtr sound) = 0; - virtual double getStreamDelay(MWBase::SoundStreamPtr sound) = 0; - virtual double getStreamOffset(MWBase::SoundStreamPtr sound) = 0; - virtual float getStreamLoudness(MWBase::SoundStreamPtr sound) = 0; - virtual bool isStreamPlaying(MWBase::SoundStreamPtr sound) = 0; - virtual void updateStream(MWBase::SoundStreamPtr sound) = 0; + virtual void playSound(Sound *sound, Sound_Handle data, float offset) = 0; + virtual void playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; + virtual void finishSound(Sound *sound) = 0; + virtual bool isSoundPlaying(Sound *sound) = 0; + virtual void updateSound(Sound *sound) = 0; + + virtual void streamSound(DecoderPtr decoder, Stream *sound) = 0; + virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0; + virtual void finishStream(Stream *sound) = 0; + virtual double getStreamDelay(Stream *sound) = 0; + virtual double getStreamOffset(Stream *sound) = 0; + virtual float getStreamLoudness(Stream *sound) = 0; + virtual bool isStreamPlaying(Stream *sound) = 0; + virtual void updateStream(Stream *sound) = 0; virtual void startUpdate() = 0; virtual void finishUpdate() = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 15b95b233..f8b753a18 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -46,11 +46,16 @@ namespace MWSound , mFootstepsVolume(1.0f) , mSoundBuffers(new SoundBufferList::element_type()) , mBufferCacheSize(0) + , mSounds(new std::deque()) + , mStreams(new std::deque()) + , mMusic(nullptr) , mListenerUnderwater(false) , mListenerPos(0,0,0) , mListenerDir(1,0,0) , mListenerUp(0,0,1) , mPausedSoundTypes(0) + , mUnderwaterSound(nullptr) + , mNearWaterSound(nullptr) { mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); @@ -246,7 +251,39 @@ namespace MWSound return decoder; } - MWBase::SoundStreamPtr SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) + Sound *SoundManager::getSoundRef() + { + Sound *ret; + if(!mUnusedSounds.empty()) + { + ret = mUnusedSounds.back(); + mUnusedSounds.pop_back(); + } + else + { + mSounds->emplace_back(); + ret = &mSounds->back(); + } + return ret; + } + + Stream *SoundManager::getStreamRef() + { + Stream *ret; + if(!mUnusedStreams.empty()) + { + ret = mUnusedStreams.back(); + mUnusedStreams.pop_back(); + } + else + { + mStreams->emplace_back(); + ret = &mStreams->back(); + } + return ret; + } + + Stream *SoundManager::playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal) { MWBase::World* world = MWBase::Environment::get().getWorld(); static const float fAudioMinDistanceMult = world->getStore().get().find("fAudioMinDistanceMult")->getFloat(); @@ -256,17 +293,17 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); - MWBase::SoundStreamPtr sound; float basevol = volumeFromType(Play_TypeVoice); + Stream *sound = getStreamRef(); if(playlocal) { - sound.reset(new Stream(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D)); + sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D); mOutput->streamSound(decoder, sound); } else { - sound.reset(new Stream(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D)); + sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, + Play_Normal|Play_TypeVoice|Play_3D); mOutput->streamSound3D(decoder, sound, true); } return sound; @@ -301,8 +338,11 @@ namespace MWSound void SoundManager::stopMusic() { if(mMusic) + { mOutput->finishStream(mMusic); - mMusic.reset(); + mUnusedStreams.push_back(mMusic); + mMusic = nullptr; + } } void SoundManager::streamMusicFull(const std::string& filename) @@ -317,13 +357,16 @@ namespace MWSound DecoderPtr decoder = getDecoder(); decoder->open(filename); - mMusic.reset(new Stream(1.0f, volumeFromType(Play_TypeMusic), 1.0f, - Play_NoEnv|Play_TypeMusic|Play_2D)); + mMusic = getStreamRef(); + mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, + Play_NoEnv|Play_TypeMusic|Play_2D); mOutput->streamSound(decoder, mMusic); } catch(std::exception &e) { std::cout << "Music Error: " << e.what() << "\n"; - mMusic.reset(); + if(mMusic) + mUnusedStreams.push_back(mMusic); + mMusic = nullptr; } } @@ -421,15 +464,8 @@ namespace MWSound MWBase::World *world = MWBase::Environment::get().getWorld(); const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); - SaySoundMap::iterator oldIt = mActiveSaySounds.find(ptr); - if (oldIt != mActiveSaySounds.end()) - { - mOutput->finishStream(oldIt->second); - mActiveSaySounds.erase(oldIt); - } - - MWBase::SoundStreamPtr sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); - + stopSay(ptr); + Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); mActiveSaySounds.insert(std::make_pair(ptr, sound)); } catch(std::exception &e) @@ -443,7 +479,7 @@ namespace MWSound SaySoundMap::const_iterator snditer = mActiveSaySounds.find(ptr); if(snditer != mActiveSaySounds.end()) { - MWBase::SoundStreamPtr sound = snditer->second; + Stream *sound = snditer->second; return mOutput->getStreamLoudness(sound); } @@ -461,13 +497,7 @@ namespace MWSound mVFS->normalizeFilename(voicefile); DecoderPtr decoder = loadVoice(voicefile); - SaySoundMap::iterator oldIt = mActiveSaySounds.find(MWWorld::ConstPtr()); - if (oldIt != mActiveSaySounds.end()) - { - mOutput->finishStream(oldIt->second); - mActiveSaySounds.erase(oldIt); - } - + stopSay(MWWorld::ConstPtr()); mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), playVoice(decoder, osg::Vec3f(), true))); } @@ -495,19 +525,20 @@ namespace MWSound if(snditer != mActiveSaySounds.end()) { mOutput->finishStream(snditer->second); + mUnusedStreams.push_back(snditer->second); mActiveSaySounds.erase(snditer); } } - MWBase::SoundStreamPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) + Stream *SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) { - MWBase::SoundStreamPtr track; if(!mOutput->isInitialized()) - return track; + return nullptr; + Stream *track = getStreamRef(); try { - track.reset(new Stream(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D)); + track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); mOutput->streamSound(decoder, track); TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); @@ -516,35 +547,40 @@ namespace MWSound catch(std::exception &e) { std::cout <<"Sound Error: "<finishStream(stream); TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), stream); if(iter != mActiveTracks.end() && *iter == stream) mActiveTracks.erase(iter); + mUnusedStreams.push_back(stream); } - double SoundManager::getTrackTimeDelay(MWBase::SoundStreamPtr stream) + double SoundManager::getTrackTimeDelay(Stream *stream) { return mOutput->getStreamDelay(stream); } - MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) + Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) { - MWBase::SoundPtr sound; if(!mOutput->isInitialized()) - return sound; + return nullptr; + Sound *sound = nullptr; try { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + sound = getSoundRef(); + sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); mOutput->playSound(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { @@ -557,17 +593,20 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<isInitialized()) - return sound; + return nullptr; + Sound *sound = nullptr; try { // Look up the sound in the ESM data @@ -577,20 +616,21 @@ namespace MWSound const osg::Vec3f objpos(pos.asVec3()); if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - return MWBase::SoundPtr(); + return nullptr; // Only one copy of given sound can be played at time on ptr, so stop previous copy stopSound3D(ptr, soundId); + sound = getSoundRef(); if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) { - sound.reset(new Sound(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D)); + sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); mOutput->playSound(sound, sfx->mHandle, offset); } else { - sound.reset(new Sound(objpos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + sound->init(objpos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); mOutput->playSound3D(sound, sfx->mHandle, offset); } if(sfx->mUses++ == 0) @@ -604,25 +644,29 @@ namespace MWSound catch(std::exception&) { //std::cout <<"Sound Error: "<isInitialized()) - return sound; + return nullptr; + Sound *sound = nullptr; try { // Look up the sound in the ESM data Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); float basevol = volumeFromType(type); - sound.reset(new Sound(initialPos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D)); + sound = getSoundRef(); + sound->init(initialPos, volume * sfx->mVolume, basevol, pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); mOutput->playSound3D(sound, sfx->mHandle, offset); if(sfx->mUses++ == 0) { @@ -635,14 +679,16 @@ namespace MWSound catch(std::exception &) { //std::cout <<"Sound Error: "<finishSound(sound); } @@ -675,7 +721,7 @@ namespace MWSound void SoundManager::stopSound(const MWWorld::CellStore *cell) { SoundMap::iterator snditer = mActiveSounds.begin(); - while(snditer != mActiveSounds.end()) + for(;snditer != mActiveSounds.end();++snditer) { if(snditer->first != MWWorld::ConstPtr() && snditer->first != MWMechanics::getPlayer() && @@ -685,18 +731,14 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) mOutput->finishSound(sndidx->first); } - ++snditer; } SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - while(sayiter != mActiveSaySounds.end()) + for(;sayiter != mActiveSaySounds.end();++sayiter) { if(sayiter->first != MWWorld::ConstPtr() && sayiter->first != MWMechanics::getPlayer() && sayiter->first.getCell() == cell) - { mOutput->finishStream(sayiter->second); - } - ++sayiter; } } @@ -885,7 +927,7 @@ namespace MWSound if (volume == 0.0f) { mOutput->finishSound(mNearWaterSound); - mNearWaterSound.reset(); + mNearWaterSound = nullptr; } else { @@ -939,7 +981,7 @@ namespace MWSound else if(mUnderwaterSound) { mOutput->finishSound(mUnderwaterSound); - mUnderwaterSound.reset(); + mUnderwaterSound = nullptr; } mOutput->startUpdate(); @@ -960,7 +1002,7 @@ namespace MWSound while(sndidx != snditer->second.end()) { MWWorld::ConstPtr ptr = snditer->first; - MWBase::SoundPtr sound = sndidx->first; + Sound *sound = sndidx->first; if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -977,6 +1019,11 @@ namespace MWSound if(!mOutput->isSoundPlaying(sound)) { mOutput->finishSound(sound); + mUnusedSounds.push_back(sound); + if(sound == mUnderwaterSound) + mUnderwaterSound = nullptr; + if(sound == mNearWaterSound) + mNearWaterSound = nullptr; Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1000,7 +1047,7 @@ namespace MWSound while(sayiter != mActiveSaySounds.end()) { MWWorld::ConstPtr ptr = sayiter->first; - MWBase::SoundStreamPtr sound = sayiter->second; + Stream *sound = sayiter->second; if(!ptr.isEmpty() && sound->getIs3D()) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -1017,6 +1064,7 @@ namespace MWSound if(!mOutput->isStreamPlaying(sound)) { mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); mActiveSaySounds.erase(sayiter++); } else @@ -1031,10 +1079,11 @@ namespace MWSound TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) { - MWBase::SoundStreamPtr sound = *trkiter; + Stream *sound = *trkiter; if(!mOutput->isStreamPlaying(sound)) { mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); trkiter = mActiveTracks.erase(trkiter); } else @@ -1049,7 +1098,7 @@ namespace MWSound if(mListenerUnderwater) { // Play underwater sound (after updating sounds) - if(!(mUnderwaterSound && mOutput->isSoundPlaying(mUnderwaterSound))) + if(!mUnderwaterSound) mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); } mOutput->finishUpdate(); @@ -1105,7 +1154,7 @@ namespace MWSound SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); for(;sndidx != snditer->second.end();++sndidx) { - MWBase::SoundPtr sound = sndidx->first; + Sound *sound = sndidx->first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateSound(sound); } @@ -1113,14 +1162,14 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) { - MWBase::SoundStreamPtr sound = sayiter->second; + Stream *sound = sayiter->second; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) { - MWBase::SoundStreamPtr sound = *trkiter; + Stream *sound = *trkiter; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } @@ -1153,7 +1202,7 @@ namespace MWSound SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); if(sayiter != mActiveSaySounds.end()) { - MWBase::SoundStreamPtr stream = sayiter->second; + Stream *stream = sayiter->second; mActiveSaySounds.erase(sayiter); mActiveSaySounds[updated] = stream; } @@ -1233,6 +1282,7 @@ namespace MWSound for(;sndidx != snditer->second.end();++sndidx) { mOutput->finishSound(sndidx->first); + mUnusedSounds.push_back(sndidx->first); Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); @@ -1241,14 +1291,20 @@ namespace MWSound mActiveSounds.clear(); SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); for(;sayiter != mActiveSaySounds.end();++sayiter) + { mOutput->finishStream(sayiter->second); + mUnusedStreams.push_back(sayiter->second); + } mActiveSaySounds.clear(); TrackList::iterator trkiter = mActiveTracks.begin(); for(;trkiter != mActiveTracks.end();++trkiter) + { mOutput->finishStream(*trkiter); + mUnusedStreams.push_back(*trkiter); + } mActiveTracks.clear(); - mUnderwaterSound.reset(); - mNearWaterSound.reset(); + mUnderwaterSound = nullptr; + mNearWaterSound = nullptr; stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 691e52932..836c3f228 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -29,6 +29,7 @@ namespace MWSound class Sound_Output; struct Sound_Decoder; class Sound; + class Stream; class Sound_Buffer; enum Environment { @@ -81,18 +82,24 @@ namespace MWSound typedef std::deque SoundList; SoundList mUnusedBuffers; - typedef std::pair SoundBufferRefPair; + std::unique_ptr> mSounds; + std::vector mUnusedSounds; + + std::unique_ptr> mStreams; + std::vector mUnusedStreams; + + typedef std::pair SoundBufferRefPair; typedef std::vector SoundBufferRefPairList; typedef std::map SoundMap; SoundMap mActiveSounds; - typedef std::map SaySoundMap; + typedef std::map SaySoundMap; SaySoundMap mActiveSaySounds; - typedef std::vector TrackList; + typedef std::vector TrackList; TrackList mActiveTracks; - MWBase::SoundStreamPtr mMusic; + Stream *mMusic; std::string mCurrentPlaylist; bool mListenerUnderwater; @@ -102,8 +109,8 @@ namespace MWSound int mPausedSoundTypes; - MWBase::SoundPtr mUnderwaterSound; - MWBase::SoundPtr mNearWaterSound; + Sound *mUnderwaterSound; + Sound *mNearWaterSound; Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); @@ -113,7 +120,10 @@ namespace MWSound // returns a decoder to start streaming DecoderPtr loadVoice(const std::string &voicefile); - MWBase::SoundStreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); + Sound *getSoundRef(); + Stream *getStreamRef(); + + Stream *playVoice(DecoderPtr decoder, const osg::Vec3f &pos, bool playlocal); void streamMusicFull(const std::string& filename); void advanceMusic(const std::string& filename); @@ -176,33 +186,33 @@ namespace MWSound /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual MWBase::SoundStreamPtr playTrack(const DecoderPtr& decoder, PlayType type); + virtual Stream *playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder - virtual void stopTrack(MWBase::SoundStreamPtr stream); + virtual void stopTrack(Stream *stream); ///< Stop the given audio track from playing - virtual double getTrackTimeDelay(MWBase::SoundStreamPtr stream); + virtual double getTrackTimeDelay(Stream *stream); ///< Retives the time delay, in seconds, of the audio track (must be a sound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. - virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); + virtual Sound *playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0); + virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, + float volume, float pitch, PlayType type=Play_TypeSfx, + PlayMode mode=Play_Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. - virtual MWBase::SoundPtr playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0); + virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, + float volume, float pitch, PlayType type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< @param offset Number of seconds into the sound to start playback. - virtual void stopSound(MWBase::SoundPtr sound); + virtual void stopSound(Sound *sound); ///< Stop the given sound from playing /// @note no-op if \a sound is null diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 5afdce700..64d601563 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -283,7 +283,7 @@ namespace MWWorld MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) { - MWBase::SoundPtr sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWBase::Sound *sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); if (sound) state.mSounds.push_back(sound); } @@ -584,8 +584,8 @@ namespace MWWorld for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++) { - MWBase::SoundPtr sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWBase::Sound *sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, + MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); if (sound) state.mSounds.push_back(sound); } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index bfa4980e9..c7025a3a0 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -103,7 +103,7 @@ namespace MWWorld bool mStack; - std::vector mSounds; + std::vector mSounds; std::vector mSoundIds; }; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index eaf88d45a..c4b46961c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -531,7 +531,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall , mQueuedWeather(0) , mRegions() , mResult() - , mAmbientSound() + , mAmbientSound(nullptr) , mPlayingSoundID() { mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; @@ -735,15 +735,15 @@ void WeatherManager::update(float duration, bool paused) mPlayingSoundID = mResult.mAmbientLoopSoundID; } - if (mAmbientSound.get()) + else if (mAmbientSound) mAmbientSound->setVolume(mResult.mAmbientSoundVolume); } void WeatherManager::stopSounds() { - if (mAmbientSound.get()) + if (mAmbientSound) MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); - mAmbientSound.reset(); + mAmbientSound = nullptr; mPlayingSoundID.clear(); } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 044200757..84a6c5105 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -288,7 +288,7 @@ namespace MWWorld std::map mRegions; MWRender::WeatherResult mResult; - MWBase::SoundPtr mAmbientSound; + MWBase::Sound *mAmbientSound; std::string mPlayingSoundID; void addWeather(const std::string& name, From 9e7a49f66eb73599a871823b10a07f7014cc554f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 11 Sep 2017 22:17:36 -0700 Subject: [PATCH 160/521] Include alext.h to get OpenAL extension definitions --- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwsound/alext.h | 466 ++++++++++++++++ apps/openmw/mwsound/efx-presets.h | 402 ++++++++++++++ apps/openmw/mwsound/efx.h | 761 ++++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.cpp | 22 - apps/openmw/mwsound/openal_output.hpp | 1 + 6 files changed, 1632 insertions(+), 23 deletions(-) create mode 100644 apps/openmw/mwsound/alext.h create mode 100644 apps/openmw/mwsound/efx-presets.h create mode 100644 apps/openmw/mwsound/efx.h diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 134953f3d..00ae2fa4a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,8 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output loudness movieaudiofactory + soundmanagerimp openal_output ffmpeg_decoder sound sound_buffer sound_decoder sound_output + loudness movieaudiofactory alext efx efx-presets ) add_openmw_dir (mwworld diff --git a/apps/openmw/mwsound/alext.h b/apps/openmw/mwsound/alext.h new file mode 100644 index 000000000..4b9a15537 --- /dev/null +++ b/apps/openmw/mwsound/alext.h @@ -0,0 +1,466 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2008 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef AL_ALEXT_H +#define AL_ALEXT_H + +#include +/* Define int64_t and uint64_t types */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef AL_EXT_MULAW +#define AL_EXT_MULAW 1 +#define AL_FORMAT_MONO_MULAW_EXT 0x10014 +#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 +#endif + +#ifndef AL_EXT_ALAW +#define AL_EXT_ALAW 1 +#define AL_FORMAT_MONO_ALAW_EXT 0x10016 +#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 +#endif + +#ifndef ALC_LOKI_audio_channel +#define ALC_LOKI_audio_channel 1 +#define ALC_CHAN_MAIN_LOKI 0x500001 +#define ALC_CHAN_PCM_LOKI 0x500002 +#define ALC_CHAN_CD_LOKI 0x500003 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#ifndef AL_EXT_MULAW_MCFORMATS +#define AL_EXT_MULAW_MCFORMATS 1 +#define AL_FORMAT_MONO_MULAW 0x10014 +#define AL_FORMAT_STEREO_MULAW 0x10015 +#define AL_FORMAT_QUAD_MULAW 0x10021 +#define AL_FORMAT_REAR_MULAW 0x10022 +#define AL_FORMAT_51CHN_MULAW 0x10023 +#define AL_FORMAT_61CHN_MULAW 0x10024 +#define AL_FORMAT_71CHN_MULAW 0x10025 +#endif + +#ifndef AL_EXT_IMA4 +#define AL_EXT_IMA4 1 +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +#endif + +#ifndef AL_EXT_STATIC_BUFFER +#define AL_EXT_STATIC_BUFFER 1 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); +#endif +#endif + +#ifndef ALC_EXT_EFX +#define ALC_EXT_EFX 1 +#include "efx.h" +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef ALC_EXT_thread_local_context +#define ALC_EXT_thread_local_context 1 +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +#endif +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifndef AL_SOFT_buffer_sub_data +#define AL_SOFT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 +#endif + +#ifndef AL_EXT_FOLDBACK +#define AL_EXT_FOLDBACK 1 +#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" +#define AL_FOLDBACK_EVENT_BLOCK 0x4112 +#define AL_FOLDBACK_EVENT_START 0x4111 +#define AL_FOLDBACK_EVENT_STOP 0x4113 +#define AL_FOLDBACK_MODE_MONO 0x4101 +#define AL_FOLDBACK_MODE_STEREO 0x4102 +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); +AL_API void AL_APIENTRY alRequestFoldbackStop(void); +#endif +#endif + +#ifndef ALC_EXT_DEDICATED +#define ALC_EXT_DEDICATED 1 +#define AL_DEDICATED_GAIN 0x0001 +#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 +#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 +#endif + +#ifndef AL_SOFT_buffer_samples +#define AL_SOFT_buffer_samples 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif + +#ifndef AL_SOFT_direct_channels +#define AL_SOFT_direct_channels 1 +#define AL_DIRECT_CHANNELS_SOFT 0x1033 +#endif + +#ifndef ALC_SOFT_loopback +#define ALC_SOFT_loopback 1 +#define ALC_FORMAT_CHANNELS_SOFT 0x1990 +#define ALC_FORMAT_TYPE_SOFT 0x1991 + +/* Sample types */ +#define ALC_BYTE_SOFT 0x1400 +#define ALC_UNSIGNED_BYTE_SOFT 0x1401 +#define ALC_SHORT_SOFT 0x1402 +#define ALC_UNSIGNED_SHORT_SOFT 0x1403 +#define ALC_INT_SOFT 0x1404 +#define ALC_UNSIGNED_INT_SOFT 0x1405 +#define ALC_FLOAT_SOFT 0x1406 + +/* Channel configurations */ +#define ALC_MONO_SOFT 0x1500 +#define ALC_STEREO_SOFT 0x1501 +#define ALC_QUAD_SOFT 0x1503 +#define ALC_5POINT1_SOFT 0x1504 +#define ALC_6POINT1_SOFT 0x1505 +#define ALC_7POINT1_SOFT 0x1506 + +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +#endif +#endif + +#ifndef AL_EXT_STEREO_ANGLES +#define AL_EXT_STEREO_ANGLES 1 +#define AL_STEREO_ANGLES 0x1030 +#endif + +#ifndef AL_EXT_SOURCE_RADIUS +#define AL_EXT_SOURCE_RADIUS 1 +#define AL_SOURCE_RADIUS 0x1031 +#endif + +#ifndef AL_SOFT_source_latency +#define AL_SOFT_source_latency 1 +#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 +#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 +typedef int64_t ALint64SOFT; +typedef uint64_t ALuint64SOFT; +typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); +AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); +AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); +AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); +#endif +#endif + +#ifndef ALC_EXT_DEFAULT_FILTER_ORDER +#define ALC_EXT_DEFAULT_FILTER_ORDER 1 +#define ALC_DEFAULT_FILTER_ORDER 0x1100 +#endif + +#ifndef AL_SOFT_deferred_updates +#define AL_SOFT_deferred_updates 1 +#define AL_DEFERRED_UPDATES_SOFT 0xC002 +typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); +typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); +#endif +#endif + +#ifndef AL_SOFT_block_alignment +#define AL_SOFT_block_alignment 1 +#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C +#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D +#endif + +#ifndef AL_SOFT_MSADPCM +#define AL_SOFT_MSADPCM 1 +#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 +#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 +#endif + +#ifndef AL_SOFT_source_length +#define AL_SOFT_source_length 1 +/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ +/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ +/*#define AL_SEC_LENGTH_SOFT 0x200B*/ +#endif + +#ifndef ALC_SOFT_pause_device +#define ALC_SOFT_pause_device 1 +typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); +typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); +#endif +#endif + +#ifndef AL_EXT_BFORMAT +#define AL_EXT_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_8 0x20021 +#define AL_FORMAT_BFORMAT2D_16 0x20022 +#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 +#define AL_FORMAT_BFORMAT3D_8 0x20031 +#define AL_FORMAT_BFORMAT3D_16 0x20032 +#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033 +#endif + +#ifndef AL_EXT_MULAW_BFORMAT +#define AL_EXT_MULAW_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_MULAW 0x10031 +#define AL_FORMAT_BFORMAT3D_MULAW 0x10032 +#endif + +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + +#ifndef AL_SOFT_gain_clamp_ex +#define AL_SOFT_gain_clamp_ex 1 +#define AL_GAIN_LIMIT_SOFT 0x200E +#endif + +#ifndef AL_SOFT_source_resampler +#define AL_SOFT_source_resampler +#define AL_NUM_RESAMPLERS_SOFT 0x1210 +#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 +#define AL_SOURCE_RESAMPLER_SOFT 0x1212 +#define AL_RESAMPLER_NAME_SOFT 0x1213 +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +#ifdef AL_ALEXT_PROTOTYPES +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +#endif +#endif + +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 +#define AL_AUTO_SOFT 0x0002 +#endif + +#ifndef ALC_SOFT_output_limiter +#define ALC_SOFT_output_limiter +#define ALC_OUTPUT_LIMITER_SOFT 0x199A +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/openmw/mwsound/efx-presets.h b/apps/openmw/mwsound/efx-presets.h new file mode 100644 index 000000000..8539fd517 --- /dev/null +++ b/apps/openmw/mwsound/efx-presets.h @@ -0,0 +1,402 @@ +/* Reverb presets for EFX */ + +#ifndef EFX_PRESETS_H +#define EFX_PRESETS_H + +#ifndef EFXEAXREVERBPROPERTIES_DEFINED +#define EFXEAXREVERBPROPERTIES_DEFINED +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; +#endif + +/* Default Presets */ + +#define EFX_REVERB_PRESET_GENERIC \ + { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PADDEDCELL \ + { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ROOM \ + { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_BATHROOM \ + { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_LIVINGROOM \ + { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_AUDITORIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CONCERTHALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CAVE \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_ARENA \ + { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HANGAR \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ + { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HALLWAY \ + { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONECORRIDOR \ + { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ALLEY \ + { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FOREST \ + { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY \ + { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOUNTAINS \ + { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_QUARRY \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PLAIN \ + { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PARKINGLOT \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SEWERPIPE \ + { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_UNDERWATER \ + { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRUGGED \ + { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DIZZY \ + { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PSYCHOTIC \ + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Castle Presets */ + +#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ + { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_HALL \ + { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ + { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ + { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ + { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +/* Factory Presets */ + +#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ + { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ + { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ + { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_HALL \ + { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ + { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ + { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ + { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +/* Ice Palace Presets */ + +#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ + { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ + { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ + { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ + { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_HALL \ + { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ + { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ + { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +/* Space Station Presets */ + +#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ + { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ + { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ + { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ + { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ + { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_HALL \ + { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ + { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ + { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +/* Wooden Galleon Presets */ + +#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_HALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ + { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ + { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +/* Sports Presets */ + +#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ + { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ + { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ + { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ + { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ + { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Prefab Presets */ + +#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ + { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ + { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ + { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ + { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Dome and Pipe Presets */ + +#define EFX_REVERB_PRESET_DOME_TOMB \ + { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_SMALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ + { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ + { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_LARGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_RESONANT \ + { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +/* Outdoors Presets */ + +#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ + { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ + { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ + { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ + { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ + { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +/* Mood Presets */ + +#define EFX_REVERB_PRESET_MOOD_HEAVEN \ + { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOOD_HELL \ + { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_MOOD_MEMORY \ + { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Driving Presets */ + +#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ + { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ + { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ + { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ + { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ + { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ + { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } + +/* City Presets */ + +#define EFX_REVERB_PRESET_CITY_STREETS \ + { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_SUBWAY \ + { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_MUSEUM \ + { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_LIBRARY \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_UNDERPASS \ + { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_ABANDONED \ + { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Misc. Presets */ + +#define EFX_REVERB_PRESET_DUSTYROOM \ + { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CHAPEL \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SMALLWATERROOM \ + { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#endif /* EFX_PRESETS_H */ diff --git a/apps/openmw/mwsound/efx.h b/apps/openmw/mwsound/efx.h new file mode 100644 index 000000000..57766983f --- /dev/null +++ b/apps/openmw/mwsound/efx.h @@ -0,0 +1,761 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + + +/* Listener properties. */ +#define AL_METERS_PER_UNIT 0x20004 + +/* Source properties. */ +#define AL_DIRECT_FILTER 0x20005 +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_AIR_ABSORPTION_FACTOR 0x20007 +#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +#define AL_CONE_OUTER_GAINHF 0x20009 +#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A +#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C + + +/* Effect properties. */ + +/* Reverb effect parameters */ +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 + +/* Chorus effect parameters */ +#define AL_CHORUS_WAVEFORM 0x0001 +#define AL_CHORUS_PHASE 0x0002 +#define AL_CHORUS_RATE 0x0003 +#define AL_CHORUS_DEPTH 0x0004 +#define AL_CHORUS_FEEDBACK 0x0005 +#define AL_CHORUS_DELAY 0x0006 + +/* Distortion effect parameters */ +#define AL_DISTORTION_EDGE 0x0001 +#define AL_DISTORTION_GAIN 0x0002 +#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +#define AL_DISTORTION_EQCENTER 0x0004 +#define AL_DISTORTION_EQBANDWIDTH 0x0005 + +/* Echo effect parameters */ +#define AL_ECHO_DELAY 0x0001 +#define AL_ECHO_LRDELAY 0x0002 +#define AL_ECHO_DAMPING 0x0003 +#define AL_ECHO_FEEDBACK 0x0004 +#define AL_ECHO_SPREAD 0x0005 + +/* Flanger effect parameters */ +#define AL_FLANGER_WAVEFORM 0x0001 +#define AL_FLANGER_PHASE 0x0002 +#define AL_FLANGER_RATE 0x0003 +#define AL_FLANGER_DEPTH 0x0004 +#define AL_FLANGER_FEEDBACK 0x0005 +#define AL_FLANGER_DELAY 0x0006 + +/* Frequency shifter effect parameters */ +#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 + +/* Vocal morpher effect parameters */ +#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +#define AL_VOCAL_MORPHER_RATE 0x0006 + +/* Pitchshifter effect parameters */ +#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 + +/* Ringmodulator effect parameters */ +#define AL_RING_MODULATOR_FREQUENCY 0x0001 +#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +#define AL_RING_MODULATOR_WAVEFORM 0x0003 + +/* Autowah effect parameters */ +#define AL_AUTOWAH_ATTACK_TIME 0x0001 +#define AL_AUTOWAH_RELEASE_TIME 0x0002 +#define AL_AUTOWAH_RESONANCE 0x0003 +#define AL_AUTOWAH_PEAK_GAIN 0x0004 + +/* Compressor effect parameters */ +#define AL_COMPRESSOR_ONOFF 0x0001 + +/* Equalizer effect parameters */ +#define AL_EQUALIZER_LOW_GAIN 0x0001 +#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +#define AL_EQUALIZER_MID1_GAIN 0x0003 +#define AL_EQUALIZER_MID1_CENTER 0x0004 +#define AL_EQUALIZER_MID1_WIDTH 0x0005 +#define AL_EQUALIZER_MID2_GAIN 0x0006 +#define AL_EQUALIZER_MID2_CENTER 0x0007 +#define AL_EQUALIZER_MID2_WIDTH 0x0008 +#define AL_EQUALIZER_HIGH_GAIN 0x0009 +#define AL_EQUALIZER_HIGH_CUTOFF 0x000A + +/* Effect type */ +#define AL_EFFECT_FIRST_PARAMETER 0x0000 +#define AL_EFFECT_LAST_PARAMETER 0x8000 +#define AL_EFFECT_TYPE 0x8001 + +/* Effect types, used with the AL_EFFECT_TYPE property */ +#define AL_EFFECT_NULL 0x0000 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_CHORUS 0x0002 +#define AL_EFFECT_DISTORTION 0x0003 +#define AL_EFFECT_ECHO 0x0004 +#define AL_EFFECT_FLANGER 0x0005 +#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +#define AL_EFFECT_VOCAL_MORPHER 0x0007 +#define AL_EFFECT_PITCH_SHIFTER 0x0008 +#define AL_EFFECT_RING_MODULATOR 0x0009 +#define AL_EFFECT_AUTOWAH 0x000A +#define AL_EFFECT_COMPRESSOR 0x000B +#define AL_EFFECT_EQUALIZER 0x000C +#define AL_EFFECT_EAXREVERB 0x8000 + +/* Auxiliary Effect Slot properties. */ +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECTSLOT_GAIN 0x0002 +#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 + +/* NULL Auxiliary Slot ID to disable a source send. */ +#define AL_EFFECTSLOT_NULL 0x0000 + + +/* Filter properties. */ + +/* Lowpass filter parameters */ +#define AL_LOWPASS_GAIN 0x0001 +#define AL_LOWPASS_GAINHF 0x0002 + +/* Highpass filter parameters */ +#define AL_HIGHPASS_GAIN 0x0001 +#define AL_HIGHPASS_GAINLF 0x0002 + +/* Bandpass filter parameters */ +#define AL_BANDPASS_GAIN 0x0001 +#define AL_BANDPASS_GAINLF 0x0002 +#define AL_BANDPASS_GAINHF 0x0003 + +/* Filter type */ +#define AL_FILTER_FIRST_PARAMETER 0x0000 +#define AL_FILTER_LAST_PARAMETER 0x8000 +#define AL_FILTER_TYPE 0x8001 + +/* Filter types, used with the AL_FILTER_TYPE property */ +#define AL_FILTER_NULL 0x0000 +#define AL_FILTER_LOWPASS 0x0001 +#define AL_FILTER_HIGHPASS 0x0002 +#define AL_FILTER_BANDPASS 0x0003 + + +/* Effect object function types. */ +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); + +/* Filter object function types. */ +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); + +/* Auxiliary Effect Slot object function types. */ +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); + +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +#endif + +/* Filter ranges and defaults. */ + +/* Lowpass filter */ +#define AL_LOWPASS_MIN_GAIN (0.0f) +#define AL_LOWPASS_MAX_GAIN (1.0f) +#define AL_LOWPASS_DEFAULT_GAIN (1.0f) + +#define AL_LOWPASS_MIN_GAINHF (0.0f) +#define AL_LOWPASS_MAX_GAINHF (1.0f) +#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define AL_HIGHPASS_MIN_GAIN (0.0f) +#define AL_HIGHPASS_MAX_GAIN (1.0f) +#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) + +#define AL_HIGHPASS_MIN_GAINLF (0.0f) +#define AL_HIGHPASS_MAX_GAINLF (1.0f) +#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define AL_BANDPASS_MIN_GAIN (0.0f) +#define AL_BANDPASS_MAX_GAIN (1.0f) +#define AL_BANDPASS_DEFAULT_GAIN (1.0f) + +#define AL_BANDPASS_MIN_GAINHF (0.0f) +#define AL_BANDPASS_MAX_GAINHF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) + +#define AL_BANDPASS_MIN_GAINLF (0.0f) +#define AL_BANDPASS_MAX_GAINLF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) + + +/* Effect parameter ranges and defaults. */ + +/* Standard reverb effect */ +#define AL_REVERB_MIN_DENSITY (0.0f) +#define AL_REVERB_MAX_DENSITY (1.0f) +#define AL_REVERB_DEFAULT_DENSITY (1.0f) + +#define AL_REVERB_MIN_DIFFUSION (0.0f) +#define AL_REVERB_MAX_DIFFUSION (1.0f) +#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_REVERB_MIN_GAIN (0.0f) +#define AL_REVERB_MAX_GAIN (1.0f) +#define AL_REVERB_DEFAULT_GAIN (0.32f) + +#define AL_REVERB_MIN_GAINHF (0.0f) +#define AL_REVERB_MAX_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_GAINHF (0.89f) + +#define AL_REVERB_MIN_DECAY_TIME (0.1f) +#define AL_REVERB_MAX_DECAY_TIME (20.0f) +#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* EAX reverb effect */ +#define AL_EAXREVERB_MIN_DENSITY (0.0f) +#define AL_EAXREVERB_MAX_DENSITY (1.0f) +#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) + +#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_EAXREVERB_MIN_GAIN (0.0f) +#define AL_EAXREVERB_MAX_GAIN (1.0f) +#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) + +#define AL_EAXREVERB_MIN_GAINHF (0.0f) +#define AL_EAXREVERB_MAX_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) + +#define AL_EAXREVERB_MIN_GAINLF (0.0f) +#define AL_EAXREVERB_MAX_GAINLF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) + +#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) + +#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) + +#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) + +#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) + +#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* Chorus effect */ +#define AL_CHORUS_WAVEFORM_SINUSOID (0) +#define AL_CHORUS_WAVEFORM_TRIANGLE (1) + +#define AL_CHORUS_MIN_WAVEFORM (0) +#define AL_CHORUS_MAX_WAVEFORM (1) +#define AL_CHORUS_DEFAULT_WAVEFORM (1) + +#define AL_CHORUS_MIN_PHASE (-180) +#define AL_CHORUS_MAX_PHASE (180) +#define AL_CHORUS_DEFAULT_PHASE (90) + +#define AL_CHORUS_MIN_RATE (0.0f) +#define AL_CHORUS_MAX_RATE (10.0f) +#define AL_CHORUS_DEFAULT_RATE (1.1f) + +#define AL_CHORUS_MIN_DEPTH (0.0f) +#define AL_CHORUS_MAX_DEPTH (1.0f) +#define AL_CHORUS_DEFAULT_DEPTH (0.1f) + +#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +#define AL_CHORUS_MAX_FEEDBACK (1.0f) +#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) + +#define AL_CHORUS_MIN_DELAY (0.0f) +#define AL_CHORUS_MAX_DELAY (0.016f) +#define AL_CHORUS_DEFAULT_DELAY (0.016f) + +/* Distortion effect */ +#define AL_DISTORTION_MIN_EDGE (0.0f) +#define AL_DISTORTION_MAX_EDGE (1.0f) +#define AL_DISTORTION_DEFAULT_EDGE (0.2f) + +#define AL_DISTORTION_MIN_GAIN (0.01f) +#define AL_DISTORTION_MAX_GAIN (1.0f) +#define AL_DISTORTION_DEFAULT_GAIN (0.05f) + +#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) + +#define AL_DISTORTION_MIN_EQCENTER (80.0f) +#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) + +#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) + +/* Echo effect */ +#define AL_ECHO_MIN_DELAY (0.0f) +#define AL_ECHO_MAX_DELAY (0.207f) +#define AL_ECHO_DEFAULT_DELAY (0.1f) + +#define AL_ECHO_MIN_LRDELAY (0.0f) +#define AL_ECHO_MAX_LRDELAY (0.404f) +#define AL_ECHO_DEFAULT_LRDELAY (0.1f) + +#define AL_ECHO_MIN_DAMPING (0.0f) +#define AL_ECHO_MAX_DAMPING (0.99f) +#define AL_ECHO_DEFAULT_DAMPING (0.5f) + +#define AL_ECHO_MIN_FEEDBACK (0.0f) +#define AL_ECHO_MAX_FEEDBACK (1.0f) +#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) + +#define AL_ECHO_MIN_SPREAD (-1.0f) +#define AL_ECHO_MAX_SPREAD (1.0f) +#define AL_ECHO_DEFAULT_SPREAD (-1.0f) + +/* Flanger effect */ +#define AL_FLANGER_WAVEFORM_SINUSOID (0) +#define AL_FLANGER_WAVEFORM_TRIANGLE (1) + +#define AL_FLANGER_MIN_WAVEFORM (0) +#define AL_FLANGER_MAX_WAVEFORM (1) +#define AL_FLANGER_DEFAULT_WAVEFORM (1) + +#define AL_FLANGER_MIN_PHASE (-180) +#define AL_FLANGER_MAX_PHASE (180) +#define AL_FLANGER_DEFAULT_PHASE (0) + +#define AL_FLANGER_MIN_RATE (0.0f) +#define AL_FLANGER_MAX_RATE (10.0f) +#define AL_FLANGER_DEFAULT_RATE (0.27f) + +#define AL_FLANGER_MIN_DEPTH (0.0f) +#define AL_FLANGER_MAX_DEPTH (1.0f) +#define AL_FLANGER_DEFAULT_DEPTH (1.0f) + +#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +#define AL_FLANGER_MAX_FEEDBACK (1.0f) +#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) + +#define AL_FLANGER_MIN_DELAY (0.0f) +#define AL_FLANGER_MAX_DELAY (0.004f) +#define AL_FLANGER_DEFAULT_DELAY (0.002f) + +/* Frequency shifter effect */ +#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) + +#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) + +#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) + +#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) + +/* Vocal morpher effect */ +#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_PHONEME_A (0) +#define AL_VOCAL_MORPHER_PHONEME_E (1) +#define AL_VOCAL_MORPHER_PHONEME_I (2) +#define AL_VOCAL_MORPHER_PHONEME_O (3) +#define AL_VOCAL_MORPHER_PHONEME_U (4) +#define AL_VOCAL_MORPHER_PHONEME_AA (5) +#define AL_VOCAL_MORPHER_PHONEME_AE (6) +#define AL_VOCAL_MORPHER_PHONEME_AH (7) +#define AL_VOCAL_MORPHER_PHONEME_AO (8) +#define AL_VOCAL_MORPHER_PHONEME_EH (9) +#define AL_VOCAL_MORPHER_PHONEME_ER (10) +#define AL_VOCAL_MORPHER_PHONEME_IH (11) +#define AL_VOCAL_MORPHER_PHONEME_IY (12) +#define AL_VOCAL_MORPHER_PHONEME_UH (13) +#define AL_VOCAL_MORPHER_PHONEME_UW (14) +#define AL_VOCAL_MORPHER_PHONEME_B (15) +#define AL_VOCAL_MORPHER_PHONEME_D (16) +#define AL_VOCAL_MORPHER_PHONEME_F (17) +#define AL_VOCAL_MORPHER_PHONEME_G (18) +#define AL_VOCAL_MORPHER_PHONEME_J (19) +#define AL_VOCAL_MORPHER_PHONEME_K (20) +#define AL_VOCAL_MORPHER_PHONEME_L (21) +#define AL_VOCAL_MORPHER_PHONEME_M (22) +#define AL_VOCAL_MORPHER_PHONEME_N (23) +#define AL_VOCAL_MORPHER_PHONEME_P (24) +#define AL_VOCAL_MORPHER_PHONEME_R (25) +#define AL_VOCAL_MORPHER_PHONEME_S (26) +#define AL_VOCAL_MORPHER_PHONEME_T (27) +#define AL_VOCAL_MORPHER_PHONEME_V (28) +#define AL_VOCAL_MORPHER_PHONEME_Z (29) + +#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) + +#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) + +#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) + +/* Pitch shifter effect */ +#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) + +#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) + +/* Ring modulator effect */ +#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) + +#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) + +#define AL_RING_MODULATOR_SINUSOID (0) +#define AL_RING_MODULATOR_SAWTOOTH (1) +#define AL_RING_MODULATOR_SQUARE (2) + +#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) + +/* Autowah effect */ +#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) + +#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) + +/* Compressor effect */ +#define AL_COMPRESSOR_MIN_ONOFF (0) +#define AL_COMPRESSOR_MAX_ONOFF (1) +#define AL_COMPRESSOR_DEFAULT_ONOFF (1) + +/* Equalizer effect */ +#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) + +#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) + +#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) + +#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) + + +/* Source parameter value ranges and defaults. */ +#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) + +#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) + +#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE + + +/* Listener parameter value ranges and defaults. */ +#define AL_MIN_METERS_PER_UNIT FLT_MIN +#define AL_MAX_METERS_PER_UNIT FLT_MAX +#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AL_EFX_H */ diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 0e000f8d8..f2e8bad5c 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -24,28 +24,6 @@ #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif -#ifndef ALC_SOFT_HRTF -#define ALC_SOFT_HRTF 1 -#define ALC_HRTF_SOFT 0x1992 -#define ALC_DONT_CARE_SOFT 0x0002 -#define ALC_HRTF_STATUS_SOFT 0x1993 -#define ALC_HRTF_DISABLED_SOFT 0x0000 -#define ALC_HRTF_ENABLED_SOFT 0x0001 -#define ALC_HRTF_DENIED_SOFT 0x0002 -#define ALC_HRTF_REQUIRED_SOFT 0x0003 -#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 -#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 -#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 -#define ALC_HRTF_SPECIFIER_SOFT 0x1995 -#define ALC_HRTF_ID_SOFT 0x1996 -typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); -typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); -#endif -#endif - #define MAKE_PTRID(id) ((void*)(uintptr_t)id) #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index cb943d87e..c35c1b2a2 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -8,6 +8,7 @@ #include "alc.h" #include "al.h" +#include "alext.h" #include "sound_output.hpp" From 9e45f6d05f95c9c5566d26ed147214b345456b1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 01:02:08 -0700 Subject: [PATCH 161/521] Make a note that stopTrack needs to be called for a stopping track --- apps/openmw/mwbase/soundmanager.hpp | 3 ++- apps/openmw/mwsound/soundmanagerimp.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 9986564cd..4439fe8f3 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -107,7 +107,8 @@ namespace MWBase /// If the actor is not saying anything, returns 0. virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; - ///< Play a 2D audio track, using a custom decoder + ///< Play a 2D audio track, using a custom decoder. The caller is expected to call + /// stopTrack with the returned handle when done. virtual void stopTrack(SoundStream *stream) = 0; ///< Stop the given audio track from playing diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f8b753a18..0dd3ef754 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1083,7 +1083,6 @@ namespace MWSound if(!mOutput->isStreamPlaying(sound)) { mOutput->finishStream(sound); - mUnusedStreams.push_back(sound); trkiter = mActiveTracks.erase(trkiter); } else From 617c05f5571a64fc09ebeb8407abecf8cec30010 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 01:19:26 -0700 Subject: [PATCH 162/521] Make Sound and Stream sibling types To avoid being able to accidentally cast a Stream* to a Sound*, or vice-versa. --- apps/openmw/mwsound/sound.hpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 9a3fc4e75..1389835db 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -7,9 +7,10 @@ namespace MWSound { - class Sound { - Sound& operator=(const Sound &rhs); - Sound(const Sound &rhs); + class SoundBase { + SoundBase& operator=(const SoundBase&) = delete; + SoundBase(const SoundBase&) = delete; + SoundBase(SoundBase&&) = delete; osg::Vec3f mPos; float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ @@ -80,17 +81,26 @@ namespace MWSound mHandle = nullptr; } - Sound() + SoundBase() : mPos(0.0f, 0.0f, 0.0f), mVolume(1.0f), mBaseVolume(1.0f), mPitch(1.0f) , mMinDistance(1.0f), mMaxDistance(1000.0f), mFlags(0), mFadeOutTime(0.0f) - , mHandle(0) + , mHandle(nullptr) { } }; - // Same as above, but it's a different type since the output handles them differently - class Stream : public Sound { - Stream& operator=(const Stream &rhs); - Stream(const Stream &rhs); + class Sound : public SoundBase { + Sound& operator=(const Sound&) = delete; + Sound(const Sound&) = delete; + Sound(Sound&&) = delete; + + public: + Sound() { } + }; + + class Stream : public SoundBase { + Stream& operator=(const Stream&) = delete; + Stream(const Stream&) = delete; + Stream(Stream&&) = delete; public: Stream() { } From c5a3fb7ccdcf3f9dd780b8d76e4df65b8a451489 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 02:48:10 -0700 Subject: [PATCH 163/521] Simplify checking for near water sfx change Rather than checking every frame you're near the water, only check when the current cell changed (the sfx will only change when moving between interior and exterior). It also doesn't need to look through all playing sounds, as it's a local one not attached to a Ptr. --- apps/openmw/mwsound/soundmanagerimp.cpp | 36 ++++++++++++++----------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0dd3ef754..67c7f77e4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -72,8 +72,8 @@ namespace MWSound mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints"); mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance"); mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance"); - mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID"); - mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID"); + mNearWaterIndoorID = Misc::StringUtils::lowerCase(mFallback.getFallbackString("Water_NearWaterIndoorID")); + mNearWaterOutdoorID = Misc::StringUtils::lowerCase(mFallback.getFallbackString("Water_NearWaterOutdoorID")); mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); @@ -873,16 +873,18 @@ namespace MWSound void SoundManager::updateWaterSound(float /*duration*/) { + static const ESM::Cell *LastCell; MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); osg::Vec3f pos = player.getRefData().getPosition().asVec3(); + const ESM::Cell *curcell = player.getCell()->getCell(); float volume = 0.0f; const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID; if (!mListenerUnderwater) { - if (player.getCell()->getCell()->hasWater()) + if (curcell->hasWater()) { float dist = std::abs(player.getCell()->getWaterLevel() - pos.z()); @@ -929,25 +931,24 @@ namespace MWSound mOutput->finishSound(mNearWaterSound); mNearWaterSound = nullptr; } - else + else if(LastCell != curcell) { bool soundIdChanged = false; - Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); - - for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + Sound_Buffer* sfx = lookupSound(soundId); + SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + if(snditer != mActiveSounds.end()) { - for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter) - { - if (pairiter->first == mNearWaterSound) - { - if (pairiter->second != sfx) - soundIdChanged = true; - break; - } - } + SoundBufferRefPairList::const_iterator pairiter = std::find_if( + snditer->second.begin(), snditer->second.end(), + [this](const SoundBufferRefPairList::value_type &item) -> bool + { return mNearWaterSound == item.first; } + ); + if (pairiter != snditer->second.end() && pairiter->second != sfx) + soundIdChanged = true; } + LastCell = curcell; if (soundIdChanged) { mOutput->finishSound(mNearWaterSound); @@ -958,7 +959,10 @@ namespace MWSound } } else if (volume > 0.0f) + { + LastCell = curcell; mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } } void SoundManager::updateSounds(float duration) From 3d37cb3cf6cd77f4e0c620e914ff97af4dcbdd7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 03:06:58 -0700 Subject: [PATCH 164/521] Load EFX functions when available --- apps/openmw/mwsound/openal_output.cpp | 93 +++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index f2e8bad5c..993000edb 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -41,12 +41,56 @@ void convertPointer(T& dest, R src) } template -void getFunc(T& func, ALCdevice *device, const char *name) +void getALCFunc(T& func, ALCdevice *device, const char *name) { void* funcPtr = alcGetProcAddress(device, name); convertPointer(func, funcPtr); } +template +void getALFunc(T& func, const char *name) +{ + void* funcPtr = alGetProcAddress(name); + convertPointer(func, funcPtr); +} + +// Effect objects +LPALGENEFFECTS alGenEffects; +LPALDELETEEFFECTS alDeleteEffects; +LPALISEFFECT alIsEffect; +LPALEFFECTI alEffecti; +LPALEFFECTIV alEffectiv; +LPALEFFECTF alEffectf; +LPALEFFECTFV alEffectfv; +LPALGETEFFECTI alGetEffecti; +LPALGETEFFECTIV alGetEffectiv; +LPALGETEFFECTF alGetEffectf; +LPALGETEFFECTFV alGetEffectfv; +// Filter objects +LPALGENFILTERS alGenFilters; +LPALDELETEFILTERS alDeleteFilters; +LPALISFILTER alIsFilter; +LPALFILTERI alFilteri; +LPALFILTERIV alFilteriv; +LPALFILTERF alFilterf; +LPALFILTERFV alFilterfv; +LPALGETFILTERI alGetFilteri; +LPALGETFILTERIV alGetFilteriv; +LPALGETFILTERF alGetFilterf; +LPALGETFILTERFV alGetFilterfv; +// Auxiliary slot objects +LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; +LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; +LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; +LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; +LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; +LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; +LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; +LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; +LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; +LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; +LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + } namespace MWSound @@ -549,6 +593,45 @@ void OpenAL_Output::init(const std::string &devname) if(mFreeSources.empty()) fail("Could not allocate any sources"); + if(alcIsExtensionPresent(mDevice, "ALC_EXT_EFX")) + { +#define LOAD_FUNC(x) getALFunc(x, #x) + LOAD_FUNC(alGenEffects); + LOAD_FUNC(alDeleteEffects); + LOAD_FUNC(alIsEffect); + LOAD_FUNC(alEffecti); + LOAD_FUNC(alEffectiv); + LOAD_FUNC(alEffectf); + LOAD_FUNC(alEffectfv); + LOAD_FUNC(alGetEffecti); + LOAD_FUNC(alGetEffectiv); + LOAD_FUNC(alGetEffectf); + LOAD_FUNC(alGetEffectfv); + LOAD_FUNC(alGenFilters); + LOAD_FUNC(alDeleteFilters); + LOAD_FUNC(alIsFilter); + LOAD_FUNC(alFilteri); + LOAD_FUNC(alFilteriv); + LOAD_FUNC(alFilterf); + LOAD_FUNC(alFilterfv); + LOAD_FUNC(alGetFilteri); + LOAD_FUNC(alGetFilteriv); + LOAD_FUNC(alGetFilterf); + LOAD_FUNC(alGetFilterfv); + LOAD_FUNC(alGenAuxiliaryEffectSlots); + LOAD_FUNC(alDeleteAuxiliaryEffectSlots); + LOAD_FUNC(alIsAuxiliaryEffectSlot); + LOAD_FUNC(alAuxiliaryEffectSloti); + LOAD_FUNC(alAuxiliaryEffectSlotiv); + LOAD_FUNC(alAuxiliaryEffectSlotf); + LOAD_FUNC(alAuxiliaryEffectSlotfv); + LOAD_FUNC(alGetAuxiliaryEffectSloti); + LOAD_FUNC(alGetAuxiliaryEffectSlotiv); + LOAD_FUNC(alGetAuxiliaryEffectSlotf); + LOAD_FUNC(alGetAuxiliaryEffectSlotfv); +#undef LOAD_FUNC + } + mInitialized = true; } @@ -582,7 +665,7 @@ std::vector OpenAL_Output::enumerateHrtf() return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; - getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); ALCint num_hrtf; alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); @@ -606,10 +689,10 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; - getFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; - getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); + getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); @@ -660,7 +743,7 @@ void OpenAL_Output::disableHrtf() } LPALCRESETDEVICESOFT alcResetDeviceSOFT = 0; - getFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); + getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT"); std::vector attrs; attrs.push_back(ALC_HRTF_SOFT); From c790fedd3f7e6610c61003d926cd6842a7cf09e4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 03:53:53 -0700 Subject: [PATCH 165/521] Load an effect and filter for underwater --- apps/openmw/mwsound/openal_output.cpp | 102 +++++++++++++++++++++++++- apps/openmw/mwsound/openal_output.hpp | 8 ++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 993000edb..1dd78f5ce 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -20,6 +20,8 @@ #include "soundmanagerimp.hpp" #include "loudness.hpp" +#include "efx-presets.h" + #ifndef ALC_ALL_DEVICES_SPECIFIER #define ALC_ALL_DEVICES_SPECIFIER 0x1013 #endif @@ -91,6 +93,56 @@ LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + +void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props) +{ + ALint type = AL_NONE; + alGetEffecti(effect, AL_EFFECT_TYPE, &type); + if(type == AL_EFFECT_EAXREVERB) + { + alEffectf(effect, AL_EAXREVERB_DIFFUSION, props.flDiffusion); + alEffectf(effect, AL_EAXREVERB_DENSITY, props.flDensity); + alEffectf(effect, AL_EAXREVERB_GAIN, props.flGain); + alEffectf(effect, AL_EAXREVERB_GAINHF, props.flGainHF); + alEffectf(effect, AL_EAXREVERB_GAINLF, props.flGainLF); + alEffectf(effect, AL_EAXREVERB_DECAY_TIME, props.flDecayTime); + alEffectf(effect, AL_EAXREVERB_DECAY_HFRATIO, props.flDecayHFRatio); + alEffectf(effect, AL_EAXREVERB_DECAY_LFRATIO, props.flDecayLFRatio); + alEffectf(effect, AL_EAXREVERB_REFLECTIONS_GAIN, props.flReflectionsGain); + alEffectf(effect, AL_EAXREVERB_REFLECTIONS_DELAY, props.flReflectionsDelay); + alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, props.flReflectionsPan); + alEffectf(effect, AL_EAXREVERB_LATE_REVERB_GAIN, props.flLateReverbGain); + alEffectf(effect, AL_EAXREVERB_LATE_REVERB_DELAY, props.flLateReverbDelay); + alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, props.flLateReverbPan); + alEffectf(effect, AL_EAXREVERB_ECHO_TIME, props.flEchoTime); + alEffectf(effect, AL_EAXREVERB_ECHO_DEPTH, props.flEchoDepth); + alEffectf(effect, AL_EAXREVERB_MODULATION_TIME, props.flModulationTime); + alEffectf(effect, AL_EAXREVERB_MODULATION_DEPTH, props.flModulationDepth); + alEffectf(effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, props.flAirAbsorptionGainHF); + alEffectf(effect, AL_EAXREVERB_HFREFERENCE, props.flHFReference); + alEffectf(effect, AL_EAXREVERB_LFREFERENCE, props.flLFReference); + alEffectf(effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor); + alEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE); + } + else if(type == AL_EFFECT_REVERB) + { + alEffectf(effect, AL_REVERB_DIFFUSION, props.flDiffusion); + alEffectf(effect, AL_REVERB_DENSITY, props.flDensity); + alEffectf(effect, AL_REVERB_GAIN, props.flGain); + alEffectf(effect, AL_REVERB_GAINHF, props.flGainHF); + alEffectf(effect, AL_REVERB_DECAY_TIME, props.flDecayTime); + alEffectf(effect, AL_REVERB_DECAY_HFRATIO, props.flDecayHFRatio); + alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, props.flReflectionsGain); + alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, props.flReflectionsDelay); + alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, props.flLateReverbGain); + alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, props.flLateReverbDelay); + alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, props.flAirAbsorptionGainHF); + alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor); + alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE); + } + alGetError(); +} + } namespace MWSound @@ -565,6 +617,8 @@ void OpenAL_Output::init(const std::string &devname) fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice))); } + ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); + alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); throwALerror(); @@ -593,7 +647,7 @@ void OpenAL_Output::init(const std::string &devname) if(mFreeSources.empty()) fail("Could not allocate any sources"); - if(alcIsExtensionPresent(mDevice, "ALC_EXT_EFX")) + if(ALC.EXT_EFX) { #define LOAD_FUNC(x) getALFunc(x, #x) LOAD_FUNC(alGenEffects); @@ -630,6 +684,41 @@ void OpenAL_Output::init(const std::string &devname) LOAD_FUNC(alGetAuxiliaryEffectSlotf); LOAD_FUNC(alGetAuxiliaryEffectSlotfv); #undef LOAD_FUNC + throwALerror(); + + alGenFilters(1, &mWaterFilter); + if(alGetError() == AL_NO_ERROR) + { + alFilteri(mWaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if(alGetError() == AL_NO_ERROR) + { + std::cout<< "Low-pass filter supported" < IDDq; IDDq mFreeSources; @@ -34,6 +38,10 @@ namespace MWSound osg::Vec3f mListenerPos; Environment mListenerEnv; + ALuint mWaterFilter; + ALuint mWaterEffect; + ALuint mEffectSlot; + struct StreamThread; std::unique_ptr mStreamThread; From 0b720cd90c66b4f978819295abeffefe9a2c5b2b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 15:22:01 -0700 Subject: [PATCH 166/521] Set the appropriate meter/unit scale for sound --- apps/openmw/mwsound/openal_output.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1dd78f5ce..596646a74 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -33,6 +33,10 @@ namespace { +// The game uses 64 units per yard, or approximately 69.99125109 units per meter. +// Should this be defined publically somewhere? +const float UnitsPerMeter = 69.99125109f; + const int sLoudnessFPS = 20; // loudness values per second of audio // Helper to get an OpenAL extension function @@ -719,7 +723,13 @@ void OpenAL_Output::init(const std::string &devname) } LoadEffect(mWaterEffect, EFX_REVERB_PRESET_UNDERWATER); } + + alListenerf(AL_METERS_PER_UNIT, 1.0f / UnitsPerMeter); } + // Speed of sound is in units per second. Given the default speed of sound is 343.3 (assumed + // meters per second), multiply by the units per meter to get the speed in u/s. + alSpeedOfSound(343.3f * UnitsPerMeter); + alGetError(); mInitialized = true; } @@ -1246,6 +1256,11 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi }; alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_ORIENTATION, orient); + if(env != mListenerEnv) + { + // Speed of sound in water is 1484m/s, and in air is 343.3m/s (roughly) + alSpeedOfSound(((env == Env_Underwater) ? 1484.0f : 343.3f) * UnitsPerMeter); + } throwALerror(); } From 033303b91164ffac09d05eb5bd2cb7b5fd63cc0c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 17:00:39 -0700 Subject: [PATCH 167/521] Properly update the near water sound volume --- apps/openmw/mwsound/soundmanagerimp.cpp | 29 ++++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 67c7f77e4..9a5963308 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -931,25 +931,28 @@ namespace MWSound mOutput->finishSound(mNearWaterSound); mNearWaterSound = nullptr; } - else if(LastCell != curcell) + else { bool soundIdChanged = false; - Sound_Buffer* sfx = lookupSound(soundId); - SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr()); - if(snditer != mActiveSounds.end()) + Sound_Buffer *sfx = lookupSound(soundId); + if(LastCell != curcell) { - SoundBufferRefPairList::const_iterator pairiter = std::find_if( - snditer->second.begin(), snditer->second.end(), - [this](const SoundBufferRefPairList::value_type &item) -> bool - { return mNearWaterSound == item.first; } - ); - if (pairiter != snditer->second.end() && pairiter->second != sfx) - soundIdChanged = true; + LastCell = curcell; + SoundMap::const_iterator snditer = mActiveSounds.find(MWWorld::Ptr()); + if(snditer != mActiveSounds.end()) + { + SoundBufferRefPairList::const_iterator pairiter = std::find_if( + snditer->second.begin(), snditer->second.end(), + [this](const SoundBufferRefPairList::value_type &item) -> bool + { return mNearWaterSound == item.first; } + ); + if (pairiter != snditer->second.end() && pairiter->second != sfx) + soundIdChanged = true; + } } - LastCell = curcell; - if (soundIdChanged) + if(soundIdChanged) { mOutput->finishSound(mNearWaterSound); mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); From ec01b89e59edc34de7b9c9eaba8ce2a46b96535d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 17:17:02 -0700 Subject: [PATCH 168/521] Increase the default buffer cache sizes --- files/settings-default.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index a0460326b..aec667a9c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -313,11 +313,11 @@ voice volume = 0.8 # Minimum size to use for the sound buffer cache, in MB. When the cache is # filled, old buffers will be unloaded until it's using no more than this much # memory. Must be less than or equal to 'buffer cache max'. -buffer cache min = 14 +buffer cache min = 56 # Maximum size to use for the sound buffer cache, in MB. The cache can use up # to this much memory until old buffers get purged. -buffer cache max = 16 +buffer cache max = 64 # Specifies whether to enable HRTF processing. Valid values are: -1 = auto, # 0 = off, 1 = on. From 27eeaf90d0c5b5c43b92928d7f8103046bf04dbe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 19:03:17 -0700 Subject: [PATCH 169/521] Use unordered_map for the music playlist and sound buffer caches --- apps/openmw/mwsound/soundmanagerimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 836c3f228..e5889e36d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -50,7 +50,7 @@ namespace MWSound std::unique_ptr mOutput; // Caches available music tracks by - std::map > mMusicFiles; + std::unordered_map> mMusicFiles; std::unordered_map> mMusicToPlay; // A list with music files not yet played std::string mLastPlayedMusic; // The music file that was last played @@ -75,7 +75,7 @@ namespace MWSound size_t mBufferCacheMax; size_t mBufferCacheSize; - typedef std::map NameBufferMap; + typedef std::unordered_map NameBufferMap; NameBufferMap mBufferNameMap; // NOTE: unused buffers are stored in front-newest order. From edfba68eb583948db714d2144be261a8800f65f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 12 Sep 2017 20:20:23 -0700 Subject: [PATCH 170/521] Apply reverb and a low-pass filter when underwater This replaces the pitch-shift effect when available. --- apps/openmw/mwsound/openal_output.cpp | 104 +++++++++++++++++++++++--- apps/openmw/mwsound/openal_output.hpp | 1 + 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 596646a74..1b6b435f2 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -698,7 +698,7 @@ void OpenAL_Output::init(const std::string &devname) { std::cout<< "Low-pass filter supported" < maxdist*maxdist) gain = 0.0f; - if(useenv && mListenerEnv == Env_Underwater) + if(useenv) { - gain *= 0.9f; - pitch *= 0.7f; + if(mWaterFilter) + alSourcei(source, AL_DIRECT_FILTER, + (mListenerEnv == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL + ); + else if(mListenerEnv == Env_Underwater) + { + gain *= 0.9f; + pitch *= 0.7f; + } + if(mEffectSlot) + alSource3i(source, AL_AUXILIARY_SEND_FILTER, mEffectSlot, 0, AL_FILTER_NULL); + } + else + { + if(mWaterFilter) + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + if(mEffectSlot) + alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL); } alSourcef(source, AL_GAIN, gain); @@ -997,7 +1048,7 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; } - if(useenv && mListenerEnv == Env_Underwater) + if(useenv && mListenerEnv == Env_Underwater && !mWaterFilter) { gain *= 0.9f; pitch *= 0.7f; @@ -1256,10 +1307,39 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi }; alListenerfv(AL_POSITION, pos.ptr()); alListenerfv(AL_ORIENTATION, orient); + if(env != mListenerEnv) { // Speed of sound in water is 1484m/s, and in air is 343.3m/s (roughly) alSpeedOfSound(((env == Env_Underwater) ? 1484.0f : 343.3f) * UnitsPerMeter); + + // Update active sources with the environment's direct filter + if(mWaterFilter) + { + ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL; + std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), + [filter](const SoundVec::value_type &item) -> void + { + if(item->getUseEnv()) + alSourcei(GET_PTRID(item->mHandle), AL_DIRECT_FILTER, filter); + } + ); + std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), + [filter](const StreamVec::value_type &item) -> void + { + if(item->getUseEnv()) + alSourcei( + reinterpret_cast(item->mHandle)->mSource, + AL_DIRECT_FILTER, filter + ); + } + ); + } + // Update the environment effect + if(mEffectSlot) + alAuxiliaryEffectSloti(mEffectSlot, AL_EFFECTSLOT_EFFECT, + (env == Env_Underwater) ? mWaterEffect : mDefaultEffect + ); } throwALerror(); } @@ -1323,7 +1403,7 @@ void OpenAL_Output::resumeSounds(int types) OpenAL_Output::OpenAL_Output(SoundManager &mgr) : Sound_Output(mgr), mDevice(0), mContext(0) , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal) - , mWaterFilter(0), mWaterEffect(0), mEffectSlot(0) + , mWaterFilter(0), mWaterEffect(0), mDefaultEffect(0), mEffectSlot(0) , mStreamThread(new StreamThread) { } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index d92f99a84..fb832abc6 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -40,6 +40,7 @@ namespace MWSound ALuint mWaterFilter; ALuint mWaterEffect; + ALuint mDefaultEffect; ALuint mEffectSlot; struct StreamThread; From 6f57233ba167e757fd5057066556aa175410288d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Sep 2017 02:47:26 -0700 Subject: [PATCH 171/521] Avoid copying the same Ptr with each iteration --- apps/openmw/mwsound/soundmanagerimp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 9a5963308..36617f3b2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1005,11 +1005,14 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { + MWWorld::ConstPtr ptr = snditer->first; SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); while(sndidx != snditer->second.end()) { - MWWorld::ConstPtr ptr = snditer->first; - Sound *sound = sndidx->first; + Sound *sound; + Sound_Buffer *sfx; + + std::tie(sound, sfx) = *sndidx; if(!ptr.isEmpty() && sound->getIs3D()) { const ESM::Position &pos = ptr.getRefData().getPosition(); @@ -1031,7 +1034,6 @@ namespace MWSound mUnderwaterSound = nullptr; if(sound == mNearWaterSound) mNearWaterSound = nullptr; - Sound_Buffer *sfx = sndidx->second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); sndidx = snditer->second.erase(sndidx); @@ -1045,7 +1047,7 @@ namespace MWSound } } if(snditer->second.empty()) - mActiveSounds.erase(snditer++); + snditer = mActiveSounds.erase(snditer); else ++snditer; } From 605c937572883913cf51fb52a6846dade8074d6c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Sep 2017 03:27:48 -0700 Subject: [PATCH 172/521] Ensure 3D sources are spatialized Standard OpenAL does not spatialize non-mono sounds, although the game has some stereo sounds meant to play in 3D. The desired behavior can be achieved with the AL_SOFT_source_spatialize extension. --- apps/openmw/mwsound/openal_output.cpp | 5 +++++ apps/openmw/mwsound/openal_output.hpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1b6b435f2..146776442 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -622,6 +622,7 @@ void OpenAL_Output::init(const std::string &devname) } ALC.EXT_EFX = !!alcIsExtensionPresent(mDevice, "ALC_EXT_EFX"); + AL.SOFT_source_spatialize = !!alIsExtensionPresent("AL_SOFT_source_spatialize"); alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); throwALerror(); @@ -972,6 +973,8 @@ void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat g alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + if(AL.SOFT_source_spatialize) + alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE); if(useenv) { @@ -1009,6 +1012,8 @@ void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat m alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE); + if(AL.SOFT_source_spatialize) + alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE); if((pos - mListenerPos).length2() > maxdist*maxdist) gain = 0.0f; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index fb832abc6..777b9207f 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -26,6 +26,9 @@ namespace MWSound struct { int EXT_EFX : 1; } ALC; + struct { + int SOFT_source_spatialize : 1; + } AL; typedef std::deque IDDq; IDDq mFreeSources; From abe80f58683b604f98e49f7386bb451dc4e4400b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Sep 2017 20:47:20 -0700 Subject: [PATCH 173/521] Move the soundlist when updating a Ptr instead of copying --- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 36617f3b2..25af9add8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1203,16 +1203,16 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(old); if(snditer != mActiveSounds.end()) { - SoundBufferRefPairList sndlist = snditer->second; + SoundBufferRefPairList sndlist = std::move(snditer->second); mActiveSounds.erase(snditer); - mActiveSounds[updated] = sndlist; + mActiveSounds.emplace(updated, std::move(sndlist)); } SaySoundMap::iterator sayiter = mActiveSaySounds.find(old); if(sayiter != mActiveSaySounds.end()) { Stream *stream = sayiter->second; mActiveSaySounds.erase(sayiter); - mActiveSaySounds[updated] = stream; + mActiveSaySounds.emplace(updated, stream); } } From c17edfd547b57efe458a8100c2709cf05c434081 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Sep 2017 03:41:11 -0700 Subject: [PATCH 174/521] Don't be so throw-happy in the sound manager --- apps/openmw/mwsound/openal_output.cpp | 389 ++++++++++++------------ apps/openmw/mwsound/openal_output.hpp | 10 +- apps/openmw/mwsound/sound_output.hpp | 10 +- apps/openmw/mwsound/soundmanagerimp.cpp | 323 +++++++++----------- 4 files changed, 364 insertions(+), 368 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 146776442..a6258babe 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -39,6 +39,26 @@ const float UnitsPerMeter = 69.99125109f; const int sLoudnessFPS = 20; // loudness values per second of audio +ALCenum checkALCError(ALCdevice *device, const char *func, int line) +{ + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + std::cerr<< ">>>>>>>>> ALC error "<>>>>>>>> AL error "< void convertPointer(T& dest, R src) @@ -144,7 +164,7 @@ void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props) alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor); alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE); } - alGetError(); + getALError(); } } @@ -152,30 +172,6 @@ void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props) namespace MWSound { -static void fail(const std::string &msg) -{ throw std::runtime_error("OpenAL exception: " + msg); } - -static void throwALCerror(ALCdevice *device) -{ - ALCenum err = alcGetError(device); - if(err != ALC_NO_ERROR) - { - const ALCchar *errstring = alcGetString(device, err); - fail(errstring ? errstring : ""); - } -} - -static void throwALerror() -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - const ALchar *errstring = alGetString(err); - fail(errstring ? errstring : ""); - } -} - - static ALenum getALFormat(ChannelConfig chans, SampleType type) { static const struct { @@ -268,7 +264,8 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } - fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); + std::cerr<< "Unsupported sound format ("<getInfo(&srate, &chans, &type); - mFormat = getALFormat(chans, type); - mSampleRate = srate; +OpenAL_SoundStream::~OpenAL_SoundStream() +{ + if(mBuffers[0] && alIsBuffer(mBuffers[0])) + alDeleteBuffers(sNumBuffers, mBuffers); + alGetError(); - switch(type) - { - case SampleType_UInt8: mSilence = 0x80; break; - case SampleType_Int16: mSilence = 0x00; break; - case SampleType_Float32: mSilence = 0x00; break; - } + mDecoder->close(); +} + +bool OpenAL_SoundStream::init(bool getLoudnessData) +{ + alGenBuffers(sNumBuffers, mBuffers); + ALenum err = getALError(); + if(err != AL_NO_ERROR) + return false; - mFrameSize = framesToBytes(1, chans, type); - mBufferSize = static_cast(sBufferLength*srate); - mBufferSize *= mFrameSize; + ChannelConfig chans; + SampleType type; - if (getLoudnessData) - mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type)); - } - catch(std::exception&) + mDecoder->getInfo(&mSampleRate, &chans, &type); + mFormat = getALFormat(chans, type); + if(!mFormat) return false; + + switch(type) { - alDeleteBuffers(sNumBuffers, mBuffers); - alGetError(); - throw; + case SampleType_UInt8: mSilence = 0x80; break; + case SampleType_Int16: mSilence = 0x00; break; + case SampleType_Float32: mSilence = 0x00; break; } - mIsFinished = false; -} -OpenAL_SoundStream::~OpenAL_SoundStream() -{ - alDeleteBuffers(sNumBuffers, mBuffers); - alGetError(); - mDecoder->close(); + mFrameSize = framesToBytes(1, chans, type); + mBufferSize = static_cast(sBufferLength*mSampleRate); + mBufferSize *= mFrameSize; + + if (getLoudnessData) + mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type)); + + mIsFinished = false; + return true; } bool OpenAL_SoundStream::isPlaying() @@ -444,7 +446,7 @@ bool OpenAL_SoundStream::isPlaying() ALint state; alGetSourcei(mSource, AL_SOURCE_STATE, &state); - throwALerror(); + getALError(); if(state == AL_PLAYING || state == AL_PAUSED) return true; @@ -467,7 +469,7 @@ double OpenAL_SoundStream::getStreamDelay() const d = (double)inqueue / (double)mSampleRate; } - throwALerror(); + getALError(); return d; } @@ -493,7 +495,7 @@ double OpenAL_SoundStream::getStreamOffset() const t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; } - throwALerror(); + getALError(); return t; } @@ -590,7 +592,7 @@ std::vector OpenAL_Output::enumerate() return devlist; } -void OpenAL_Output::init(const std::string &devname) +bool OpenAL_Output::init(const std::string &devname) { deinit(); @@ -598,9 +600,10 @@ void OpenAL_Output::init(const std::string &devname) if(!mDevice) { if(devname.empty()) - fail("Failed to open default device"); + std::cerr<< "Failed to open default audio device" <(maxmono+maxstereo, 256); + maxtotal = std::min(maxmono+maxstereo, 256); if (maxtotal == 0) // workaround for broken implementations maxtotal = 256; - for(size_t i = 0;i < maxtotal;i++) - { - ALuint src = 0; - alGenSources(1, &src); - throwALerror(); - mFreeSources.push_back(src); - } } - catch(std::exception &e) + for(size_t i = 0;i < maxtotal;i++) { - std::cout <<"Error: "< OpenAL_Output::enumerateHrtf() { - if(!mDevice) - fail("Device not initialized"); - std::vector ret; - if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + + if(!mDevice || !alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; @@ -816,7 +831,6 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) return; } - LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); @@ -891,7 +905,7 @@ void OpenAL_Output::disableHrtf() Sound_Handle OpenAL_Output::loadSound(const std::string &fname) { - throwALerror(); + getALError(); DecoderPtr decoder = mManager.getDecoder(); // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav. @@ -914,20 +928,20 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); + if(!format) return nullptr; decoder->readAll(data); decoder->close(); ALuint buf = 0; - try { - alGenBuffers(1, &buf); - alBufferData(buf, format, &data[0], data.size(), srate); - throwALerror(); - } - catch(...) { + alGenBuffers(1, &buf); + alBufferData(buf, format, &data[0], data.size(), srate); + if(getALError() != AL_NO_ERROR) + { if(buf && alIsBuffer(buf)) alDeleteBuffers(1, &buf); - throw; + getALError(); + return nullptr; } return MAKE_PTRID(buf); } @@ -952,6 +966,7 @@ void OpenAL_Output::unloadSound(Sound_Handle data) } } alDeleteBuffers(1, &buffer); + getALError(); } size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const @@ -960,7 +975,7 @@ size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const ALint size = 0; alGetBufferi(buffer, AL_SIZE, &size); - throwALerror(); + getALError(); return (ALuint)size; } @@ -1067,65 +1082,63 @@ void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat m } -void OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) +bool OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset) { ALuint source; if(mFreeSources.empty()) - fail("No free sources"); + { + std::cerr<< "No free sources!" <getPosition(), sound->getRealVolume(), sound->getPitch(), - sound->getIsLooping(), sound->getUseEnv()); - - alSourcef(source, AL_SEC_OFFSET, offset); - throwALerror(); - alSourcei(source, AL_BUFFER, GET_PTRID(data)); - alSourcePlay(source); - throwALerror(); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + sound->getIsLooping(), sound->getUseEnv()); + alSourcef(source, AL_SEC_OFFSET, offset); + if(getALError() != AL_NO_ERROR) + return false; - mActiveSounds.push_back(sound); - } - catch(std::exception&) { - mFreeSources.push_back(source); - throw; - } + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + return false; + mFreeSources.pop_front(); sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); + + return true; } -void OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) +bool OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset) { ALuint source; if(mFreeSources.empty()) - fail("No free sources"); + { + std::cerr<< "No free sources!" <getPosition(), sound->getMinDistance(), sound->getMaxDistance(), - sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), - sound->getUseEnv()); - - alSourcef(source, AL_SEC_OFFSET, offset); - throwALerror(); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(), + sound->getUseEnv()); + alSourcef(source, AL_SEC_OFFSET, offset); + if(getALError() != AL_NO_ERROR) + return false; - alSourcei(source, AL_BUFFER, GET_PTRID(data)); - alSourcePlay(source); - throwALerror(); - - mActiveSounds.push_back(sound); - } - catch(std::exception&) { - mFreeSources.push_back(source); - throw; - } + alSourcei(source, AL_BUFFER, GET_PTRID(data)); + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + return false; + mFreeSources.pop_front(); sound->mHandle = MAKE_PTRID(source); + mActiveSounds.push_back(sound); + + return true; } void OpenAL_Output::finishSound(Sound *sound) @@ -1139,6 +1152,7 @@ void OpenAL_Output::finishSound(Sound *sound) // the initial queue already played when it hasn't. alSourceRewind(source); alSourcei(source, AL_BUFFER, 0); + getALError(); mFreeSources.push_back(source); mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound)); @@ -1148,10 +1162,10 @@ bool OpenAL_Output::isSoundPlaying(Sound *sound) { if(!sound->mHandle) return false; ALuint source = GET_PTRID(sound->mHandle); - ALint state; + ALint state = AL_STOPPED; alGetSourcei(source, AL_SOURCE_STATE, &state); - throwALerror(); + getALError(); return state == AL_PLAYING || state == AL_PAUSED; } @@ -1163,69 +1177,68 @@ void OpenAL_Output::updateSound(Sound *sound) updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); + getALError(); } -void OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound) +bool OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound) { - OpenAL_SoundStream *stream = 0; - ALuint source; - if(mFreeSources.empty()) - fail("No free sources"); - source = mFreeSources.front(); - mFreeSources.pop_front(); + { + std::cerr<< "No free sources!" <getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try { - initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), - false, sound->getUseEnv()); - throwALerror(); + initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(), + false, sound->getUseEnv()); + if(getALError() != AL_NO_ERROR) + return false; - stream = new OpenAL_SoundStream(source, decoder); - mStreamThread->add(stream); - mActiveStreams.push_back(sound); - } - catch(std::exception&) { - mStreamThread->remove(stream); + OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder)); + if(!stream->init()) + { delete stream; - mFreeSources.push_back(source); - throw; + return false; } + mStreamThread->add(stream); + mFreeSources.pop_front(); sound->mHandle = stream; + mActiveStreams.push_back(sound); + return true; } -void OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) +bool OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) { - OpenAL_SoundStream *stream = 0; - ALuint source; - if(mFreeSources.empty()) - fail("No free sources"); - source = mFreeSources.front(); - mFreeSources.pop_front(); + { + std::cerr<< "No free sources!" <getIsLooping()) std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; - try { - initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), - sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); - throwALerror(); + initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(), + sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv()); + if(getALError() != AL_NO_ERROR) + return false; - stream = new OpenAL_SoundStream(source, decoder, getLoudnessData); - mStreamThread->add(stream); - mActiveStreams.push_back(sound); - } - catch(std::exception&) { - mStreamThread->remove(stream); + OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder)); + if(!stream->init(getLoudnessData)) + { delete stream; - mFreeSources.push_back(source); - throw; + return false; } + mStreamThread->add(stream); + mFreeSources.pop_front(); sound->mHandle = stream; + mActiveStreams.push_back(sound); + return true; } void OpenAL_Output::finishStream(Stream *sound) @@ -1242,6 +1255,7 @@ void OpenAL_Output::finishStream(Stream *sound) // the initial queue already played when it hasn't. alSourceRewind(source); alSourcei(source, AL_BUFFER, 0); + getALError(); mFreeSources.push_back(source); mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound)); @@ -1288,6 +1302,7 @@ void OpenAL_Output::updateStream(Stream *sound) updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(), sound->getPitch(), sound->getUseEnv(), sound->getIs3D()); + getALError(); } @@ -1346,7 +1361,7 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi (env == Env_Underwater) ? mWaterEffect : mDefaultEffect ); } - throwALerror(); + getALError(); } mListenerPos = pos; @@ -1374,8 +1389,8 @@ void OpenAL_Output::pauseSounds(int types) } if(!sources.empty()) { - alSourcePausev(sources.size(), &sources[0]); - throwALerror(); + alSourcePausev(sources.size(), sources.data()); + getALError(); } } @@ -1399,8 +1414,8 @@ void OpenAL_Output::resumeSounds(int types) } if(!sources.empty()) { - alSourcePlayv(sources.size(), &sources[0]); - throwALerror(); + alSourcePlayv(sources.size(), sources.data()); + getALError(); } } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 777b9207f..05f9c5090 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -59,7 +59,7 @@ namespace MWSound public: virtual std::vector enumerate(); - virtual void init(const std::string &devname=std::string()); + virtual bool init(const std::string &devname=std::string()); virtual void deinit(); virtual std::vector enumerateHrtf(); @@ -70,14 +70,14 @@ namespace MWSound virtual void unloadSound(Sound_Handle data); virtual size_t getSoundDataSize(Sound_Handle data) const; - virtual void playSound(Sound *sound, Sound_Handle data, float offset); - virtual void playSound3D(Sound *sound, Sound_Handle data, float offset); + virtual bool playSound(Sound *sound, Sound_Handle data, float offset); + virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset); virtual void finishSound(Sound *sound); virtual bool isSoundPlaying(Sound *sound); virtual void updateSound(Sound *sound); - virtual void streamSound(DecoderPtr decoder, Stream *sound); - virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData); + virtual bool streamSound(DecoderPtr decoder, Stream *sound); + virtual bool streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData); virtual void finishStream(Stream *sound); virtual double getStreamDelay(Stream *sound); virtual double getStreamOffset(Stream *sound); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 907a601b5..01dc8b5b9 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -24,7 +24,7 @@ namespace MWSound SoundManager &mManager; virtual std::vector enumerate() = 0; - virtual void init(const std::string &devname=std::string()) = 0; + virtual bool init(const std::string &devname=std::string()) = 0; virtual void deinit() = 0; virtual std::vector enumerateHrtf() = 0; @@ -35,14 +35,14 @@ namespace MWSound virtual void unloadSound(Sound_Handle data) = 0; virtual size_t getSoundDataSize(Sound_Handle data) const = 0; - virtual void playSound(Sound *sound, Sound_Handle data, float offset) = 0; - virtual void playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; + virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0; + virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; virtual void finishSound(Sound *sound) = 0; virtual bool isSoundPlaying(Sound *sound) = 0; virtual void updateSound(Sound *sound) = 0; - virtual void streamSound(DecoderPtr decoder, Stream *sound) = 0; - virtual void streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0; + virtual bool streamSound(DecoderPtr decoder, Stream *sound) = 0; + virtual bool streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData) = 0; virtual void finishStream(Stream *sound) = 0; virtual double getStreamDelay(Stream *sound) = 0; virtual double getStreamOffset(Stream *sound) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 25af9add8..51ce67096 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -89,40 +89,42 @@ namespace MWSound std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; - try { - std::vector names = mOutput->enumerate(); - std::cout <<"Enumerated output devices:"<< std::endl; - for(size_t i = 0;i < names.size();i++) - std::cout <<" "<init(devname); - } - catch(std::exception &e) { - if(devname.empty()) - throw; - std::cerr <<"Failed to open device \""<init(); - Settings::Manager::setString("device", "Sound", ""); - } - - names = mOutput->enumerateHrtf(); - if(!names.empty()) - { - std::cout <<"Enumerated HRTF names:"<< std::endl; - for(size_t i = 0;i < names.size();i++) - std::cout <<" "< names = mOutput->enumerate(); + std::cout <<"Enumerated output devices:\n"; + std::for_each(names.cbegin(), names.cend(), + [](const std::string &name) -> void + { std::cout <<" "<disableHrtf(); - else if(!hrtfname.empty()) - mOutput->enableHrtf(hrtfname, hrtfstate<0); + std::string devname = Settings::Manager::getString("device", "Sound"); + bool inited = mOutput->init(devname); + if(!inited && !devname.empty()) + { + std::cerr<< "Failed to initialize device \""<init(); } - catch(std::exception &e) { - std::cout <<"Sound init failed: "<enumerateHrtf(); + if(!names.empty()) + { + std::cout<< "Enumerated HRTF names:\n"; + std::for_each(names.cbegin(), names.cend(), + [](const std::string &name) -> void + { std::cout<< " "<disableHrtf(); + else if(!hrtfname.empty()) + mOutput->enableHrtf(hrtfname, hrtfstate<0); } SoundManager::~SoundManager() @@ -186,8 +188,12 @@ namespace MWSound Sound_Buffer *SoundManager::lookupSound(const std::string &soundId) const { NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); - if(snd != mBufferNameMap.end()) return snd->second; - return 0; + if(snd != mBufferNameMap.end()) + { + Sound_Buffer *sfx = snd->second; + if(sfx->mHandle) return sfx; + } + return nullptr; } // Lookup a soundId for its sound data (resource name, local volume, @@ -201,15 +207,17 @@ namespace MWSound else { MWBase::World *world = MWBase::Environment::get().getWorld(); - const ESM::Sound *sound = world->getStore().get().find(soundId); + const ESM::Sound *sound = world->getStore().get().search(soundId); + if(!sound) return nullptr; sfx = insertSound(soundId, sound); } if(!sfx->mHandle) { sfx->mHandle = mOutput->loadSound(sfx->mResourceName); - mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + if(!sfx->mHandle) return nullptr; + mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); if(mBufferCacheSize > mBufferCacheMax) { do { @@ -293,18 +301,24 @@ namespace MWSound static float minDistance = std::max(fAudioVoiceDefaultMinDistance * fAudioMinDistanceMult, 1.0f); static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); + bool played; float basevol = volumeFromType(Play_TypeVoice); Stream *sound = getStreamRef(); if(playlocal) { sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D); - mOutput->streamSound(decoder, sound); + played = mOutput->streamSound(decoder, sound); } else { sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, Play_Normal|Play_TypeVoice|Play_3D); - mOutput->streamSound3D(decoder, sound, true); + played = mOutput->streamSound3D(decoder, sound, true); + } + if(!played) + { + mUnusedStreams.push_back(sound); + return nullptr; } return sound; } @@ -351,23 +365,16 @@ namespace MWSound return; std::cout <<"Playing "<open(filename); + stopMusic(); - mMusic = getStreamRef(); - mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, - Play_NoEnv|Play_TypeMusic|Play_2D); - mOutput->streamSound(decoder, mMusic); - } - catch(std::exception &e) { - std::cout << "Music Error: " << e.what() << "\n"; - if(mMusic) - mUnusedStreams.push_back(mMusic); - mMusic = nullptr; - } + DecoderPtr decoder = getDecoder(); + decoder->open(filename); + + mMusic = getStreamRef(); + mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, + Play_NoEnv|Play_TypeMusic|Play_2D); + mOutput->streamSound(decoder, mMusic); } void SoundManager::advanceMusic(const std::string& filename) @@ -454,24 +461,20 @@ namespace MWSound { if(!mOutput->isInitialized()) return; - try - { - std::string voicefile = "Sound/"+filename; - mVFS->normalizeFilename(voicefile); - DecoderPtr decoder = loadVoice(voicefile); + std::string voicefile = "Sound/"+filename; - MWBase::World *world = MWBase::Environment::get().getWorld(); - const osg::Vec3f pos = world->getActorHeadTransform(ptr).getTrans(); + mVFS->normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile); - stopSay(ptr); - Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); - mActiveSaySounds.insert(std::make_pair(ptr, sound)); - } - catch(std::exception &e) - { - std::cout <<"Sound Error: "<getActorHeadTransform(ptr).getTrans(); + + stopSay(ptr); + Stream *sound = playVoice(decoder, pos, (ptr == MWMechanics::getPlayer())); + if(!sound) return; + + mActiveSaySounds.insert(std::make_pair(ptr, sound)); } float SoundManager::getSaySoundLoudness(const MWWorld::ConstPtr &ptr) const @@ -490,21 +493,17 @@ namespace MWSound { if(!mOutput->isInitialized()) return; - try - { - std::string voicefile = "Sound/"+filename; - mVFS->normalizeFilename(voicefile); - DecoderPtr decoder = loadVoice(voicefile); + std::string voicefile = "Sound/"+filename; - stopSay(MWWorld::ConstPtr()); - mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), - playVoice(decoder, osg::Vec3f(), true))); - } - catch(std::exception &e) - { - std::cout <<"Sound Error: "<normalizeFilename(voicefile); + DecoderPtr decoder = loadVoice(voicefile); + + stopSay(MWWorld::ConstPtr()); + Stream *sound = playVoice(decoder, osg::Vec3f(), true); + if(!sound) return; + + mActiveSaySounds.insert(std::make_pair(MWWorld::ConstPtr(), sound)); } bool SoundManager::sayDone(const MWWorld::ConstPtr &ptr) const @@ -535,22 +534,18 @@ namespace MWSound { if(!mOutput->isInitialized()) return nullptr; - Stream *track = getStreamRef(); - try - { - track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); - mOutput->streamSound(decoder, track); - TrackList::iterator iter = std::lower_bound(mActiveTracks.begin(), mActiveTracks.end(), track); - mActiveTracks.insert(iter, track); - } - catch(std::exception &e) + Stream *track = getStreamRef(); + track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); + if(!mOutput->streamSound(decoder, track)) { - std::cout <<"Sound Error: "<isInitialized()) return nullptr; - Sound *sound = nullptr; - try - { - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - float basevol = volumeFromType(type); - sound = getSoundRef(); - sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); - mOutput->playSound(sound, sfx->mHandle, offset); - if(sfx->mUses++ == 0) - { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if(!sfx) return nullptr; + + Sound *sound = getSoundRef(); + sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); + if(!mOutput->playSound(sound, sfx->mHandle, offset)) + { + mUnusedSounds.push_back(sound); + return nullptr; } - catch(std::exception&) + + if(sfx->mUses++ == 0) { - //std::cout <<"Sound Error: "<isInitialized()) return nullptr; - Sound *sound = nullptr; - try - { - // Look up the sound in the ESM data - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - float basevol = volumeFromType(type); - const ESM::Position &pos = ptr.getRefData().getPosition(); - const osg::Vec3f objpos(pos.asVec3()); - if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) - return nullptr; + // Look up the sound in the ESM data + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if(!sfx) return nullptr; - // Only one copy of given sound can be played at time on ptr, so stop previous copy - stopSound3D(ptr, soundId); + const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3()); + if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) + return nullptr; - sound = getSoundRef(); - if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) - { - sound->init(volume * sfx->mVolume, basevol, pitch, mode|type|Play_2D); - mOutput->playSound(sound, sfx->mHandle, offset); - } - else - { - sound->init(objpos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); - mOutput->playSound3D(sound, sfx->mHandle, offset); - } - if(sfx->mUses++ == 0) - { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - mActiveSounds[ptr].push_back(std::make_pair(sound, sfx)); + // Only one copy of given sound can be played at time on ptr, so stop previous copy + stopSound3D(ptr, soundId); + + bool played; + Sound *sound = getSoundRef(); + if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) + { + sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); + played = mOutput->playSound(sound, sfx->mHandle, offset); } - catch(std::exception&) + else { - //std::cout <<"Sound Error: "<init(objpos, volume * sfx->mVolume, volumeFromType(type), pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); + played = mOutput->playSound3D(sound, sfx->mHandle, offset); } + if(!played) + { + mUnusedSounds.push_back(sound); + return nullptr; + } + + if(sfx->mUses++ == 0) + { + SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } + mActiveSounds[ptr].push_back(std::make_pair(sound, sfx)); return sound; } @@ -657,32 +643,27 @@ namespace MWSound { if(!mOutput->isInitialized()) return nullptr; - Sound *sound = nullptr; - try - { - // Look up the sound in the ESM data - Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - float basevol = volumeFromType(type); - sound = getSoundRef(); - sound->init(initialPos, volume * sfx->mVolume, basevol, pitch, - sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); - mOutput->playSound3D(sound, sfx->mHandle, offset); - if(sfx->mUses++ == 0) - { - SoundList::iterator iter = std::find(mUnusedBuffers.begin(), mUnusedBuffers.end(), sfx); - if(iter != mUnusedBuffers.end()) - mUnusedBuffers.erase(iter); - } - mActiveSounds[MWWorld::ConstPtr()].push_back(std::make_pair(sound, sfx)); + // Look up the sound in the ESM data + Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); + if(!sfx) return nullptr; + + Sound *sound = getSoundRef(); + sound->init(initialPos, volume * sfx->mVolume, volumeFromType(type), pitch, + sfx->mMinDist, sfx->mMaxDist, mode|type|Play_3D); + if(!mOutput->playSound3D(sound, sfx->mHandle, offset)) + { + mUnusedSounds.push_back(sound); + return nullptr; } - catch(std::exception &) + + if(sfx->mUses++ == 0) { - //std::cout <<"Sound Error: "< Date: Thu, 14 Sep 2017 04:48:12 -0700 Subject: [PATCH 175/521] Set HRTF when initializing the device --- apps/openmw/mwsound/openal_output.cpp | 103 ++++++++++++++++-------- apps/openmw/mwsound/openal_output.hpp | 10 +-- apps/openmw/mwsound/sound_output.hpp | 11 ++- apps/openmw/mwsound/soundmanagerimp.cpp | 11 +-- 4 files changed, 85 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a6258babe..b3ba4a07f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -592,7 +592,7 @@ std::vector OpenAL_Output::enumerate() return devlist; } -bool OpenAL_Output::init(const std::string &devname) +bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode) { deinit(); @@ -615,7 +615,47 @@ bool OpenAL_Output::init(const std::string &devname) std::cout << "Opened \""< attrs; + attrs.reserve(15); + if(ALC.SOFT_HRTF) + { + LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; + getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT"); + + attrs.push_back(ALC_HRTF_SOFT); + attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE : + hrtfmode == HrtfMode::Enable ? ALC_TRUE : + /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT); + if(!hrtfname.empty()) + { + ALCint index = -1; + ALCint num_hrtf; + alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf); + for(ALCint i = 0;i < num_hrtf;++i) + { + const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i); + if(hrtfname == entry) + { + index = i; + break; + } + } + + if(index < 0) + std::cerr<< "Failed to find HRTF name \""< OpenAL_Output::enumerateHrtf() { std::vector ret; - if(!mDevice || !alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + if(!mDevice || !ALC.SOFT_HRTF) return ret; LPALCGETSTRINGISOFT alcGetStringiSOFT = 0; @@ -823,9 +877,9 @@ std::vector OpenAL_Output::enumerateHrtf() return ret; } -void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) +void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) { - if(!alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF")) + if(!mDevice || !ALC.SOFT_HRTF) { std::cerr<< "HRTF extension not present" < attrs; + attrs.reserve(15); + attrs.push_back(ALC_HRTF_SOFT); - attrs.push_back(auto_enable ? ALC_DONT_CARE_SOFT : ALC_TRUE); + attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE : + hrtfmode == HrtfMode::Enable ? ALC_TRUE : + /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT); if(!hrtfname.empty()) { ALCint index = -1; @@ -864,12 +922,12 @@ void OpenAL_Output::enableHrtf(const std::string &hrtfname, bool auto_enable) } } attrs.push_back(0); - alcResetDeviceSOFT(mDevice, &attrs[0]); + alcResetDeviceSOFT(mDevice, attrs.data()); ALCint hrtf_state; alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); if(!hrtf_state) - std::cerr<< "Failed to enable HRTF" < attrs; - attrs.push_back(ALC_HRTF_SOFT); - attrs.push_back(ALC_FALSE); - attrs.push_back(0); - alcResetDeviceSOFT(mDevice, &attrs[0]); - - ALCint hrtf_state; - alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state); - if(hrtf_state) - std::cerr<< "Failed to disable HRTF" < IDDq; @@ -59,12 +60,11 @@ namespace MWSound public: virtual std::vector enumerate(); - virtual bool init(const std::string &devname=std::string()); + virtual bool init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode); virtual void deinit(); virtual std::vector enumerateHrtf(); - virtual void enableHrtf(const std::string &hrtfname, bool auto_enable); - virtual void disableHrtf(); + virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode); virtual Sound_Handle loadSound(const std::string &fname); virtual void unloadSound(Sound_Handle data); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 01dc8b5b9..ad18e0d40 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -19,17 +19,22 @@ namespace MWSound // An opaque handle for the implementation's sound instances. typedef void *Sound_Instance; + enum class HrtfMode { + Disable, + Enable, + Auto + }; + class Sound_Output { SoundManager &mManager; virtual std::vector enumerate() = 0; - virtual bool init(const std::string &devname=std::string()) = 0; + virtual bool init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode) = 0; virtual void deinit() = 0; virtual std::vector enumerateHrtf() = 0; - virtual void enableHrtf(const std::string &hrtfname, bool auto_enable) = 0; - virtual void disableHrtf() = 0; + virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0; virtual Sound_Handle loadSound(const std::string &fname) = 0; virtual void unloadSound(Sound_Handle data) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 51ce67096..7310e457f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -85,6 +85,8 @@ namespace MWSound std::string hrtfname = Settings::Manager::getString("hrtf", "Sound"); int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound"); + HrtfMode hrtfmode = hrtfstate < 0 ? HrtfMode::Auto : + hrtfstate > 0 ? HrtfMode::Enable : HrtfMode::Disable; std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; @@ -98,11 +100,11 @@ namespace MWSound std::cout.flush(); std::string devname = Settings::Manager::getString("device", "Sound"); - bool inited = mOutput->init(devname); + bool inited = mOutput->init(devname, hrtfname, hrtfmode); if(!inited && !devname.empty()) { std::cerr<< "Failed to initialize device \""<init(); + inited = mOutput->init(std::string(), hrtfname, hrtfmode); } if(!inited) { @@ -120,11 +122,6 @@ namespace MWSound ); std::cout.flush(); } - - if(hrtfstate == 0) - mOutput->disableHrtf(); - else if(!hrtfname.empty()) - mOutput->enableHrtf(hrtfname, hrtfstate<0); } SoundManager::~SoundManager() From 1e123a22e1a51d59d3a1ea4336142d87f93b086d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Sep 2017 16:56:46 -0700 Subject: [PATCH 176/521] Avoid some explicit loops --- apps/openmw/mwsound/soundmanagerimp.cpp | 33 ++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 7310e457f..2e8ff85c8 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -819,15 +819,12 @@ namespace MWSound if(regn == NULL) return; - std::vector::const_iterator soundIter; if(total == 0) { - soundIter = regn->mSoundList.begin(); - while(soundIter != regn->mSoundList.end()) - { - total += (int)soundIter->mChance; - ++soundIter; - } + std::for_each(regn->mSoundList.cbegin(), regn->mSoundList.cend(), + [](const ESM::Region::SoundRef &sndref) -> void + { total += (int)sndref.mChance; } + ); if(total == 0) return; } @@ -835,18 +832,20 @@ namespace MWSound int r = Misc::Rng::rollDice(total); int pos = 0; - soundIter = regn->mSoundList.begin(); - while(soundIter != regn->mSoundList.end()) - { - if(r - pos < soundIter->mChance) + std::find_if_not(regn->mSoundList.cbegin(), regn->mSoundList.cend(), + [&pos, r, this](const ESM::Region::SoundRef &sndref) -> bool { - playSound(soundIter->mSound.toString(), 1.0f, 1.0f); - break; + if(r - pos < sndref.mChance) + { + playSound(sndref.mSound.toString(), 1.0f, 1.0f); + // Played this sound, stop iterating + return false; + } + pos += sndref.mChance; + // Not this sound, keep iterating + return true; } - pos += soundIter->mChance; - - ++soundIter; - } + ); } void SoundManager::updateWaterSound(float /*duration*/) From 0c1ad7c74e32a7aecf6e608558e7d6082615621c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Sep 2017 21:39:13 -0700 Subject: [PATCH 177/521] Replace a few more explicit loops --- apps/openmw/mwsound/openal_output.cpp | 102 +++++++++++++------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index b3ba4a07f..00562de1a 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1,9 +1,10 @@ #include #include #include +#include #include #include -#include +#include #include @@ -174,93 +175,90 @@ namespace MWSound static ALenum getALFormat(ChannelConfig chans, SampleType type) { - static const struct { + struct FormatEntry { ALenum format; ChannelConfig chans; SampleType type; - } fmtlist[] = { + }; + struct FormatEntryExt { + const char name[32]; + ChannelConfig chans; + SampleType type; + }; + static const std::array fmtlist{{ { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, - }; - static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); + }}; - for(size_t i = 0;i < fmtlistsize;i++) - { - if(fmtlist[i].chans == chans && fmtlist[i].type == type) - return fmtlist[i].format; - } + auto fmt = std::find_if(fmtlist.cbegin(), fmtlist.cend(), + [chans,type](const FormatEntry &fmt) -> bool + { return fmt.chans == chans && fmt.type == type; } + ); + if(fmt != fmtlist.cend()) + return fmt->format; if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } mcfmtlist[] = { + static const std::array mcfmtlist{{ { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, - }; - static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); + }}; + ALenum format = AL_NONE; - for(size_t i = 0;i < mcfmtlistsize;i++) - { - if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) + std::find_if(mcfmtlist.cbegin(), mcfmtlist.cend(), + [&format,chans,type](const FormatEntryExt &fmt) -> bool { - ALenum format = alGetEnumValue(mcfmtlist[i].name); - if(format != 0 && format != -1) - return format; + if(fmt.chans == chans && fmt.type == type) + format = alGetEnumValue(fmt.name); + return format != 0 && format != -1; } - } + ); + if(format != 0 && format != -1) + return format; } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltfmtlist[] = { + static const std::array fltfmtlist{{ { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, - }; - static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + }}; + ALenum format = AL_NONE; - for(size_t i = 0;i < fltfmtlistsize;i++) - { - if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) + std::find_if(fltfmtlist.cbegin(), fltfmtlist.cend(), + [&format,chans,type](const FormatEntryExt &fmt) -> bool { - ALenum format = alGetEnumValue(fltfmtlist[i].name); - if(format != 0 && format != -1) - return format; + if(fmt.chans == chans && fmt.type == type) + format = alGetEnumValue(fmt.name); + return format != 0 && format != -1; } - } + ); + if(format != 0 && format != -1) + return format; + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { - static const struct { - char name[32]; - ChannelConfig chans; - SampleType type; - } fltmcfmtlist[] = { + static const std::array fltmcfmtlist{{ { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, - }; - static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + }}; - for(size_t i = 0;i < fltmcfmtlistsize;i++) - { - if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) + std::find_if(fltmcfmtlist.cbegin(), fltmcfmtlist.cend(), + [&format,chans,type](const FormatEntryExt &fmt) -> bool { - ALenum format = alGetEnumValue(fltmcfmtlist[i].name); - if(format != 0 && format != -1) - return format; + if(fmt.chans == chans && fmt.type == type) + format = alGetEnumValue(fmt.name); + return format != 0 && format != -1; } - } + ); + if(format != 0 && format != -1) + return format; } } From 780e82480d7a8b700ab6459f09da6bc3076f2aea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Sep 2017 01:03:41 -0700 Subject: [PATCH 178/521] Make the PlayMode and PlayType enums scoped Also shorten them by putting them in the MWSound namespace --- apps/openmw/mwbase/soundmanager.hpp | 81 ++++++++++++----------- apps/openmw/mwclass/container.cpp | 4 +- apps/openmw/mwclass/door.cpp | 4 +- apps/openmw/mwclass/light.cpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 13 ++-- apps/openmw/mwrender/npcanimation.cpp | 5 +- apps/openmw/mwscript/soundextensions.cpp | 16 ++--- apps/openmw/mwsound/movieaudiofactory.cpp | 2 +- apps/openmw/mwsound/openal_output.cpp | 56 ++++++++-------- apps/openmw/mwsound/sound.hpp | 14 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 52 ++++++++------- apps/openmw/mwsound/soundmanagerimp.hpp | 16 ++--- apps/openmw/mwworld/action.cpp | 12 ++-- apps/openmw/mwworld/projectilemanager.cpp | 11 ++- apps/openmw/mwworld/weather.cpp | 6 +- 17 files changed, 157 insertions(+), 146 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 4439fe8f3..f1c35df19 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -18,6 +18,37 @@ namespace MWSound class Stream; struct Sound_Decoder; typedef std::shared_ptr DecoderPtr; + + /* These must all fit together */ + enum class PlayMode { + Normal = 0, /* non-looping, affected by environment */ + Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ + NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ + RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away + * from the sound source, the sound is removed. + * This is weird stuff but apparently how vanilla works for sounds + * played by the PlayLoopSound family of script functions. Perhaps + * we can make this cut off a more subtle fade later, but have to + * be careful to not change the overall volume of areas by too + * much. */ + NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the + * player is making it. */ + LoopNoEnv = Loop | NoEnv, + LoopRemoveAtDistance = Loop | RemoveAtDistance + }; + enum class Type { + Sfx = 1<<4, /* Normal SFX sound */ + Voice = 1<<5, /* Voice sound */ + Foot = 1<<6, /* Footstep sound */ + Music = 1<<7, /* Music track */ + Movie = 1<<8, /* Movie audio track */ + Mask = Sfx | Voice | Foot | Music | Movie + }; + // Used for creating a type mask for SoundManager::pauseSounds and resumeSounds + inline int operator~(Type a) { return ~static_cast(a); } + inline int operator&(Type a, Type b) { return static_cast(a) & static_cast(b); } + inline int operator&(int a, Type b) { return a & static_cast(b); } + inline int operator|(Type a, Type b) { return static_cast(a) | static_cast(b); } } namespace MWBase @@ -28,44 +59,18 @@ namespace MWBase /// \brief Interface for sound manager (implemented in MWSound) class SoundManager { - public: - /* These must all fit together */ - enum PlayMode { - Play_Normal = 0, /* non-looping, affected by environment */ - Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ - Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ - Play_RemoveAtDistance = 1<<2, /* (3D only) If the listener gets further than 2000 units away - from the sound source, the sound is removed. - This is weird stuff but apparently how vanilla works for sounds - played by the PlayLoopSound family of script functions. Perhaps we - can make this cut off a more subtle fade later, but have to - be careful to not change the overall volume of areas by too much. */ - Play_NoPlayerLocal = 1<<3, /* (3D only) Don't play the sound local to the listener even if the - player is making it. */ - Play_LoopNoEnv = Play_Loop | Play_NoEnv, - Play_LoopRemoveAtDistance = Play_Loop | Play_RemoveAtDistance - }; - enum PlayType { - Play_TypeSfx = 1<<4, /* Normal SFX sound */ - Play_TypeVoice = 1<<5, /* Voice sound */ - Play_TypeFoot = 1<<6, /* Footstep sound */ - Play_TypeMusic = 1<<7, /* Music track */ - Play_TypeMovie = 1<<8, /* Movie audio track */ - Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeFoot|Play_TypeMusic|Play_TypeMovie - }; - - private: - SoundManager (const SoundManager&); ///< not implemented SoundManager& operator= (const SoundManager&); ///< not implemented - public: + protected: + using PlayMode = MWSound::PlayMode; + using Type = MWSound::Type; + public: SoundManager() {} - virtual ~SoundManager() {} virtual void processChangedSettings(const std::set< std::pair >& settings) = 0; @@ -106,7 +111,7 @@ namespace MWBase /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; + virtual SoundStream *playTrack(const MWSound::DecoderPtr& decoder, Type type) = 0; ///< Play a 2D audio track, using a custom decoder. The caller is expected to call /// stopTrack with the returned handle when done. @@ -119,20 +124,20 @@ namespace MWBase /// decoder's read method. virtual Sound *playSound(const std::string& soundId, float volume, float pitch, - PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, + Type type=Type::Sfx, PlayMode mode=PlayMode::Normal, float offset=0) = 0; ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0) = 0; + float volume, float pitch, Type type=Type::Sfx, + PlayMode mode=PlayMode::Normal, float offset=0) = 0; ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0) = 0; + float volume, float pitch, Type type=Type::Sfx, + PlayMode mode=PlayMode::Normal, float offset=0) = 0; ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. virtual void stopSound(Sound *sound) = 0; @@ -160,10 +165,10 @@ namespace MWBase ///< Is the given sound currently playing on the given object? /// If you want to check if sound played with playSound is playing, use empty Ptr - virtual void pauseSounds(int types=Play_TypeMask) = 0; + virtual void pauseSounds(int types=static_cast(Type::Mask)) = 0; ///< Pauses all currently playing sounds, including music. - virtual void resumeSounds(int types=Play_TypeMask) = 0; + virtual void resumeSounds(int types=static_cast(Type::Mask)) = 0; ///< Resumes all previously paused sounds. virtual void update(float duration) = 0; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index dc4eb844a..b6a46cff8 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -169,9 +169,7 @@ namespace MWClass if(isTrapped) { ptr.getCellRef().setTrap(""); - MWBase::Environment::get().getSoundManager()->playSound3D(ptr, - "Disarm Trap", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Normal); + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f); isTrapped = false; } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 07e6cc9db..903ec4958 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -163,9 +163,7 @@ namespace MWClass if(isTrapped) { ptr.getCellRef().setTrap(""); - MWBase::Environment::get().getSoundManager()->playSound3D(ptr, - "Disarm Trap", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Normal); + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f); isTrapped = false; } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 172c16c83..f9056b75d 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -49,8 +49,8 @@ namespace MWClass if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); + MWSound::Type::Sfx, + MWSound::PlayMode::Loop); } bool Light::useAnim() const diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4b7b3c387..1526949a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1848,7 +1848,8 @@ namespace MWGui if (mVideoWidget->hasAudioStream()) MWBase::Environment::get().getSoundManager()->pauseSounds( - MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie)); + ~MWSound::Type::Movie & MWSound::Type::Mask + ); osg::Timer frameTimer; while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) { @@ -2035,7 +2036,7 @@ namespace MWGui void WindowManager::playSound(const std::string& soundId, float volume, float pitch) { - MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d15e1a1a5..baa2470da 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -991,7 +991,7 @@ namespace MWMechanics // ...But, only the player makes a sound. if(isPlayer) MWBase::Environment::get().getSoundManager()->playSound("torch out", - 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + 1.0, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } } } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 51dc37e18..2f645279a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -843,8 +843,8 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: { // Don't make foot sounds local for the player, it makes sense to keep them // positioned on the ground. - sndMgr->playSound3D(mPtr, sound, volume, pitch, MWBase::SoundManager::Play_TypeFoot, - MWBase::SoundManager::Play_NoPlayerLocal); + sndMgr->playSound3D(mPtr, sound, volume, pitch, MWSound::Type::Foot, + MWSound::PlayMode::NoPlayerLocal); } else { @@ -1177,8 +1177,8 @@ bool CharacterController::updateWeaponState() && mWeaponType == WeapType_None) { if(!sndMgr->getSoundPlaying(mPtr, "WolfRun")) - sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); + sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWSound::Type::Sfx, + MWSound::PlayMode::Loop); } else sndMgr->stopSound3D(mPtr, "WolfRun"); @@ -1309,9 +1309,8 @@ bool CharacterController::updateWeaponState() if(!resultMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(resultMessage); if(!resultSound.empty()) - MWBase::Environment::get().getSoundManager()->playSound3D(target, - resultSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Normal); + MWBase::Environment::get().getSoundManager()->playSound3D(target, resultSound, + 1.0f, 1.0f); } else if (ammunition) { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e4d0abf7b..8211c2f5f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -770,8 +770,9 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g mSoundIds[type] = csi->getClass().getSound(*csi); if (!mSoundIds[type].empty()) { - MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, mSoundIds[type], 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, - MWBase::SoundManager::Play_Loop); + MWBase::Environment::get().getSoundManager()->playSound3D(mPtr, mSoundIds[type], + 1.0f, 1.0f, MWSound::Type::Sfx, MWSound::PlayMode::Loop + ); } } } diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index bedc02138..4d199c299 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -82,7 +82,7 @@ namespace MWScript std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound(sound, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(sound, 1.0, 1.0, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } }; @@ -101,7 +101,7 @@ namespace MWScript Interpreter::Type_Float pitch = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound(sound, volume, pitch, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + MWBase::Environment::get().getSoundManager()->playSound(sound, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } }; @@ -122,9 +122,9 @@ namespace MWScript runtime.pop(); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, sound, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, - mLoop ? MWBase::SoundManager::Play_LoopRemoveAtDistance - : MWBase::SoundManager::Play_Normal); + MWSound::Type::Sfx, + mLoop ? MWSound::PlayMode::LoopRemoveAtDistance + : MWSound::PlayMode::Normal); } }; @@ -151,9 +151,9 @@ namespace MWScript runtime.pop(); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, sound, volume, pitch, - MWBase::SoundManager::Play_TypeSfx, - mLoop ? MWBase::SoundManager::Play_LoopRemoveAtDistance - : MWBase::SoundManager::Play_Normal); + MWSound::Type::Sfx, + mLoop ? MWSound::PlayMode::LoopRemoveAtDistance + : MWSound::PlayMode::Normal); } }; diff --git a/apps/openmw/mwsound/movieaudiofactory.cpp b/apps/openmw/mwsound/movieaudiofactory.cpp index 9c9b442c7..f54ab5c06 100644 --- a/apps/openmw/mwsound/movieaudiofactory.cpp +++ b/apps/openmw/mwsound/movieaudiofactory.cpp @@ -162,7 +162,7 @@ namespace MWSound decoder->setupFormat(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - MWBase::SoundStream *sound = sndMgr->playTrack(decoder->mDecoderBridge, MWBase::SoundManager::Play_TypeMovie); + MWBase::SoundStream *sound = sndMgr->playTrack(decoder->mDecoderBridge, MWSound::Type::Movie); if (!sound) { decoder.reset(); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 00562de1a..1a9baed77 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -1403,21 +1403,23 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi void OpenAL_Output::pauseSounds(int types) { std::vector sources; - SoundVec::const_iterator sound = mActiveSounds.begin(); - for(;sound != mActiveSounds.end();++sound) - { - if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) - sources.push_back(GET_PTRID((*sound)->mHandle)); - } - StreamVec::const_iterator stream = mActiveStreams.begin(); - for(;stream != mActiveStreams.end();++stream) - { - if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), + [types,&sources](const SoundVec::value_type &sound) -> void { - OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); - sources.push_back(strm->mSource); + if(sound && sound->mHandle && (types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); } - } + ); + std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), + [types,&sources](const StreamVec::value_type &stream) -> void + { + if(stream && stream->mHandle && (types&stream->getPlayType())) + { + OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); + sources.push_back(strm->mSource); + } + } + ); if(!sources.empty()) { alSourcePausev(sources.size(), sources.data()); @@ -1428,21 +1430,23 @@ void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::resumeSounds(int types) { std::vector sources; - SoundVec::const_iterator sound = mActiveSounds.begin(); - for(;sound != mActiveSounds.end();++sound) - { - if(*sound && (*sound)->mHandle && ((*sound)->getPlayType()&types)) - sources.push_back(GET_PTRID((*sound)->mHandle)); - } - StreamVec::const_iterator stream = mActiveStreams.begin(); - for(;stream != mActiveStreams.end();++stream) - { - if(*stream && (*stream)->mHandle && ((*stream)->getPlayType()&types)) + std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), + [types,&sources](const SoundVec::value_type &sound) -> void { - OpenAL_SoundStream *strm = reinterpret_cast((*stream)->mHandle); - sources.push_back(strm->mSource); + if(sound && sound->mHandle && (types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); } - } + ); + std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), + [types,&sources](const StreamVec::value_type &stream) -> void + { + if(stream && stream->mHandle && (types&stream->getPlayType())) + { + OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); + sources.push_back(strm->mSource); + } + } + ); if(!sources.empty()) { alSourcePlayv(sources.size(), sources.data()); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 1389835db..7324b6747 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -7,6 +7,10 @@ namespace MWSound { + // For testing individual PlayMode flags + inline int operator&(int a, PlayMode b) { return a & static_cast(b); } + inline int operator&(PlayMode a, PlayMode b) { return static_cast(a) & static_cast(b); } + class SoundBase { SoundBase& operator=(const SoundBase&) = delete; SoundBase(const SoundBase&) = delete; @@ -48,11 +52,11 @@ namespace MWSound float getMinDistance() const { return mMinDistance; } float getMaxDistance() const { return mMaxDistance; } - MWBase::SoundManager::PlayType getPlayType() const - { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } - bool getUseEnv() const { return !(mFlags&MWBase::SoundManager::Play_NoEnv); } - bool getIsLooping() const { return mFlags&MWBase::SoundManager::Play_Loop; } - bool getDistanceCull() const { return mFlags&MWBase::SoundManager::Play_RemoveAtDistance; } + MWSound::Type getPlayType() const + { return static_cast(mFlags&MWSound::Type::Mask); } + bool getUseEnv() const { return !(mFlags&MWSound::PlayMode::NoEnv); } + bool getIsLooping() const { return mFlags&MWSound::PlayMode::Loop; } + bool getDistanceCull() const { return mFlags&MWSound::PlayMode::RemoveAtDistance; } bool getIs3D() const { return mFlags&Play_3D; } void init(const osg::Vec3f& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2e8ff85c8..0b6d8ff34 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -35,6 +35,9 @@ namespace MWSound { + // For combining PlayMode and Type flags + inline int operator|(PlayMode a, Type b) { return static_cast(a) | static_cast(b); } + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) , mFallback(fallbackMap) @@ -299,17 +302,17 @@ namespace MWSound static float maxDistance = std::max(fAudioVoiceDefaultMaxDistance * fAudioMaxDistanceMult, minDistance); bool played; - float basevol = volumeFromType(Play_TypeVoice); + float basevol = volumeFromType(Type::Voice); Stream *sound = getStreamRef(); if(playlocal) { - sound->init(1.0f, basevol, 1.0f, Play_NoEnv|Play_TypeVoice|Play_2D); + sound->init(1.0f, basevol, 1.0f, PlayMode::NoEnv|Type::Voice|Play_2D); played = mOutput->streamSound(decoder, sound); } else { sound->init(pos, 1.0f, basevol, 1.0f, minDistance, maxDistance, - Play_Normal|Play_TypeVoice|Play_3D); + PlayMode::Normal|Type::Voice|Play_3D); played = mOutput->streamSound3D(decoder, sound, true); } if(!played) @@ -321,26 +324,25 @@ namespace MWSound } // Gets the combined volume settings for the given sound type - float SoundManager::volumeFromType(PlayType type) const + float SoundManager::volumeFromType(Type type) const { float volume = mMasterVolume; switch(type) { - case Play_TypeSfx: + case Type::Sfx: volume *= mSFXVolume; break; - case Play_TypeVoice: + case Type::Voice: volume *= mVoiceVolume; break; - case Play_TypeFoot: + case Type::Foot: volume *= mFootstepsVolume; break; - case Play_TypeMusic: + case Type::Music: volume *= mMusicVolume; break; - case Play_TypeMask: - break; - default: + case Type::Movie: + case Type::Mask: break; } return volume; @@ -369,8 +371,8 @@ namespace MWSound decoder->open(filename); mMusic = getStreamRef(); - mMusic->init(1.0f, volumeFromType(Play_TypeMusic), 1.0f, - Play_NoEnv|Play_TypeMusic|Play_2D); + mMusic->init(1.0f, volumeFromType(Type::Music), 1.0f, + PlayMode::NoEnv|Type::Music|Play_2D); mOutput->streamSound(decoder, mMusic); } @@ -527,13 +529,13 @@ namespace MWSound } - Stream *SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) + Stream *SoundManager::playTrack(const DecoderPtr& decoder, Type type) { if(!mOutput->isInitialized()) return nullptr; Stream *track = getStreamRef(); - track->init(1.0f, volumeFromType(type), 1.0f, Play_NoEnv|type|Play_2D); + track->init(1.0f, volumeFromType(type), 1.0f, PlayMode::NoEnv|type|Play_2D); if(!mOutput->streamSound(decoder, track)) { mUnusedStreams.push_back(track); @@ -561,7 +563,7 @@ namespace MWSound } - Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayType type, PlayMode mode, float offset) + Sound *SoundManager::playSound(const std::string& soundId, float volume, float pitch, Type type, PlayMode mode, float offset) { if(!mOutput->isInitialized()) return nullptr; @@ -588,7 +590,7 @@ namespace MWSound } Sound *SoundManager::playSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, + float volume, float pitch, Type type, PlayMode mode, float offset) { if(!mOutput->isInitialized()) @@ -599,7 +601,7 @@ namespace MWSound if(!sfx) return nullptr; const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3()); - if((mode&Play_RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) + if((mode&PlayMode::RemoveAtDistance) && (mListenerPos-objpos).length2() > 2000*2000) return nullptr; // Only one copy of given sound can be played at time on ptr, so stop previous copy @@ -607,7 +609,7 @@ namespace MWSound bool played; Sound *sound = getSoundRef(); - if(!(mode&Play_NoPlayerLocal) && ptr == MWMechanics::getPlayer()) + if(!(mode&PlayMode::NoPlayerLocal) && ptr == MWMechanics::getPlayer()) { sound->init(volume * sfx->mVolume, volumeFromType(type), pitch, mode|type|Play_2D); played = mOutput->playSound(sound, sfx->mHandle, offset); @@ -635,7 +637,7 @@ namespace MWSound } Sound *SoundManager::playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, + float volume, float pitch, Type type, PlayMode mode, float offset) { if(!mOutput->isInitialized()) @@ -772,7 +774,7 @@ namespace MWSound { if(mOutput->isInitialized()) { - types &= Play_TypeMask; + types = types & Type::Mask; mOutput->pauseSounds(types); mPausedSoundTypes |= types; } @@ -782,7 +784,7 @@ namespace MWSound { if(mOutput->isInitialized()) { - types &= types&Play_TypeMask&mPausedSoundTypes; + types = types & Type::Mask & mPausedSoundTypes; mOutput->resumeSounds(types); mPausedSoundTypes &= ~types; } @@ -932,7 +934,7 @@ namespace MWSound if(soundIdChanged) { mOutput->finishSound(mNearWaterSound); - mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop); } else if (sfx) mNearWaterSound->setVolume(volume * sfx->mVolume); @@ -941,7 +943,7 @@ namespace MWSound else if (volume > 0.0f) { LastCell = curcell; - mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + mNearWaterSound = playSound(soundId, volume, 1.0f, Type::Sfx, PlayMode::Loop); } } @@ -1084,7 +1086,7 @@ namespace MWSound { // Play underwater sound (after updating sounds) if(!mUnderwaterSound) - mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv); + mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Type::Sfx, PlayMode::LoopNoEnv); } mOutput->finishUpdate(); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index e5889e36d..d2dce3928 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -135,7 +135,7 @@ namespace MWSound std::string mNextMusic; - float volumeFromType(PlayType type) const; + float volumeFromType(Type type) const; SoundManager(const SoundManager &rhs); SoundManager& operator=(const SoundManager &rhs); @@ -186,7 +186,7 @@ namespace MWSound /// and get an average loudness value (scale [0,1]) at the current time position. /// If the actor is not saying anything, returns 0. - virtual Stream *playTrack(const DecoderPtr& decoder, PlayType type); + virtual Stream *playTrack(const DecoderPtr& decoder, Type type); ///< Play a 2D audio track, using a custom decoder virtual void stopTrack(Stream *stream); @@ -197,18 +197,18 @@ namespace MWSound /// returned by \ref playTrack). Only intended to be called by the track /// decoder's read method. - virtual Sound *playSound(const std::string& soundId, float volume, float pitch, PlayType type=Play_TypeSfx, PlayMode mode=Play_Normal, float offset=0); + virtual Sound *playSound(const std::string& soundId, float volume, float pitch, Type type=Type::Sfx, PlayMode mode=PlayMode::Normal, float offset=0); ///< Play a sound, independently of 3D-position ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const MWWorld::ConstPtr &reference, const std::string& soundId, - float volume, float pitch, PlayType type=Play_TypeSfx, - PlayMode mode=Play_Normal, float offset=0); + float volume, float pitch, Type type=Type::Sfx, + PlayMode mode=PlayMode::Normal, float offset=0); ///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified. ///< @param offset Number of seconds into the sound to start playback. virtual Sound *playSound3D(const osg::Vec3f& initialPos, const std::string& soundId, - float volume, float pitch, PlayType type, PlayMode mode, float offset=0); + float volume, float pitch, Type type, PlayMode mode, float offset=0); ///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using Sound::setPosition. ///< @param offset Number of seconds into the sound to start playback. @@ -237,10 +237,10 @@ namespace MWSound virtual bool getSoundPlaying(const MWWorld::ConstPtr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? - virtual void pauseSounds(int types=Play_TypeMask); + virtual void pauseSounds(int types); ///< Pauses all currently playing sounds, including music. - virtual void resumeSounds(int types=Play_TypeMask); + virtual void resumeSounds(int types); ///< Resumes all previously paused sounds. virtual void update(float duration); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 468207e81..32a3c8f96 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -27,18 +27,18 @@ void MWWorld::Action::execute (const Ptr& actor, bool noSound) { if(!mSoundId.empty() && !noSound) { - MWBase::SoundManager::PlayMode envType = MWBase::SoundManager::Play_Normal; + MWSound::PlayMode envType = MWSound::PlayMode::Normal; // Action sounds should not have a distortion in GUI mode // example: take an item or drink a potion underwater if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWindowManager()->isGuiMode()) { - envType = MWBase::SoundManager::Play_NoEnv; + envType = MWSound::PlayMode::NoEnv; } if(mKeepSound && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, - MWBase::SoundManager::Play_TypeSfx, envType, mSoundOffset + MWSound::Type::Sfx, envType, mSoundOffset ); else { @@ -46,13 +46,11 @@ void MWWorld::Action::execute (const Ptr& actor, bool noSound) if(mKeepSound) MWBase::Environment::get().getSoundManager()->playSound3D( (local ? actor : mTarget).getRefData().getPosition().asVec3(), - mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - envType, mSoundOffset + mSoundId, 1.0, 1.0, MWSound::Type::Sfx, envType, mSoundOffset ); else MWBase::Environment::get().getSoundManager()->playSound3D(local ? actor : mTarget, - mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, - envType, mSoundOffset + mSoundId, 1.0, 1.0, MWSound::Type::Sfx, envType, mSoundOffset ); } } diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 64d601563..5b15583bf 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -283,7 +283,8 @@ namespace MWWorld MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) { - MWBase::Sound *sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWBase::Sound *sound = sndMgr->playSound3D(pos, state.mSoundIds.at(it), 1.0f, 1.0f, + MWSound::Type::Sfx, MWSound::PlayMode::Loop); if (sound) state.mSounds.push_back(sound); } @@ -377,10 +378,9 @@ namespace MWWorld MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject, ESM::RT_Target, it->mSpellId, it->mSourceName); + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) - { - MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter)); - } + sndMgr->stopSound(it->mSounds.at(soundIter)); mParent->removeChild(it->mNode); @@ -581,11 +581,10 @@ namespace MWWorld createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - for (size_t soundIter = 0; soundIter != state.mSoundIds.size(); soundIter++) { MWBase::Sound *sound = sndMgr->playSound3D(esm.mPosition, state.mSoundIds.at(soundIter), 1.0f, 1.0f, - MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + MWSound::Type::Sfx, MWSound::PlayMode::Loop); if (sound) state.mSounds.push_back(sound); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c4b46961c..2f0a2f8cf 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -731,8 +731,10 @@ void WeatherManager::update(float duration, bool paused) { stopSounds(); if (!mResult.mAmbientLoopSoundID.empty()) - mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, mResult.mAmbientSoundVolume, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - + mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound( + mResult.mAmbientLoopSoundID, mResult.mAmbientSoundVolume, 1.0, + MWSound::Type::Sfx, MWSound::PlayMode::Loop + ); mPlayingSoundID = mResult.mAmbientLoopSoundID; } else if (mAmbientSound) From d68e1581ee3652bcb7f93457d7e67008c3f79538 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Sep 2017 05:40:20 -0700 Subject: [PATCH 179/521] Use an std::array for the OpenAL stream buffers --- apps/openmw/mwsound/openal_output.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1a9baed77..64aa1aff7 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -273,13 +273,12 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) // class OpenAL_SoundStream { - static const ALuint sNumBuffers = 6; static const ALfloat sBufferLength; private: ALuint mSource; - ALuint mBuffers[sNumBuffers]; + std::array mBuffers; ALint mCurrentBufIdx; ALenum mFormat; @@ -392,16 +391,17 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder) - : mSource(src), mBuffers{0}, mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0) + : mSource(src), mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0) , mBufferSize(0), mFrameSize(0), mSilence(0), mDecoder(std::move(decoder)) , mLoudnessAnalyzer(nullptr) { + mBuffers.fill(0); } OpenAL_SoundStream::~OpenAL_SoundStream() { if(mBuffers[0] && alIsBuffer(mBuffers[0])) - alDeleteBuffers(sNumBuffers, mBuffers); + alDeleteBuffers(mBuffers.size(), mBuffers.data()); alGetError(); mDecoder->close(); @@ -409,7 +409,7 @@ OpenAL_SoundStream::~OpenAL_SoundStream() bool OpenAL_SoundStream::init(bool getLoudnessData) { - alGenBuffers(sNumBuffers, mBuffers); + alGenBuffers(mBuffers.size(), mBuffers.data()); ALenum err = getALError(); if(err != AL_NO_ERROR) return false; @@ -542,10 +542,10 @@ ALint OpenAL_SoundStream::refillQueue() ALint queued; alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - if(!mIsFinished && (ALuint)queued < sNumBuffers) + if(!mIsFinished && (ALuint)queued < mBuffers.size()) { std::vector data(mBufferSize); - for(;!mIsFinished && (ALuint)queued < sNumBuffers;++queued) + for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued) { size_t got = mDecoder->read(&data[0], data.size()); if(got < data.size()) @@ -561,7 +561,7 @@ ALint OpenAL_SoundStream::refillQueue() ALuint bufid = mBuffers[mCurrentBufIdx]; alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); - mCurrentBufIdx = (mCurrentBufIdx+1) % sNumBuffers; + mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size(); } } } From 2abf7f1752bfd06530425c5d33d6ae73653d90be Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 15 Sep 2017 12:19:12 -0400 Subject: [PATCH 180/521] Remove unnecessary cache dump --- components/terrain/world.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 22c65b62c..335bb496b 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -77,7 +77,6 @@ void World::updateTextureFiltering() void World::clearAssociatedCaches() { - mTextureManager->clearCache(); mChunkManager->clearCache(); } From 44738e1141464605104db17d596a38f6905e2e24 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 11 Sep 2017 20:49:22 +0400 Subject: [PATCH 181/521] Clear player fields upon reload (bug #2639) --- apps/openmw/mwworld/player.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d233fba6f..19bf7f55e 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -276,6 +276,29 @@ namespace MWWorld mAutoMove = false; mForwardBackward = 0; mTeleported = false; + mAttackingOrSpell = false; + mCurrentCrimeId = -1; + mPaidCrimeId = -1; + mLastKnownExteriorPosition = osg::Vec3f(0,0,0); + + for (int i=0; i Date: Sat, 16 Sep 2017 15:04:15 +0100 Subject: [PATCH 182/521] Update differences.rst --- docs/source/reference/modding/differences.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/modding/differences.rst b/docs/source/reference/modding/differences.rst index e7cac15d0..d492dc542 100644 --- a/docs/source/reference/modding/differences.rst +++ b/docs/source/reference/modding/differences.rst @@ -12,14 +12,14 @@ OpenMW is designed to be able to use all the normal Morrowind mod files such as Multiple Data Folders --------------------- -The largest difference between OpenMW and Morrowind in terms of data structure is OpenMW's support of multiple data folders. This has many advantages, especially when it comes to unistalling mods and preventing unintentional overwrites of files. +The largest difference between OpenMW and Morrowind in terms of data structure is OpenMW's support of multiple data folders. This has many advantages, especially when it comes to uninstalling mods and preventing unintentional overwrites of files. .. warning:: Most mods can still be installed into the root OpenMW data folder, but this is not recommended. To install mods via this new feature: -#. Open ``openmw.cfg`` with your preffered text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory. +#. Open ``openmw.cfg`` with your preferred text editor. It is located as described in :doc:`paths` and *not* in your OpenMW root directory. #. Find or search for ``data=``. This is located very near the bottom of the file. #. Add a new line below this line and make a new entry of the format ``data="path/to/your/mod"`` #. Make as many of these entries as you need for each mod folder you want to include. From f594eda5744a7cede847a262a0cd61b4849778ae Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 16 Sep 2017 23:04:54 +0000 Subject: [PATCH 183/521] Reset attackStrength when starting a new attack (Fixes #3935) --- apps/openmw/mwmechanics/character.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2f645279a..bfe8812e6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1216,6 +1216,7 @@ bool CharacterController::updateWeaponState() if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block)) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); + mAttackStrength = 0; if(mWeaponType == WeapType_Spell) { // Unset casting flag, otherwise pressing the mouse button down would From acd6d9cd72cc4c24d552403a324a5e34a43c887b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Sep 2017 19:36:49 -0700 Subject: [PATCH 184/521] Try opening the default device fallback in OpenAL_Output --- apps/openmw/mwsound/openal_output.cpp | 36 +++++++++++++------------ apps/openmw/mwsound/soundmanagerimp.cpp | 19 +++---------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 64aa1aff7..85a7d13ba 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -595,24 +595,24 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname deinit(); mDevice = alcOpenDevice(devname.c_str()); - if(!mDevice) + if(!mDevice && !devname.empty()) { - if(devname.empty()) - std::cerr<< "Failed to open default audio device" <removeAll(); - for(size_t i = 0;i < mFreeSources.size();i++) - alDeleteSources(1, &mFreeSources[i]); + std::for_each(mFreeSources.cbegin(), mFreeSources.cend(), + [](ALuint source) -> void + { alDeleteSources(1, &source); } + ); mFreeSources.clear(); if(mEffectSlot) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0b6d8ff34..03bff89b4 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -26,11 +26,7 @@ #include "sound.hpp" #include "openal_output.hpp" -#define SOUND_OUT "OpenAL" #include "ffmpeg_decoder.hpp" -#ifndef SOUND_IN -#define SOUND_IN "FFmpeg" -#endif namespace MWSound @@ -60,6 +56,8 @@ namespace MWSound , mUnderwaterSound(nullptr) , mNearWaterSound(nullptr) { + std::cout<< "Initializing sound..." < 0 ? HrtfMode::Enable : HrtfMode::Disable; - std::cout << "Sound output: " << SOUND_OUT << std::endl; - std::cout << "Sound decoder: " << SOUND_IN << std::endl; - std::vector names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; std::for_each(names.cbegin(), names.cend(), @@ -103,15 +98,9 @@ namespace MWSound std::cout.flush(); std::string devname = Settings::Manager::getString("device", "Sound"); - bool inited = mOutput->init(devname, hrtfname, hrtfmode); - if(!inited && !devname.empty()) - { - std::cerr<< "Failed to initialize device \""<init(std::string(), hrtfname, hrtfmode); - } - if(!inited) + if(!mOutput->init(devname, hrtfname, hrtfmode)) { - std::cerr<< "Failed to initialize default audio device, sound disabled" < Date: Fri, 15 Sep 2017 21:21:49 -0700 Subject: [PATCH 185/521] Print a bit more information for sound initialization --- apps/openmw/mwsound/openal_output.cpp | 13 +++++++++++++ apps/openmw/mwsound/soundmanagerimp.cpp | 19 ++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 85a7d13ba..a6d3e4b12 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -594,6 +594,8 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname { deinit(); + std::cout<< "Initializing OpenAL..." < 0 ? HrtfMode::Enable : HrtfMode::Disable; + std::string devname = Settings::Manager::getString("device", "Sound"); + if(!mOutput->init(devname, hrtfname, hrtfmode)) + { + std::cerr<< "Failed to initialize audio output, sound disabled" < names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; std::for_each(names.cbegin(), names.cend(), @@ -97,13 +105,6 @@ namespace MWSound ); std::cout.flush(); - std::string devname = Settings::Manager::getString("device", "Sound"); - if(!mOutput->init(devname, hrtfname, hrtfmode)) - { - std::cerr<< "Failed to initialize audio output, sound disabled" <enumerateHrtf(); if(!names.empty()) { From 1e729e8da96b9ec08046c899aa25eccaf94beecf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 01:56:58 -0700 Subject: [PATCH 186/521] Avoid more explicit loops --- apps/openmw/mwsound/soundmanagerimp.cpp | 158 ++++++++++-------------- 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2a65be737..f50b3f2fb 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -99,20 +99,16 @@ namespace MWSound std::vector names = mOutput->enumerate(); std::cout <<"Enumerated output devices:\n"; - std::for_each(names.cbegin(), names.cend(), - [](const std::string &name) -> void - { std::cout <<" "<enumerateHrtf(); if(!names.empty()) { std::cout<< "Enumerated HRTF names:\n"; - std::for_each(names.cbegin(), names.cend(), - [](const std::string &name) -> void - { std::cout<< " "<begin(); - for(;sfxiter != mSoundBuffers->end();++sfxiter) + for(Sound_Buffer &sfx : *mSoundBuffers) { - if(sfxiter->mHandle) - mOutput->unloadSound(sfxiter->mHandle); - sfxiter->mHandle = 0; + if(sfx.mHandle) + mOutput->unloadSound(sfx.mHandle); + sfx.mHandle = 0; } mUnusedBuffers.clear(); mOutput.reset(); @@ -668,11 +663,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &snd : snditer->second) { - if(sndidx->second == sfx) - mOutput->finishSound(sndidx->first); + if(snd.second == sfx) + mOutput->finishSound(snd.first); } } } @@ -682,33 +676,28 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.find(ptr); if(snditer != mActiveSounds.end()) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) - mOutput->finishSound(sndidx->first); + for(SoundBufferRefPair &snd : snditer->second) + mOutput->finishSound(snd.first); } + SaySoundMap::iterator sayiter = mActiveSaySounds.find(ptr); + if(sayiter != mActiveSaySounds.end()) + mOutput->finishStream(sayiter->second); } void SoundManager::stopSound(const MWWorld::CellStore *cell) { - SoundMap::iterator snditer = mActiveSounds.begin(); - for(;snditer != mActiveSounds.end();++snditer) + for(SoundMap::value_type &snd : mActiveSounds) { - if(snditer->first != MWWorld::ConstPtr() && - snditer->first != MWMechanics::getPlayer() && - snditer->first.getCell() == cell) + if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) - mOutput->finishSound(sndidx->first); + for(SoundBufferRefPair &sndbuf : snd.second) + mOutput->finishSound(sndbuf.first); } } - SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - for(;sayiter != mActiveSaySounds.end();++sayiter) + for(SaySoundMap::value_type &snd : mActiveSaySounds) { - if(sayiter->first != MWWorld::ConstPtr() && - sayiter->first != MWMechanics::getPlayer() && - sayiter->first.getCell() == cell) - mOutput->finishStream(sayiter->second); + if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell) + mOutput->finishStream(snd.second); } } @@ -718,11 +707,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snditer->second) { - if(sndidx->second == sfx) - mOutput->finishSound(sndidx->first); + if(sndbuf.second == sfx) + mOutput->finishSound(sndbuf.first); } } } @@ -734,11 +722,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snditer->second) { - if(sndidx->second == sfx) - sndidx->first->setFadeout(duration); + if(sndbuf.second == sfx) + sndbuf.first->setFadeout(duration); } } } @@ -749,12 +736,10 @@ namespace MWSound if(snditer != mActiveSounds.end()) { Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); - SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) - { - if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first)) - return true; - } + return std::find_if(snditer->second.cbegin(), snditer->second.cend(), + [this,sfx](const SoundBufferRefPair &snd) -> bool + { return snd.second == sfx && mOutput->isSoundPlaying(snd.first); } + ) != snditer->second.cend(); } return false; } @@ -813,10 +798,8 @@ namespace MWSound if(total == 0) { - std::for_each(regn->mSoundList.cbegin(), regn->mSoundList.cend(), - [](const ESM::Region::SoundRef &sndref) -> void - { total += (int)sndref.mChance; } - ); + for(const ESM::Region::SoundRef &sndref : regn->mSoundList) + total += (int)sndref.mChance; if(total == 0) return; } @@ -824,20 +807,15 @@ namespace MWSound int r = Misc::Rng::rollDice(total); int pos = 0; - std::find_if_not(regn->mSoundList.cbegin(), regn->mSoundList.cend(), - [&pos, r, this](const ESM::Region::SoundRef &sndref) -> bool + for(const ESM::Region::SoundRef &sndref : regn->mSoundList) + { + if(r - pos < sndref.mChance) { - if(r - pos < sndref.mChance) - { - playSound(sndref.mSound.toString(), 1.0f, 1.0f); - // Played this sound, stop iterating - return false; - } - pos += sndref.mChance; - // Not this sound, keep iterating - return true; + playSound(sndref.mSound.toString(), 1.0f, 1.0f); + break; } - ); + pos += sndref.mChance; + } } void SoundManager::updateWaterSound(float /*duration*/) @@ -1125,28 +1103,23 @@ namespace MWSound if(!mOutput->isInitialized()) return; mOutput->startUpdate(); - SoundMap::iterator snditer = mActiveSounds.begin(); - for(;snditer != mActiveSounds.end();++snditer) + for(SoundMap::value_type &snd : mActiveSounds) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snd.second) { - Sound *sound = sndidx->first; + Sound *sound = sndbuf.first; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateSound(sound); } } - SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - for(;sayiter != mActiveSaySounds.end();++sayiter) + for(SaySoundMap::value_type &snd : mActiveSaySounds) { - Stream *sound = sayiter->second; + Stream *sound = snd.second; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } - TrackList::iterator trkiter = mActiveTracks.begin(); - for(;trkiter != mActiveTracks.end();++trkiter) + for(Stream *sound : mActiveTracks) { - Stream *sound = *trkiter; sound->setBaseVolume(volumeFromType(sound->getPlayType())); mOutput->updateStream(sound); } @@ -1252,36 +1225,35 @@ namespace MWSound void SoundManager::clear() { - SoundMap::iterator snditer = mActiveSounds.begin(); - for(;snditer != mActiveSounds.end();++snditer) + stopMusic(); + + for(SoundMap::value_type &snd : mActiveSounds) { - SoundBufferRefPairList::iterator sndidx = snditer->second.begin(); - for(;sndidx != snditer->second.end();++sndidx) + for(SoundBufferRefPair &sndbuf : snd.second) { - mOutput->finishSound(sndidx->first); - mUnusedSounds.push_back(sndidx->first); - Sound_Buffer *sfx = sndidx->second; + mOutput->finishSound(sndbuf.first); + mUnusedSounds.push_back(sndbuf.first); + Sound_Buffer *sfx = sndbuf.second; if(sfx->mUses-- == 1) mUnusedBuffers.push_front(sfx); } } mActiveSounds.clear(); - SaySoundMap::iterator sayiter = mActiveSaySounds.begin(); - for(;sayiter != mActiveSaySounds.end();++sayiter) + mUnderwaterSound = nullptr; + mNearWaterSound = nullptr; + + for(SaySoundMap::value_type &snd : mActiveSaySounds) { - mOutput->finishStream(sayiter->second); - mUnusedStreams.push_back(sayiter->second); + mOutput->finishStream(snd.second); + mUnusedStreams.push_back(snd.second); } mActiveSaySounds.clear(); - TrackList::iterator trkiter = mActiveTracks.begin(); - for(;trkiter != mActiveTracks.end();++trkiter) + + for(Stream *sound : mActiveTracks) { - mOutput->finishStream(*trkiter); - mUnusedStreams.push_back(*trkiter); + mOutput->finishStream(sound); + mUnusedStreams.push_back(sound); } mActiveTracks.clear(); - mUnderwaterSound = nullptr; - mNearWaterSound = nullptr; - stopMusic(); } } From 4b448c74d24023c9f43c952335829c3c287061f7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 03:19:06 -0700 Subject: [PATCH 187/521] Use range-for loops instead of for_each --- apps/openmw/mwsound/openal_output.cpp | 152 +++++++++++--------------- 1 file changed, 66 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index a6d3e4b12..77a14a398 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -192,12 +192,11 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, }}; - auto fmt = std::find_if(fmtlist.cbegin(), fmtlist.cend(), - [chans,type](const FormatEntry &fmt) -> bool - { return fmt.chans == chans && fmt.type == type; } - ); - if(fmt != fmtlist.cend()) - return fmt->format; + for(auto &fmt : fmtlist) + { + if(fmt.chans == chans && fmt.type == type) + return fmt.format; + } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { @@ -209,18 +208,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, }}; - ALenum format = AL_NONE; - std::find_if(mcfmtlist.cbegin(), mcfmtlist.cend(), - [&format,chans,type](const FormatEntryExt &fmt) -> bool + for(auto &fmt : mcfmtlist) + { + if(fmt.chans == chans && fmt.type == type) { - if(fmt.chans == chans && fmt.type == type) - format = alGetEnumValue(fmt.name); - return format != 0 && format != -1; + ALenum format = alGetEnumValue(fmt.name); + if(format != 0 && format != -1) + return format; } - ); - if(format != 0 && format != -1) - return format; + } } if(alIsExtensionPresent("AL_EXT_FLOAT32")) { @@ -228,18 +225,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, }}; - ALenum format = AL_NONE; - std::find_if(fltfmtlist.cbegin(), fltfmtlist.cend(), - [&format,chans,type](const FormatEntryExt &fmt) -> bool + for(auto &fmt : fltfmtlist) + { + if(fmt.chans == chans && fmt.type == type) { - if(fmt.chans == chans && fmt.type == type) - format = alGetEnumValue(fmt.name); - return format != 0 && format != -1; + ALenum format = alGetEnumValue(fmt.name); + if(format != 0 && format != -1) + return format; } - ); - if(format != 0 && format != -1) - return format; + } if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { @@ -249,16 +244,15 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, }}; - std::find_if(fltmcfmtlist.cbegin(), fltmcfmtlist.cend(), - [&format,chans,type](const FormatEntryExt &fmt) -> bool + for(auto &fmt : fltmcfmtlist) + { + if(fmt.chans == chans && fmt.type == type) { - if(fmt.chans == chans && fmt.type == type) - format = alGetEnumValue(fmt.name); - return format != 0 && format != -1; + ALenum format = alGetEnumValue(fmt.name); + if(format != 0 && format != -1) + return format; } - ); - if(format != 0 && format != -1) - return format; + } } } @@ -547,11 +541,11 @@ ALint OpenAL_SoundStream::refillQueue() std::vector data(mBufferSize); for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued) { - size_t got = mDecoder->read(&data[0], data.size()); + size_t got = mDecoder->read(data.data(), data.size()); if(got < data.size()) { mIsFinished = true; - std::memset(&data[got], mSilence, data.size()-got); + std::fill(data.begin()+got, data.end(), mSilence); } if(got > 0) { @@ -559,7 +553,7 @@ ALint OpenAL_SoundStream::refillQueue() mLoudnessAnalyzer->analyzeLoudness(data); ALuint bufid = mBuffers[mCurrentBufIdx]; - alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate); + alBufferData(bufid, mFormat, data.data(), data.size(), mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size(); } @@ -837,10 +831,8 @@ void OpenAL_Output::deinit() { mStreamThread->removeAll(); - std::for_each(mFreeSources.cbegin(), mFreeSources.cend(), - [](ALuint source) -> void - { alDeleteSources(1, &source); } - ); + for(ALuint source : mFreeSources) + alDeleteSources(1, &source); mFreeSources.clear(); if(mEffectSlot) @@ -1383,23 +1375,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi if(mWaterFilter) { ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [filter](const SoundVec::value_type &item) -> void - { - if(item->getUseEnv()) - alSourcei(GET_PTRID(item->mHandle), AL_DIRECT_FILTER, filter); - } - ); - std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), - [filter](const StreamVec::value_type &item) -> void - { - if(item->getUseEnv()) - alSourcei( - reinterpret_cast(item->mHandle)->mSource, - AL_DIRECT_FILTER, filter - ); - } - ); + for(Sound *sound : mActiveSounds) + { + if(sound->getUseEnv()) + alSourcei(GET_PTRID(sound->mHandle), AL_DIRECT_FILTER, filter); + } + for(Stream *sound : mActiveStreams) + { + if(sound->getUseEnv()) + alSourcei( + reinterpret_cast(sound->mHandle)->mSource, + AL_DIRECT_FILTER, filter + ); + } } // Update the environment effect if(mEffectSlot) @@ -1418,23 +1406,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi void OpenAL_Output::pauseSounds(int types) { std::vector sources; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [types,&sources](const SoundVec::value_type &sound) -> void - { - if(sound && sound->mHandle && (types&sound->getPlayType())) - sources.push_back(GET_PTRID(sound->mHandle)); - } - ); - std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), - [types,&sources](const StreamVec::value_type &stream) -> void + for(Sound *sound : mActiveSounds) + { + if((types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); + } + for(Stream *sound : mActiveStreams) + { + if((types&sound->getPlayType())) { - if(stream && stream->mHandle && (types&stream->getPlayType())) - { - OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); - sources.push_back(strm->mSource); - } + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + sources.push_back(stream->mSource); } - ); + } if(!sources.empty()) { alSourcePausev(sources.size(), sources.data()); @@ -1445,23 +1429,19 @@ void OpenAL_Output::pauseSounds(int types) void OpenAL_Output::resumeSounds(int types) { std::vector sources; - std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(), - [types,&sources](const SoundVec::value_type &sound) -> void - { - if(sound && sound->mHandle && (types&sound->getPlayType())) - sources.push_back(GET_PTRID(sound->mHandle)); - } - ); - std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(), - [types,&sources](const StreamVec::value_type &stream) -> void + for(Sound *sound : mActiveSounds) + { + if((types&sound->getPlayType())) + sources.push_back(GET_PTRID(sound->mHandle)); + } + for(Stream *sound : mActiveStreams) + { + if((types&sound->getPlayType())) { - if(stream && stream->mHandle && (types&stream->getPlayType())) - { - OpenAL_SoundStream *strm = reinterpret_cast(stream->mHandle); - sources.push_back(strm->mSource); - } + OpenAL_SoundStream *stream = reinterpret_cast(sound->mHandle); + sources.push_back(stream->mSource); } - ); + } if(!sources.empty()) { alSourcePlayv(sources.size(), sources.data()); From 5c53ee42a10d8037420f442b65b2ac9e7045ad82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 03:48:41 -0700 Subject: [PATCH 188/521] Prepare all Sound_Buffers when retrieving the first one --- apps/openmw/mwsound/soundmanagerimp.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f50b3f2fb..949b724f1 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -185,9 +185,23 @@ namespace MWSound // minRange, and maxRange), and ensure it's ready for use. Sound_Buffer *SoundManager::loadSound(const std::string &soundId) { +#ifdef __GNUC__ +#define LIKELY(x) __builtin_expect((bool)(x), true) +#define UNLIKELY(x) __builtin_expect((bool)(x), false) +#else +#define LIKELY(x) (bool)(x) +#define UNLIKELY(x) (bool)(x) +#endif + if(UNLIKELY(mBufferNameMap.empty())) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + for(const ESM::Sound &sound : world->getStore().get()) + insertSound(Misc::StringUtils::lowerCase(sound.mId), &sound); + } + Sound_Buffer *sfx; NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId); - if(snd != mBufferNameMap.end()) + if(LIKELY(snd != mBufferNameMap.end())) sfx = snd->second; else { @@ -196,6 +210,8 @@ namespace MWSound if(!sound) return nullptr; sfx = insertSound(soundId, sound); } +#undef LIKELY +#undef UNLIKELY if(!sfx->mHandle) { From 41bb35655bf6da3de0b2bf8ff546dac2ce1dcec2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Sep 2017 04:24:01 -0700 Subject: [PATCH 189/521] Avoid an extra call to get the buffer size --- apps/openmw/mwsound/openal_output.cpp | 28 +++++++++++-------------- apps/openmw/mwsound/openal_output.hpp | 5 ++--- apps/openmw/mwsound/sound_output.hpp | 5 ++--- apps/openmw/mwsound/soundmanagerimp.cpp | 9 ++++---- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 77a14a398..3fb1c1c13 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -941,7 +941,7 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) } -Sound_Handle OpenAL_Output::loadSound(const std::string &fname) +std::pair OpenAL_Output::loadSound(const std::string &fname) { getALError(); @@ -966,27 +966,31 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname) decoder->getInfo(&srate, &chans, &type); format = getALFormat(chans, type); - if(!format) return nullptr; + if(!format) return std::make_pair(nullptr, 0); decoder->readAll(data); decoder->close(); + ALint size; ALuint buf = 0; alGenBuffers(1, &buf); - alBufferData(buf, format, &data[0], data.size(), srate); + alBufferData(buf, format, data.data(), data.size(), srate); + alGetBufferi(buf, AL_SIZE, &size); if(getALError() != AL_NO_ERROR) { if(buf && alIsBuffer(buf)) alDeleteBuffers(1, &buf); getALError(); - return nullptr; + return std::make_pair(nullptr, 0); } - return MAKE_PTRID(buf); + return std::make_pair(MAKE_PTRID(buf), size); } -void OpenAL_Output::unloadSound(Sound_Handle data) +size_t OpenAL_Output::unloadSound(Sound_Handle data) { ALuint buffer = GET_PTRID(data); + if(!buffer) return 0; + // Make sure no sources are playing this buffer before unloading it. SoundVec::const_iterator iter = mActiveSounds.begin(); for(;iter != mActiveSounds.end();++iter) @@ -1003,19 +1007,11 @@ void OpenAL_Output::unloadSound(Sound_Handle data) alSourcei(source, AL_BUFFER, 0); } } - alDeleteBuffers(1, &buffer); - getALError(); -} - -size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const -{ - ALuint buffer = GET_PTRID(data); ALint size = 0; - alGetBufferi(buffer, AL_SIZE, &size); + alDeleteBuffers(1, &buffer); getALError(); - - return (ALuint)size; + return size; } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 8a7b7b3b8..afc869733 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -66,9 +66,8 @@ namespace MWSound virtual std::vector enumerateHrtf(); virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode); - virtual Sound_Handle loadSound(const std::string &fname); - virtual void unloadSound(Sound_Handle data); - virtual size_t getSoundDataSize(Sound_Handle data) const; + virtual std::pair loadSound(const std::string &fname); + virtual size_t unloadSound(Sound_Handle data); virtual bool playSound(Sound *sound, Sound_Handle data, float offset); virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index ad18e0d40..871562dc0 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -36,9 +36,8 @@ namespace MWSound virtual std::vector enumerateHrtf() = 0; virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0; - virtual Sound_Handle loadSound(const std::string &fname) = 0; - virtual void unloadSound(Sound_Handle data) = 0; - virtual size_t getSoundDataSize(Sound_Handle data) const = 0; + virtual std::pair loadSound(const std::string &fname) = 0; + virtual size_t unloadSound(Sound_Handle data) = 0; virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0; virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 949b724f1..ac87a2f06 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -215,10 +215,11 @@ namespace MWSound if(!sfx->mHandle) { - sfx->mHandle = mOutput->loadSound(sfx->mResourceName); + size_t size; + std::tie(sfx->mHandle, size) = mOutput->loadSound(sfx->mResourceName); if(!sfx->mHandle) return nullptr; - mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle); + mBufferCacheSize += size; if(mBufferCacheSize > mBufferCacheMax) { do { @@ -229,8 +230,8 @@ namespace MWSound } Sound_Buffer *unused = mUnusedBuffers.back(); - mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle); - mOutput->unloadSound(unused->mHandle); + size = mOutput->unloadSound(unused->mHandle); + mBufferCacheSize -= size; unused->mHandle = 0; mUnusedBuffers.pop_back(); From 19d034f3705afb10064412f984a753af02085bc2 Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Sun, 17 Sep 2017 07:43:26 +0100 Subject: [PATCH 190/521] Docs CS-Manual - tour - add ring to chest Extend the ring tutorial in the CS-Manual to put the ring in a chest. Images omitted pending decisions on style and where to store them --- docs/source/manuals/openmw-cs/tour.rst | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index fedd42462..923b1af36 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -304,3 +304,42 @@ already checked. Load a game and make your way to Seyda Neen - or start a new ga Check whether Arrille has one (or more) for sale, and whether Fargoth give you one when you return his healing ring. + +Placing in a chest +****************** + +For this example we will use the small chest intended for lockpick practice, +located in the Census and Excise Office in Seyda Neen. + +FIrst we need the ID of the chest - this can be obtained either by clicking on it in the console +in the game, or by applying a similar process in the CS - + +World/Cells + +Select "Seyda Neen, Census and Excise Office" + +Right-click and select "View" + +Use mouse wheel to zoon in/out, and mouse plus WASD keys to navigate + +Click on the small chest + +Either way, you should find the ID, which is "chest_small_02_lockprac". + +Open the Objects table (World/Objects) and scroll down to find this item. + +Alternatively use the Edit/Search facility, selecting ID rather than text, +enter "lockprac" (without the quotes) into the search box, press "Search", +which should return two rows, then select the "Container" one rather than the "Instance" + +Right-click and "Edit Record". + +Right-click the "Content" section and select "Add a row" + +Set the Item ID of the new row to be your new ring - simplest way is probably to open the Objects +table if it's not already open, sort on the "Modified" column which should bring the ring, +with its status of "Added" to the top, then drag and drop to the chest row. + +Increase the Count to 1. + +Save the addon, then test to ensure it works - e.g. start a new game and lockpick the chest. From 6b56f25f9ec5b7c58f055f0195ca4ff0397b3fc3 Mon Sep 17 00:00:00 2001 From: David Walley <31402617+loriel2@users.noreply.github.com> Date: Sun, 17 Sep 2017 07:47:27 +0100 Subject: [PATCH 191/521] Update tour.rst --- docs/source/manuals/openmw-cs/tour.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index 923b1af36..38915c95b 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -311,7 +311,7 @@ Placing in a chest For this example we will use the small chest intended for lockpick practice, located in the Census and Excise Office in Seyda Neen. -FIrst we need the ID of the chest - this can be obtained either by clicking on it in the console +First we need the ID of the chest - this can be obtained either by clicking on it in the console in the game, or by applying a similar process in the CS - World/Cells @@ -320,7 +320,7 @@ Select "Seyda Neen, Census and Excise Office" Right-click and select "View" -Use mouse wheel to zoon in/out, and mouse plus WASD keys to navigate +Use mouse wheel to zoom in/out, and mouse plus WASD keys to navigate Click on the small chest From 5e60fb7c10557864e06ab31f0f0de006f5f57f36 Mon Sep 17 00:00:00 2001 From: PlutonicOverkill Date: Sun, 17 Sep 2017 21:09:28 +1200 Subject: [PATCH 192/521] Fix preferences pane width --- apps/opencs/view/prefs/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/prefs/dialogue.cpp b/apps/opencs/view/prefs/dialogue.cpp index 7f901c470..960ca74bc 100644 --- a/apps/opencs/view/prefs/dialogue.cpp +++ b/apps/opencs/view/prefs/dialogue.cpp @@ -24,7 +24,7 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main) main->addWidget (list); - QFontMetrics metrics (QApplication::font()); + QFontMetrics metrics (QApplication::font(list)); int maxWidth = 1; From 3fb3c4c20f60e39903421f8b5aed0462192b994f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Sep 2017 14:06:01 +0400 Subject: [PATCH 193/521] Add scrollbar to a birth effect lists (bug #4105) --- apps/openmw/mwgui/birth.cpp | 8 +++++++- apps/openmw/mwgui/birth.hpp | 2 +- files/mygui/openmw_chargen_birth.layout | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 69fb2c462..ecc011fc1 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -244,6 +245,11 @@ namespace MWGui } } } - } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden + mSpellArea->setVisibleVScroll(false); + mSpellArea->setCanvasSize(MyGUI::IntSize(mSpellArea->getWidth(), std::max(mSpellArea->getHeight(), coord.top))); + mSpellArea->setVisibleVScroll(true); + mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0)); + } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 0a84bb4e9..c8ec9da09 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -47,7 +47,7 @@ namespace MWGui void updateSpells(); MyGUI::ListBox* mBirthList; - MyGUI::Widget* mSpellArea; + MyGUI::ScrollView* mSpellArea; MyGUI::ImageBox* mBirthImage; std::vector mSpellItems; diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index 2375e5277..d93249c03 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -11,7 +11,9 @@ - + + + > From 4bb349a5259d534c34ef2017d2f941c5be838045 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Sep 2017 14:34:27 +0400 Subject: [PATCH 194/521] Use default 0 precision in the float formatting (bug #4096) --- components/misc/messageformatparser.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/misc/messageformatparser.cpp b/components/misc/messageformatparser.cpp index bfd8dd562..3a35c83ea 100644 --- a/components/misc/messageformatparser.cpp +++ b/components/misc/messageformatparser.cpp @@ -34,21 +34,19 @@ namespace Misc if (i < m.size()) { - int precision = 0; - bool precisionSet = false; + int precision = -1; if (m[i] == '.') { + precision = 0; while (++i < m.size() && m[i] >= '0' && m[i] <= '9') { precision = precision * 10 + (m[i] - '0'); - precisionSet = true; } } if (i < m.size()) { width = (widthSet) ? width : -1; - precision = (precisionSet) ? precision : -1; if (m[i] == 'S' || m[i] == 's') visitedPlaceholder(StringPlaceholder, pad, width, precision); From 5a5cb1a160d65b9b1d84a65bece4a7626daab3ec Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Sep 2017 14:09:29 +0100 Subject: [PATCH 195/521] Check death counts are for valid actors before loading them --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index baa2470da..673304d30 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1767,9 +1767,12 @@ namespace MWMechanics while (reader.isNextSub("ID__")) { std::string id = reader.getHString(); - int count; - reader.getHNT (count, "COUN"); - mDeathCount[id] = count; + if (MWBase::Environment::get().getWorld()->getStore().find(id)) + { + int count; + reader.getHNT(count, "COUN"); + mDeathCount[id] = count; + } } } } From 10a0136b4aa561f1bba7bc42a24643523d364ce2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Sep 2017 17:04:30 +0400 Subject: [PATCH 196/521] Cycle only through weapons which can be equipped by player (bug #4104) --- apps/openmw/mwgui/inventorywindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6a2d3ff83..6eb0c554e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -717,7 +717,9 @@ namespace MWGui lastId = item.getCellRef().getRefId(); - if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && isRightHandWeapon(item)) + if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && + isRightHandWeapon(item) && + item.getClass().canBeEquipped(item, player).first) { found = true; break; From 0be7e2a5a574354ebe7dc14c05ca22becf934315 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 17 Sep 2017 14:16:17 +0100 Subject: [PATCH 197/521] Fix really obvious flaw with ignored records not being skipped that I missed --- apps/openmw/mwmechanics/actors.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 673304d30..0cb7619db 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1767,12 +1767,10 @@ namespace MWMechanics while (reader.isNextSub("ID__")) { std::string id = reader.getHString(); + int count; + reader.getHNT(count, "COUN"); if (MWBase::Environment::get().getWorld()->getStore().find(id)) - { - int count; - reader.getHNT(count, "COUN"); mDeathCount[id] = count; - } } } } From fcb815f2c70df2b15088cf89a748bab7fd8e7f9d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 17 Sep 2017 23:03:02 +0000 Subject: [PATCH 198/521] Move fall height reset into PhysicsSystem (Fixes #4049) To avoid using onGround before it's actually set. --- apps/openmw/mwmechanics/character.cpp | 14 +------------- apps/openmw/mwphysics/physicssystem.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bfe8812e6..75ecf00a8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1704,20 +1704,11 @@ void CharacterController::update(float duration) if(sneak || inwater || flying) vec.z() = 0.0f; - if (inwater || flying) - cls.getCreatureStats(mPtr).land(); - bool inJump = true; if(!onground && !flying && !inwater) { // In the air (either getting up —ascending part of jump— or falling). - if (world->isSlowFalling(mPtr)) - { - // SlowFalling spell effect is active, do not keep previous fall height - cls.getCreatureStats(mPtr).land(); - } - forcestateupdate = (mJumpState != JumpState_InAir); jumpstate = JumpState_InAir; @@ -1763,7 +1754,7 @@ void CharacterController::update(float duration) } } } - else if(mJumpState == JumpState_InAir) + else if(mJumpState == JumpState_InAir && !inwater) { forcestateupdate = true; jumpstate = JumpState_Landing; @@ -1846,9 +1837,6 @@ void CharacterController::update(float duration) movestate = mMovementState; } - if (onground) - cls.getCreatureStats(mPtr).land(); - if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight) clearAnimQueue(); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 790ae2099..ee368ad24 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1404,14 +1404,16 @@ namespace MWPhysics // Slow fall reduces fall speed by a factor of (effect magnitude / 200) float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); + bool flying = world->isFlying(iter->first); + + bool wasOnGround = physicActor->getOnGround(); osg::Vec3f position = physicActor->getPosition(); float oldHeight = position.z(); bool positionChanged = false; for (int i=0; igetPtr(), physicActor, iter->second, physicsDt, - world->isFlying(iter->first), - waterlevel, slowFall, mCollisionWorld, mStandingCollisions); + flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions); if (position != physicActor->getPosition()) positionChanged = true; physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct @@ -1424,8 +1426,11 @@ namespace MWPhysics float heightDiff = position.z() - oldHeight; - if (heightDiff < 0) - iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff); + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + if ((wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1) + stats.land(); + else if (heightDiff < 0) + stats.addToFallHeight(-heightDiff); mMovementResults.push_back(std::make_pair(iter->first, interpolated)); } From 00034192dca8adc4f3f71ca6c2dc877bc3f6f7ce Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 17 Sep 2017 23:07:17 +0000 Subject: [PATCH 199/521] Fix player Ptr in RenderingManager not being updated on cell changes Noticed that 'setpos' wasn't working in the console with the player selected. --- apps/openmw/mwrender/renderingmanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4d4a36f6c..5c22de12e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -530,8 +530,10 @@ namespace MWRender void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) { if(mPlayerAnimation.get()) + { + setupPlayer(ptr); mPlayerAnimation->updatePtr(ptr); - + } mCamera->attachTo(ptr); } @@ -834,6 +836,7 @@ namespace MWRender player.getRefData().setBaseNode(mPlayerNode); + mWater->removeEmitter(player); mWater->addEmitter(player); } From d294d7e284b74e9c9f16600371cf87b163546b34 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 17 Sep 2017 23:16:49 +0000 Subject: [PATCH 200/521] Fix possible fall damage when switching from falling to flying --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 75ecf00a8..cd14ec5a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1754,7 +1754,7 @@ void CharacterController::update(float duration) } } } - else if(mJumpState == JumpState_InAir && !inwater) + else if(mJumpState == JumpState_InAir && !inwater && !flying) { forcestateupdate = true; jumpstate = JumpState_Landing; From 50d9d9f78f4f66b2721986bff2151f61282af216 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sun, 17 Sep 2017 20:29:51 -0400 Subject: [PATCH 201/521] Get rid of some templates, exceptions instead of assert, and other small changes. --- apps/opencs/model/world/columnimp.cpp | 93 ++++++++++++++++++- apps/opencs/model/world/columnimp.hpp | 80 ++++------------ apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/data.cpp | 8 +- apps/opencs/view/world/landtexturecreator.cpp | 4 +- components/esm/loadland.cpp | 9 +- 8 files changed, 120 insertions(+), 80 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 1ee7f8a03..6a19df0d5 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,7 +1,80 @@ #include "columnimp.hpp" +#include + namespace CSMWorld { + /* LandTextureNicknameColumn */ + LandTextureNicknameColumn::LandTextureNicknameColumn() + : Column(Columns::ColumnId_TextureNickname, ColumnBase::Display_String) + { + } + + QVariant LandTextureNicknameColumn::get(const Record& record) const + { + return QString::fromUtf8(record.get().mId.c_str()); + } + + void LandTextureNicknameColumn::set(Record& record, const QVariant& data) + { + LandTexture copy = record.get(); + copy.mId = data.toString().toUtf8().constData(); + record.setModified(copy); + } + + bool LandTextureNicknameColumn::isEditable() const + { + return true; + } + + /* LandTextureIndexColumn */ + LandTextureIndexColumn::LandTextureIndexColumn() + : Column(Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) + { + } + + QVariant LandTextureIndexColumn::get(const Record& record) const + { + return record.get().mIndex; + } + + bool LandTextureIndexColumn::isEditable() const + { + return false; + } + + /* LandPluginIndexColumn */ + LandPluginIndexColumn::LandPluginIndexColumn() + : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandPluginIndexColumn::get(const Record& record) const + { + return record.get().mPlugin; + } + + bool LandPluginIndexColumn::isEditable() const + { + return false; + } + + /* LandTexturePluginIndexColumn */ + LandTexturePluginIndexColumn::LandTexturePluginIndexColumn() + : Column(Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer, 0) + { + } + + QVariant LandTexturePluginIndexColumn::get(const Record& record) const + { + return record.get().mPluginIndex; + } + + bool LandTexturePluginIndexColumn::isEditable() const + { + return false; + } + /* LandMapLodColumn */ LandMapLodColumn::LandMapLodColumn() : Column(Columns::ColumnId_LandMapLodIndex, ColumnBase::Display_String, 0) @@ -30,7 +103,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_GLOBAL_MAP_LOD_SIZE); + + if (array.count() != Land::LAND_GLOBAL_MAP_LOD_SIZE) + throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_WNAM); @@ -76,7 +151,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const signed char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + + if (array.count() != Land::LAND_NUM_VERTS * 3) + throw std::runtime_error("invalid land normals data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VNML); @@ -121,7 +198,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const float* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * sizeof(float)); + + if (array.count() != Land::LAND_NUM_VERTS * sizeof(float)) + throw std::runtime_error("invalid land heights data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VHGT); @@ -167,7 +246,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const unsigned char* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_VERTS * 3); + + if (array.count() != Land::LAND_NUM_VERTS * 3) + throw std::runtime_error("invalid land colours data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VCLR); @@ -212,7 +293,9 @@ namespace CSMWorld { QByteArray array = data.toByteArray(); const uint16_t* rawData = reinterpret_cast(array.data()); - assert (array.count() == Land::LAND_NUM_TEXTURES * sizeof(uint16_t)); + + if (array.count() != Land::LAND_NUM_TEXTURES * sizeof(uint16_t)) + throw std::runtime_error("invalid land textures data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VTEX); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 8e5908bd3..025b064c6 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -67,14 +67,14 @@ namespace CSMWorld inline QVariant StringIdColumn::get(const Record& record) const { const Land& land = record.get(); - return QString(Land::createUniqueRecordId(land.mX, land.mY).c_str()); + return QString::fromUtf8(Land::createUniqueRecordId(land.mX, land.mY).c_str()); } template<> inline QVariant StringIdColumn::get(const Record& record) const { const LandTexture& ltex = record.get(); - return QString(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); + return QString::fromUtf8(LandTexture::createUniqueRecordId(ltex.mPluginIndex, ltex.mIndex).c_str()); } template @@ -2435,78 +2435,38 @@ namespace CSMWorld } }; - template - struct TextureHandleColumn : public Column + struct LandTextureNicknameColumn : public Column { - TextureHandleColumn() - : Column (Columns::ColumnId_TextureHandle, ColumnBase::Display_String) - {} - - QVariant get(const Record& record) const override - { - return QString::fromUtf8(record.get().mId.c_str()); - } + LandTextureNicknameColumn(); - void set(Record& record, const QVariant& data) override - { - ESXRecordT copy = record.get(); - copy.mId = data.toString().toUtf8().constData(); - record.setModified(copy); - } - - bool isEditable() const override - { - return true; - } + QVariant get(const Record& record) const override; + void set(Record& record, const QVariant& data) override; + bool isEditable() const override; }; - template - struct TextureIndexColumn : public Column + struct LandTextureIndexColumn : public Column { - TextureIndexColumn() - : Column (Columns::ColumnId_TextureIndex, ColumnBase::Display_Integer) - {} + LandTextureIndexColumn(); - QVariant get(const Record& record) const override - { - return record.get().mIndex; - } - - bool isEditable() const override - { - return false; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; }; - template - struct PluginIndexColumn : public Column + struct LandPluginIndexColumn : public Column { - PluginIndexColumn() - : Column (Columns::ColumnId_PluginIndex, ColumnBase::Display_Integer,0) - {} - - QVariant get(const Record& record) const override - { - return -1; - } + LandPluginIndexColumn(); - bool isEditable() const override - { - return false; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; }; - template<> - inline QVariant PluginIndexColumn::get (const Record& record) const + struct LandTexturePluginIndexColumn : public Column { - return record.get().mPlugin; - } + LandTexturePluginIndexColumn(); - template<> - inline QVariant PluginIndexColumn::get (const Record& record) const - { - return record.get().mPluginIndex; - } + QVariant get(const Record& record) const override; + bool isEditable() const override; + }; struct LandMapLodColumn : public Column { diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 63ccb6017..ec010ba36 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,7 +330,7 @@ namespace CSMWorld { ColumnId_WeatherChance, "Percent Chance" }, { ColumnId_Text, "Text" }, - { ColumnId_TextureHandle, "Texture Handle" }, + { ColumnId_TextureNickname, "Texture Nickname" }, { ColumnId_PluginIndex, "Plugin Index" }, { ColumnId_TextureIndex, "Texture Index" }, { ColumnId_LandMapLodIndex, "Land map height LOD" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 432597105..15018795c 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,7 +329,7 @@ namespace CSMWorld ColumnId_Text = 297, - ColumnId_TextureHandle = 298, + ColumnId_TextureNickname = 298, ColumnId_PluginIndex = 299, ColumnId_TextureIndex = 300, ColumnId_LandMapLodIndex = 301, diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 5bfcd6846..b654eb00d 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -48,7 +48,7 @@ CSMWorld::ImportLandTexturesCommand::ImportLandTexturesCommand(IdTable& landTabl , mLtexs(ltexTable) , mOldState(0) { - setText("Import land textures"); + setText("Copy land textures to current plugin"); } void CSMWorld::ImportLandTexturesCommand::redo() diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0ffe5fa21..2216d5ca6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -415,7 +415,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLand.addColumn (new StringIdColumn); mLand.addColumn (new RecordStateColumn); mLand.addColumn (new FixedRecordTypeColumn(UniversalId::Type_Land)); - mLand.addColumn (new PluginIndexColumn); + mLand.addColumn (new LandPluginIndexColumn); mLand.addColumn (new LandMapLodColumn); mLand.addColumn (new LandNormalsColumn); mLand.addColumn (new LandHeightsColumn); @@ -425,9 +425,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mLandTextures.addColumn (new StringIdColumn(true)); mLandTextures.addColumn (new RecordStateColumn); mLandTextures.addColumn (new FixedRecordTypeColumn(UniversalId::Type_LandTexture)); - mLandTextures.addColumn (new TextureHandleColumn); - mLandTextures.addColumn (new PluginIndexColumn); - mLandTextures.addColumn (new TextureIndexColumn); + mLandTextures.addColumn (new LandTextureNicknameColumn); + mLandTextures.addColumn (new LandTexturePluginIndexColumn); + mLandTextures.addColumn (new LandTextureIndexColumn); mLandTextures.addColumn (new TextureColumn); mPathgrids.addColumn (new StringIdColumn); diff --git a/apps/opencs/view/world/landtexturecreator.cpp b/apps/opencs/view/world/landtexturecreator.cpp index fdabfb281..43d911e50 100644 --- a/apps/opencs/view/world/landtexturecreator.cpp +++ b/apps/opencs/view/world/landtexturecreator.cpp @@ -45,7 +45,7 @@ namespace CSVWorld CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); mNameEdit->setText((table.data(table.getModelIndex(originId, column)).toString())); column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureIndex); @@ -79,7 +79,7 @@ namespace CSVWorld GenericCreator::configureCreateCommand(command); CSMWorld::IdTable& table = dynamic_cast(*getData().getTableModel(getCollectionId())); - int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureHandle); + int column = table.findColumnIndex(CSMWorld::Columns::ColumnId_TextureNickname); command.addValue(column, mName.c_str()); } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 083f27cef..f3f72e88a 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -177,17 +177,14 @@ namespace ESM void Land::blank() { - if (mLandData) - { - delete mLandData; - } - mPlugin = 0; for (int i = 0; i < LAND_GLOBAL_MAP_LOD_SIZE; ++i) mWnam[0] = 0; - mLandData = new LandData; + if (!mLandData) + mLandData = new LandData; + mLandData->mHeightOffset = 0; for (int i = 0; i < LAND_NUM_VERTS; ++i) mLandData->mHeights[i] = 0; From 074be7d7c62e8f437e9330378012e82acec6c74b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Sep 2017 21:44:16 -0700 Subject: [PATCH 202/521] Remove a function from the sound manager interface --- apps/openmw/mwbase/soundmanager.hpp | 3 --- apps/openmw/mwsound/soundmanagerimp.cpp | 11 ++++++----- apps/openmw/mwsound/soundmanagerimp.hpp | 4 +--- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index f1c35df19..2b3cf1f0d 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -82,9 +82,6 @@ namespace MWBase ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - virtual void startRandomTitle() = 0; - ///< Starts a random track from the current playlist - virtual bool isMusicPlaying() = 0; ///< Returns true if music is playing diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ac87a2f06..a798d350c 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -391,11 +391,6 @@ namespace MWSound mMusic->setFadeout(0.5f); } - void SoundManager::streamMusic(const std::string& filename) - { - advanceMusic("Music/"+filename); - } - void SoundManager::startRandomTitle() { std::vector filelist; @@ -446,6 +441,12 @@ namespace MWSound tracklist.pop_back(); } + + void SoundManager::streamMusic(const std::string& filename) + { + advanceMusic("Music/"+filename); + } + bool SoundManager::isMusicPlaying() { return mMusic && mOutput->isStreamPlaying(mMusic); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d2dce3928..e31a0e575 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -127,6 +127,7 @@ namespace MWSound void streamMusicFull(const std::string& filename); void advanceMusic(const std::string& filename); + void startRandomTitle(); void updateSounds(float duration); void updateRegionSound(float duration); @@ -157,9 +158,6 @@ namespace MWSound ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - virtual void startRandomTitle(); - ///< Starts a random track from the current playlist - virtual bool isMusicPlaying(); ///< Returns true if music is playing From b770c1493fc73bc38d2ede20ca14fad09d8d6740 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Sep 2017 01:21:18 -0700 Subject: [PATCH 203/521] Don't spam about missing animations --- apps/openmw/mwmechanics/character.cpp | 79 +++++++++++++-------------- apps/openmw/mwrender/animation.cpp | 2 - 2 files changed, 37 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index cd14ec5a4..06916f989 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2025,58 +2025,53 @@ void CharacterController::unpersistAnimationState() bool CharacterController::playGroup(const std::string &groupname, int mode, int count, bool persist) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) - { - std::cerr<< "Animation "<getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && + mAnimation->isPlaying(groupname)) { - // If this animation is a looped animation (has a "loop start" key) that is already playing - // and has not yet reached the end of the loop, allow it to continue animating with its existing loop count - // and remove any other animations that were queued. - // This emulates observed behavior from the original allows the script "OutsideBanner" to animate banners correctly. - if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname && - mAnimation->getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 && - mAnimation->isPlaying(groupname)) - { - float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); + float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop"); - if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key - endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop"); + if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key + endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop"); - if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) - { - mAnimQueue.resize(1); - return true; - } + if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop)) + { + mAnimQueue.resize(1); + return true; } + } - count = std::max(count, 1); + count = std::max(count, 1); - AnimationQueueEntry entry; - entry.mGroup = groupname; - entry.mLoopCount = count-1; - entry.mPersist = persist; + AnimationQueueEntry entry; + entry.mGroup = groupname; + entry.mLoopCount = count-1; + entry.mPersist = persist; - if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) - { - clearAnimQueue(); - mAnimQueue.push_back(entry); + if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) + { + clearAnimQueue(); + mAnimQueue.push_back(entry); - mAnimation->disable(mCurrentIdle); - mCurrentIdle.clear(); + mAnimation->disable(mCurrentIdle); + mCurrentIdle.clear(); - mIdleState = CharState_SpecialIdle; - bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); - mAnimation->play(groupname, Priority_Default, - MWRender::Animation::BlendMask_All, false, 1.0f, - ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); - } - else if(mode == 0) - { - mAnimQueue.resize(1); - mAnimQueue.push_back(entry); - } + mIdleState = CharState_SpecialIdle; + bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0); + mAnimation->play(groupname, Priority_Default, + MWRender::Animation::BlendMask_All, false, 1.0f, + ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); + } + else if(mode == 0) + { + mAnimQueue.resize(1); + mAnimQueue.push_back(entry); } return true; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df9b8545a..a8e0caed5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -757,8 +757,6 @@ namespace MWRender break; } } - if(iter == mAnimSources.rend()) - std::cerr<< "Failed to find animation "< Date: Mon, 18 Sep 2017 01:41:05 -0700 Subject: [PATCH 204/521] Avoid creating temp strings when looking for an animation stop key --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8e0caed5..90b69de8e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -793,7 +793,7 @@ namespace MWRender // We have to ignore extra garbage at the end. // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". // Why, just why? :( - && (stopkey->second.size() < stoptag.size() || stopkey->second.substr(0,stoptag.size()) != stoptag)) + && (stopkey->second.size() < stoptag.size() || stopkey->second.compare(0,stoptag.size(), stoptag) != 0)) ++stopkey; if(stopkey == keys.rend()) return false; From 021627bdf8d874dd2326ad94477bc4e78bddbc4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Sep 2017 01:51:11 -0700 Subject: [PATCH 205/521] Mark some functions with override Fixes some Clang warnings about overriding a virtual function without the override keyword. --- components/resource/scenemanager.hpp | 6 +++--- components/terrain/chunkmanager.hpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 65524f76e..b223353c2 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -141,11 +141,11 @@ namespace Resource void setUnRefImageDataAfterApply(bool unref); /// @see ResourceManager::updateCache - virtual void updateCache(double referenceTime); + void updateCache(double referenceTime) override; - virtual void clearCache(); + void clearCache() override; - virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; private: diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 46531f23e..d8c4fd084 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -32,9 +32,9 @@ namespace Terrain osg::ref_ptr getChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); - virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) const; + void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; - virtual void clearCache(); + void clearCache() override; void releaseGLObjects(osg::State* state) override; From 65d8e2ff5d70aebb9c6f230ba2b26d5e7d420f98 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Sep 2017 21:46:57 +0400 Subject: [PATCH 206/521] Allow to use GetDetected without a reference (bug #3110) --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 +++ apps/openmw/mwmechanics/actors.cpp | 33 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 4 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 5 +++ .../mwmechanics/mechanicsmanagerimp.hpp | 4 +++ apps/openmw/mwscript/aiextensions.cpp | 13 ++------ 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 84d43156e..d9068b285 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -225,6 +225,10 @@ namespace MWBase virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0; virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const = 0; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0; + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0; /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index baa2470da..366954944 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1086,6 +1086,39 @@ namespace MWMechanics } } + bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + if (!actor.getClass().isActor()) + return false; + + // If an observer is NPC, check if he detected an actor + if (!observer.isEmpty() && observer.getClass().isNpc()) + { + return + MWBase::Environment::get().getWorld()->getLOS(observer, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + } + + // Otherwise check if any actor in AI processing range sees the target actor + std::vector actors; + osg::Vec3f position (actor.getRefData().getPosition().asVec3()); + getObjectsInRange(position, aiProcessingDistance, actors); + for(std::vector::iterator it = actors.begin(); it != actors.end(); ++it) + { + if (*it == actor) + continue; + + bool result = + MWBase::Environment::get().getWorld()->getLOS(*it, actor) && + MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, *it); + + if (result) + return true; + } + + return false; + } + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { PtrActorMap::iterator iter = mActors.find(old); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6eb3a2955..e433434a5 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -57,6 +57,10 @@ namespace MWMechanics PtrActorMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator end() { return mActors.end(); } + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) void updateMagicEffects (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5f3dd58af..5d9ef726a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -423,6 +423,11 @@ namespace MWMechanics mObjects.update(duration, paused); } + bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) + { + return mActors.isActorDetected(actor, observer); + } + bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr) { return mActors.isAttackPrepairing(ptr); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index adad21916..1bf3a8d22 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -191,6 +191,10 @@ namespace MWMechanics /// Is \a ptr casting spell or using weapon now? virtual bool isAttackingOrSpell(const MWWorld::Ptr &ptr) const; + /// Check if the target actor was detected by an observer + /// If the observer is a non-NPC, check all actors in AI processing distance as observers + virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); + virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer); /// List the owners that the player has stolen this item from (the owner can be an NPC or a faction). diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 76130be24..c98e0fc5a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -372,21 +372,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr observer = R()(runtime); + MWWorld::Ptr observer = R()(runtime, false); // required=false + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true); - if(!actor.getClass().isActor() || !observer.getClass().isActor()) - { - runtime.push(0); - return; - } - - Interpreter::Type_Integer value = - MWBase::Environment::get().getWorld()->getLOS(observer, actor) && - MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor, observer); + Interpreter::Type_Integer value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer); runtime.push (value); } From 2806a35a614d4ceb378f612f7c896ba02e7f994c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Sep 2017 23:03:47 +0400 Subject: [PATCH 207/521] Fixed padding of MessageBox buttons --- apps/openmw/mwgui/messagebox.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ab43df0f1..bfe173b47 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -206,7 +206,8 @@ namespace MWGui int textButtonPadding = 10; // padding between the text-widget und the button-widget int buttonLeftPadding = 10; // padding between the buttons if horizontal int buttonTopPadding = 10; // ^-- if vertical - int buttonPadding = 5; // padding between button label and button itself + int buttonLabelLeftPadding = 12; // padding between button label and button itself, from left + int buttonLabelTopPadding = 4; // padding between button label and button itself, from top int buttonMainPadding = 10; // padding between buttons and bottom of the main widget mMarkedToDelete = false; @@ -245,10 +246,10 @@ namespace MWGui if (buttonsWidth != 0) buttonsWidth += buttonLeftPadding; - int buttonWidth = button->getTextSize().width + 2*buttonPadding; + int buttonWidth = button->getTextSize().width + 2*buttonLabelLeftPadding; buttonsWidth += buttonWidth; - buttonHeight = button->getTextSize().height + 2*buttonPadding; + buttonHeight = button->getTextSize().height + 2*buttonLabelTopPadding; if (buttonsHeight != 0) buttonsHeight += buttonTopPadding; @@ -295,8 +296,8 @@ namespace MWGui buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; + buttonSize.width = (*button)->getTextSize().width + 2*buttonLabelLeftPadding; + buttonSize.height = (*button)->getTextSize().height + 2*buttonLabelTopPadding; (*button)->setCoord(buttonCord); (*button)->setSize(buttonSize); @@ -322,8 +323,8 @@ namespace MWGui std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*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; From 9342a0254fc673ab1cf771cac33247f89c24e13d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Sep 2017 10:44:24 +0400 Subject: [PATCH 208/521] Restack soulgems when use SoulTrap --- apps/openmw/mwmechanics/actors.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index baa2470da..eb2a97cbb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -209,6 +209,9 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); + // Restack the gem with other gems with the same soul + gem->getContainerStore()->restack(*gem); + mTrapped = true; if (caster == getPlayer()) From 9d826b2deb5f3a01821aec289d64eb1a5770dec6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Sep 2017 11:57:00 +0400 Subject: [PATCH 209/521] Improve item sorting in inventory and containers --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 92 +++++++++++++++++++++-- 1 file changed, 86 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 68d95fb88..098029ce7 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -59,15 +59,95 @@ namespace if (mSortByType && left.mType != right.mType) return left.mType < right.mType; - if (left.mBase.getTypeName() == right.mBase.getTypeName()) + float result = 0; + + // compare items by type + std::string leftName = left.mBase.getTypeName(); + std::string rightName = right.mBase.getTypeName(); + + if (leftName != rightName) + return compareType(leftName, rightName); + + // compare items by name + leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); + rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + + result = leftName.compare(rightName); + if (result != 0) + return result < 0; + + // compare items by enchantment: + // 1. enchanted items showed before non-enchanted + // 2. item with lesser charge percent comes after items with more charge percent + // 3. item with constant effect comes before items with non-constant effects + int leftChargePercent = -1; + int rightChargePercent = -1; + leftName = left.mBase.getClass().getEnchantment(left.mBase); + rightName = right.mBase.getClass().getEnchantment(right.mBase); + + if (!leftName.empty()) { - std::string leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); - std::string rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(leftName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + leftChargePercent = 101; + else + leftChargePercent = (left.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast(left.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + } + else + std::cerr << "Warning: Can't find enchantment '" << leftName << "' on item " << left.mBase.getCellRef().getRefId() << std::endl; + } - return leftName.compare(rightName) < 0; + if (!rightName.empty()) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(rightName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + rightChargePercent = 101; + else + rightChargePercent = (right.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast(right.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + } + else + std::cerr << "Warning: Can't find enchantment '" << rightName << "' on item " << right.mBase.getCellRef().getRefId() << std::endl; + } + + result = leftChargePercent - rightChargePercent; + if (result != 0) + return result > 0; + + // compare items by condition + if (left.mBase.getClass().hasItemHealth(left.mBase) && right.mBase.getClass().hasItemHealth(right.mBase)) + { + result = left.mBase.getClass().getItemHealth(left.mBase) - right.mBase.getClass().getItemHealth(right.mBase); + if (result != 0) + return result > 0; } - else - return compareType(left.mBase.getTypeName(), right.mBase.getTypeName()); + + // compare items by remaining usage time + result = left.mBase.getClass().getRemainingUsageTime(left.mBase) - right.mBase.getClass().getRemainingUsageTime(right.mBase); + if (result != 0) + return result > 0; + + // compare items by value + result = left.mBase.getClass().getValue(left.mBase) - right.mBase.getClass().getValue(right.mBase); + if (result != 0) + return result > 0; + + // compare items by weight + result = left.mBase.getClass().getWeight(left.mBase) - right.mBase.getClass().getWeight(right.mBase); + if (result != 0) + return result > 0; + + // compare items by Id + leftName = left.mBase.getCellRef().getRefId(); + rightName = right.mBase.getCellRef().getRefId(); + + result = leftName.compare(rightName); + return result < 0; } }; } From 2346c5338e93effffdaa6c281ef4c07ede421763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 20 Sep 2017 16:34:27 +0200 Subject: [PATCH 210/521] increase water fudge to get rid of artifacts --- apps/openmw/mwrender/water.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0ed389bdf..2329e7afa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; + const float clipFudge = -30; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); @@ -336,8 +336,7 @@ public: void setWaterLevel(float waterLevel) { - setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); - + setViewMatrix(osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,2 * waterLevel)); mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); } From 771f58ce58e2089f88338acf01a51c1f02635e3f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Sep 2017 19:47:14 +0400 Subject: [PATCH 211/521] Remove unwanted warnings --- apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 098029ce7..45aa261df 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -96,8 +96,6 @@ namespace leftChargePercent = (left.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 : static_cast(left.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); } - else - std::cerr << "Warning: Can't find enchantment '" << leftName << "' on item " << left.mBase.getCellRef().getRefId() << std::endl; } if (!rightName.empty()) @@ -111,8 +109,6 @@ namespace rightChargePercent = (right.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 : static_cast(right.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); } - else - std::cerr << "Warning: Can't find enchantment '" << rightName << "' on item " << right.mBase.getCellRef().getRefId() << std::endl; } result = leftChargePercent - rightChargePercent; From f15de6d3cad92fe3513ce9d328098f6b6ac134a5 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Wed, 20 Sep 2017 18:56:32 +0200 Subject: [PATCH 212/521] ESS-Importer: Convert magic projectiles (Closes #2320) --- apps/essimporter/CMakeLists.txt | 1 + apps/essimporter/converter.cpp | 53 +++++++++++---- apps/essimporter/converter.hpp | 12 ++++ apps/essimporter/importer.cpp | 3 +- apps/essimporter/importercontext.hpp | 4 +- apps/essimporter/importsplm.cpp | 43 ++++++++++++ apps/essimporter/importsplm.h | 81 +++++++++++++++++++++++ apps/openmw/mwbase/world.hpp | 3 +- apps/openmw/mwmechanics/spellcasting.cpp | 9 ++- apps/openmw/mwmechanics/spellcasting.hpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 58 ++++++++++------ apps/openmw/mwworld/projectilemanager.hpp | 5 +- apps/openmw/mwworld/worldimp.cpp | 5 +- apps/openmw/mwworld/worldimp.hpp | 3 +- components/esm/projectilestate.cpp | 15 ++--- components/esm/projectilestate.hpp | 4 -- 16 files changed, 238 insertions(+), 63 deletions(-) create mode 100644 apps/essimporter/importsplm.cpp create mode 100644 apps/essimporter/importsplm.h diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index fc5fae72e..0e742ff54 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -17,6 +17,7 @@ set(ESSIMPORTER_FILES importscri.cpp importscpt.cpp importproj.cpp + importsplm.cpp importercontext.cpp converter.cpp convertacdt.cpp diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 5c65332be..2473daf95 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -1,12 +1,12 @@ #include "converter.hpp" #include +#include #include #include #include -#include #include "convertcrec.hpp" #include "convertcntc.hpp" @@ -461,11 +461,7 @@ namespace ESSImport if (!pnam.isMagic()) { ESM::ProjectileState out; - out.mId = pnam.mArrowId.toString(); - out.mPosition = pnam.mPosition; - out.mOrientation.mValues[0] = out.mOrientation.mValues[1] = out.mOrientation.mValues[2] = 0.0f; - out.mOrientation.mValues[3] = 1.0f; - out.mActorId = convertActorId(pnam.mActorId.toString(), *mContext); + convertBaseState(out, pnam); out.mBowId = pnam.mBowId.toString(); out.mVelocity = pnam.mVelocity; @@ -477,16 +473,49 @@ namespace ESSImport } else { - // TODO: Implement magic projectile conversion. + ESM::MagicBoltState out; + convertBaseState(out, pnam); - /*esm.startRecord(ESM::REC_MPRJ); - out.save(esm); - esm.endRecord(ESM::REC_MPRJ);*/ + auto it = std::find_if(mContext->mActiveSpells.begin(), mContext->mActiveSpells.end(), + [&pnam](const SPLM::ActiveSpell& spell) -> bool { return spell.mIndex == pnam.mSplmIndex; }); - std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (not implemented)" << std::endl; - continue; + if (it == mContext->mActiveSpells.end()) + { + std::cerr << "Warning: Skipped conversion for magic projectile \"" << pnam.mArrowId.toString() << "\" (invalid spell link)" << std::endl; + continue; + } + + out.mSpellId = it->mSPDT.mId.toString(); + out.mSpeed = pnam.mSpeed * 0.001f; // not sure where this factor comes from + + esm.startRecord(ESM::REC_MPRJ); + out.save(esm); + esm.endRecord(ESM::REC_MPRJ); } } } + void ConvertPROJ::convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam) + { + base.mId = pnam.mArrowId.toString(); + base.mPosition = pnam.mPosition; + + osg::Quat orient; + orient.makeRotate(osg::Vec3f(0,1,0), pnam.mVelocity); + base.mOrientation = orient; + + base.mActorId = convertActorId(pnam.mActorId.toString(), *mContext); + } + + void ConvertSPLM::read(ESM::ESMReader& esm) + { + mSPLM.load(esm); + mContext->mActiveSpells = mSPLM.mActiveSpells; + } + + void ConvertSPLM::write(ESM::ESMWriter& esm) + { + std::cerr << "Warning: Skipped active spell conversion (not implemented)" << std::endl; + } + } diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index a640d6756..621b85709 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "importcrec.hpp" #include "importcntc.hpp" @@ -36,6 +37,7 @@ #include "importjour.hpp" #include "importscpt.hpp" #include "importproj.h" +#include "importsplm.h" #include "convertacdt.hpp" #include "convertnpcc.hpp" @@ -602,9 +604,19 @@ public: virtual void read(ESM::ESMReader& esm) override; virtual void write(ESM::ESMWriter& esm) override; private: + void convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam); PROJ mProj; }; +class ConvertSPLM : public Converter +{ +public: + virtual void read(ESM::ESMReader& esm) override; + virtual void write(ESM::ESMWriter& esm) override; +private: + SPLM mSPLM; +}; + } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 4c8222c56..73b15baae 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -271,6 +271,7 @@ namespace ESSImport const unsigned int recSTLN = ESM::FourCC<'S','T','L','N'>::value; const unsigned int recGAME = ESM::FourCC<'G','A','M','E'>::value; const unsigned int recJOUR = ESM::FourCC<'J','O','U','R'>::value; + const unsigned int recSPLM = ESM::FourCC<'S','P','L','M'>::value; std::map > converters; converters[ESM::REC_GLOB] = std::shared_ptr(new ConvertGlobal()); @@ -304,12 +305,12 @@ namespace ESSImport converters[recJOUR ] = std::shared_ptr(new ConvertJOUR()); converters[ESM::REC_SCPT] = std::shared_ptr(new ConvertSCPT()); converters[ESM::REC_PROJ] = std::shared_ptr(new ConvertPROJ()); + converters[recSPLM] = std::shared_ptr(new ConvertSPLM()); // TODO: // - REGN (weather in certain regions?) // - VFXM // - SPLM (active spell effects) - // - PROJ (magic projectiles in air) std::set unknownRecords; diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index 4896f5594..86501b3cb 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -15,7 +15,7 @@ #include "importcrec.hpp" #include "importcntc.hpp" #include "importplayer.hpp" - +#include "importsplm.h" @@ -54,6 +54,8 @@ namespace ESSImport std::map mCreatures; std::map mNpcs; + std::vector mActiveSpells; + Context() : mDay(0) , mMonth(0) diff --git a/apps/essimporter/importsplm.cpp b/apps/essimporter/importsplm.cpp new file mode 100644 index 000000000..9fdba4ddb --- /dev/null +++ b/apps/essimporter/importsplm.cpp @@ -0,0 +1,43 @@ +#include "importsplm.h" + +#include + +namespace ESSImport +{ + +void SPLM::load(ESM::ESMReader& esm) +{ + while (esm.isNextSub("NAME")) + { + ActiveSpell spell; + esm.getHT(spell.mIndex); + esm.getHNT(spell.mSPDT, "SPDT"); + spell.mTarget = esm.getHNOString("TNAM"); + + while (esm.isNextSub("NPDT")) + { + ActiveEffect effect; + esm.getHT(effect.mNPDT); + + // Effect-specific subrecords can follow: + // - INAM for disintegration and bound effects + // - CNAM for summoning and command effects + // - VNAM for vampirism + // NOTE: There can be multiple INAMs per effect. + // TODO: Needs more research. + + esm.skipHSubUntil("NAM0"); // sentinel + esm.getSubName(); + esm.skipHSub(); + + spell.mActiveEffects.push_back(effect); + } + + unsigned char xnam; // sentinel + esm.getHNT(xnam, "XNAM"); + + mActiveSpells.push_back(spell); + } +} + +} diff --git a/apps/essimporter/importsplm.h b/apps/essimporter/importsplm.h new file mode 100644 index 000000000..8fd5c2bb5 --- /dev/null +++ b/apps/essimporter/importsplm.h @@ -0,0 +1,81 @@ +#ifndef OPENMW_ESSIMPORT_IMPORTSPLM_H +#define OPENMW_ESSIMPORT_IMPORTSPLM_H + +#include +#include +#include + +namespace ESM +{ + class ESMReader; +} + +namespace ESSImport +{ + +struct SPLM +{ + +#pragma pack(push) +#pragma pack(1) + struct SPDT // 160 bytes + { + int mType; // 1 = spell, 2 = enchantment, 3 = potion + ESM::NAME32 mId; // base ID of a spell/enchantment/potion + unsigned char mUnknown[4*4]; + ESM::NAME32 mCasterId; + ESM::NAME32 mSourceId; // empty for spells + unsigned char mUnknown2[4*11]; + }; + + struct NPDT // 56 bytes + { + ESM::NAME32 mAffectedActorId; + unsigned char mUnknown[4*2]; + int mMagnitude; + float mSecondsActive; + unsigned char mUnknown2[4*2]; + }; + + struct INAM // 40 bytes + { + int mUnknown; + unsigned char mUnknown2; + ESM::FIXED_STRING<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration + }; + + struct CNAM // 36 bytes + { + int mUnknown; // seems to always be 0 + ESM::NAME32 mSummonedOrCommandedActor[32]; + }; + + struct VNAM // 4 bytes + { + int mUnknown; + }; + + +#pragma pack(pop) + + struct ActiveEffect + { + NPDT mNPDT; + }; + + struct ActiveSpell + { + int mIndex; + SPDT mSPDT; + std::string mTarget; + std::vector mActiveEffects; + }; + + std::vector mActiveSpells; + + void load(ESM::ESMReader& esm); +}; + +} + +#endif diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5e76d82eb..038535939 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -487,8 +487,7 @@ namespace MWBase virtual void castSpell (const MWWorld::Ptr& actor) = 0; - virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) = 0; + virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f7ee15bf4..a808b8285 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -329,7 +329,7 @@ namespace MWMechanics { } - void CastSpell::launchMagicBolt (const ESM::EffectList& effects) + void CastSpell::launchMagicBolt () { osg::Vec3f fallbackDirection (0,1,0); @@ -340,8 +340,7 @@ namespace MWMechanics osg::Vec3f(mTarget.getRefData().getPosition().asVec3())- osg::Vec3f(mCaster.getRefData().getPosition().asVec3()); - MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, effects, - mCaster, mSourceName, fallbackDirection); + MWBase::Environment::get().getWorld()->launchMagicBolt(mId, mCaster, fallbackDirection); } void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, @@ -823,7 +822,7 @@ namespace MWMechanics inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); if (launchProjectile) - launchMagicBolt(enchantment->mEffects); + launchMagicBolt(); else if (isProjectile || !mTarget.isEmpty()) inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Target); @@ -915,7 +914,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - launchMagicBolt(spell->mEffects); + launchMagicBolt(); return true; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 9991c583d..2e368afcf 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -106,7 +106,7 @@ namespace MWMechanics void playSpellCastingEffects(const std::string &spellid); /// Launch a bolt with the given effects. - void launchMagicBolt (const ESM::EffectList& effects); + void launchMagicBolt (); /// @note \a target can be any type of object, not just actors. /// @note \a caster can be any type of object, or even an empty object. diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 5b15583bf..6e716cb54 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -1,6 +1,7 @@ #include "projectilemanager.hpp" #include +#include #include @@ -41,13 +42,29 @@ namespace { - ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, std::string& texture, const ESM::EffectList& effects) + ESM::EffectList getMagicBoltData(std::vector& projectileIDs, std::vector& sounds, float& speed, std::string& texture, std::string& sourceName, const std::string& id) { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + const ESM::EffectList* effects; + if (const ESM::Spell* spell = esmStore.get().search(id)) // check if it's a spell + { + sourceName = spell->mName; + effects = &spell->mEffects; + } + else // check if it's an enchanted item + { + MWWorld::ManualRef ref(esmStore, id); + MWWorld::Ptr ptr = ref.getPtr(); + const ESM::Enchantment* ench = esmStore.get().find(ptr.getClass().getEnchantment(ptr)); + sourceName = ptr.getClass().getName(ptr); + effects = &ench->mEffects; + } + int count = 0; speed = 0.0f; ESM::EffectList projectileEffects; - for (std::vector::const_iterator iter (effects.mList.begin()); - iter!=effects.mList.end(); ++iter) + for (std::vector::const_iterator iter (effects->mList.begin()); + iter!=effects->mList.end(); ++iter) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( iter->mEffectID); @@ -82,14 +99,14 @@ namespace if (projectileEffects.mList.size() == 1) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( - effects.mList.begin()->mEffectID); + effects->mList.begin()->mEffectID); texture = magicEffect->mParticle; } if (projectileEffects.mList.size() > 1) // insert a VFX_Multiple projectile if there are multiple projectile effects { std::ostringstream ID; - ID << "VFX_Multiple" << effects.mList.size(); + ID << "VFX_Multiple" << effects->mList.size(); std::vector::iterator it; it = projectileIDs.begin(); it = projectileIDs.insert(it, ID.str()); @@ -235,8 +252,7 @@ namespace MWWorld state.mEffectAnimationTime->addTime(duration); } - void ProjectileManager::launchMagicBolt(const std::string &spellId, bool stack, const ESM::EffectList &effects, const Ptr &caster, - const std::string &sourceName, const osg::Vec3f& fallbackDirection) + void ProjectileManager::launchMagicBolt(const std::string &spellId, const Ptr &caster, const osg::Vec3f& fallbackDirection) { osg::Vec3f pos = caster.getRefData().getPosition().asVec3(); if (caster.getClass().isActor()) @@ -257,18 +273,16 @@ namespace MWWorld orient.makeRotate(osg::Vec3f(0,1,0), osg::Vec3f(fallbackDirection)); MagicBoltState state; - state.mSourceName = sourceName; state.mSpellId = spellId; state.mCasterHandle = caster; if (caster.getClass().isActor()) state.mActorId = caster.getClass().getCreatureStats(caster).getActorId(); else state.mActorId = -1; - state.mStack = stack; std::string texture = ""; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, effects); + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, state.mSourceName, state.mSpellId); // Non-projectile should have been removed by getMagicBoltData if (state.mEffects.mList.empty()) @@ -277,7 +291,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(effects); + osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -364,7 +378,7 @@ namespace MWWorld cast.mHitPosition = pos; cast.mId = it->mSpellId; cast.mSourceName = it->mSourceName; - cast.mStack = it->mStack; + cast.mStack = false; cast.inflict(result.mHitObject, caster, it->mEffects, ESM::RT_Target, false, true); } } @@ -504,11 +518,7 @@ namespace MWWorld state.mActorId = it->mActorId; state.mSpellId = it->mSpellId; - state.mEffects = it->mEffects; - state.mSound = it->mSoundIds.at(0); - state.mSourceName = it->mSourceName; state.mSpeed = it->mSpeed; - state.mStack = it->mStack; state.save(writer); @@ -553,13 +563,21 @@ namespace MWWorld esm.load(reader); MagicBoltState state; - state.mSourceName = esm.mSourceName; state.mIdMagic.push_back(esm.mId); state.mSpellId = esm.mSpellId; state.mActorId = esm.mActorId; - state.mStack = esm.mStack; std::string texture = ""; - state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, esm.mEffects); + + try + { + state.mEffects = getMagicBoltData(state.mIdMagic, state.mSoundIds, state.mSpeed, texture, state.mSourceName, state.mSpellId); + } + catch(...) + { + std::cerr << "Warning: Failed to recreate magic projectile from saved data (id \"" << state.mSpellId << "\" no longer exists?)" << std::endl; + return true; + } + state.mSpeed = esm.mSpeed; // speed is derived from non-projectile effects as well as // projectile effects, so we can't calculate it from the save // file's effect list, which is already trimmed of non-projectile @@ -577,7 +595,7 @@ namespace MWWorld return true; } - osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(esm.mEffects); + osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects); createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index c7025a3a0..1ef72a048 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -49,8 +49,7 @@ namespace MWWorld MWRender::RenderingManager* rendering, MWPhysics::PhysicsSystem* physics); /// If caster is an actor, the actor's facing orientation is used. Otherwise fallbackDirection is used. - void launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); + void launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection); void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); @@ -101,8 +100,6 @@ namespace MWWorld float mSpeed; - bool mStack; - std::vector mSounds; std::vector mSoundIds; }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a9506385d..40bc13c94 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2816,10 +2816,9 @@ namespace MWWorld mProjectileManager->launchProjectile(actor, projectile, worldPos, orient, bow, speed, attackStrength); } - void World::launchMagicBolt (const std::string &spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection) + void World::launchMagicBolt (const std::string &spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) { - mProjectileManager->launchMagicBolt(spellId, stack, effects, caster, sourceName, fallbackDirection); + mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection); } const std::vector& World::getContentFiles() const diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a15dcaf3d..774753b6c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -601,8 +601,7 @@ namespace MWWorld */ virtual void castSpell (const MWWorld::Ptr& actor); - virtual void launchMagicBolt (const std::string& spellId, bool stack, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, const std::string& sourceName, const osg::Vec3f& fallbackDirection); + virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); diff --git a/components/esm/projectilestate.cpp b/components/esm/projectilestate.cpp index 70ae4c5ee..8ade9d5b2 100644 --- a/components/esm/projectilestate.cpp +++ b/components/esm/projectilestate.cpp @@ -27,11 +27,7 @@ namespace ESM BaseProjectileState::save(esm); esm.writeHNString ("SPEL", mSpellId); - esm.writeHNString ("SRCN", mSourceName); - mEffects.save(esm); esm.writeHNT ("SPED", mSpeed); - esm.writeHNT ("STCK", mStack); - esm.writeHNString ("SOUN", mSound); } void MagicBoltState::load(ESMReader &esm) @@ -39,11 +35,14 @@ namespace ESM BaseProjectileState::load(esm); mSpellId = esm.getHNString("SPEL"); - mSourceName = esm.getHNString ("SRCN"); - mEffects.load(esm); + if (esm.isNextSub("SRCN")) // for backwards compatibility + esm.skipHSub(); + ESM::EffectList().load(esm); // for backwards compatibility esm.getHNT (mSpeed, "SPED"); - esm.getHNT (mStack, "STCK"); - mSound = esm.getHNString ("SOUN"); + if (esm.isNextSub("STCK")) // for backwards compatibility + esm.skipHSub(); + if (esm.isNextSub("SOUN")) // for backwards compatibility + esm.skipHSub(); } void ProjectileState::save(ESMWriter &esm) const diff --git a/components/esm/projectilestate.hpp b/components/esm/projectilestate.hpp index 3471fbfc7..67ec89bb6 100644 --- a/components/esm/projectilestate.hpp +++ b/components/esm/projectilestate.hpp @@ -31,11 +31,7 @@ namespace ESM struct MagicBoltState : public BaseProjectileState { std::string mSpellId; - std::string mSourceName; - ESM::EffectList mEffects; float mSpeed; - bool mStack; - std::string mSound; void load (ESMReader &esm); void save (ESMWriter &esm) const; From 186cc1e37066abe92c2117f5b14deb5fb1da4fe6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:29:34 +0200 Subject: [PATCH 213/521] Fix skins incorrectly named 'Client' to avoid a collision with new MyGUI feature cfdaf5f --- .../openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_dialogue_window.layout | 2 +- files/mygui/openmw_hud_box.skin.xml | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 43b0518fd..906ca2352 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b02..1ed399572 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1..a1c4f608b 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ - + - + - + - + - + @@ -36,11 +36,11 @@ - + - + @@ -48,11 +48,11 @@ - + - + From fb975d02dba79d9eb73ce3be14cb1127a8ce47ea Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:41:50 +0200 Subject: [PATCH 214/521] Use client coordinates in HBox/VBox --- components/widgets/box.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ce8ce951..eeddc22dd 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -171,9 +171,11 @@ namespace Gui total_width += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } @@ -191,19 +193,19 @@ namespace Gui continue; bool vstretch = w->getUserString ("VStretch") == "true"; - int max_height = getSize().height - mPadding*2; + int max_height = getClientCoord().height - mPadding*2; int height = vstretch ? max_height : sizes[i].first.height; MyGUI::IntCoord widgetCoord; widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + widgetCoord.top = mPadding + (getClientCoord().height-mPadding*2 - height) / 2; int width = 0; if (sizes[i].second) { if (h_stretched_count == 0) throw std::logic_error("unexpected"); - width = sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count; + width = sizes[i].first.width + (getClientCoord().width-mPadding*2 - total_width)/h_stretched_count; } else width = sizes[i].first.width; @@ -317,13 +319,14 @@ namespace Gui total_height += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } - int curY = 0; for (unsigned int i = 0; i < count; ++i) { @@ -337,19 +340,19 @@ namespace Gui continue; bool hstretch = w->getUserString ("HStretch") == "true"; - int maxWidth = getSize().width - mPadding*2; + int maxWidth = getClientCoord().width - mPadding*2; int width = hstretch ? maxWidth : sizes[i].first.width; MyGUI::IntCoord widgetCoord; widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + widgetCoord.left = mPadding + (getClientCoord().width-mPadding*2 - width) / 2; int height = 0; if (sizes[i].second) { if (v_stretched_count == 0) throw std::logic_error("unexpected"); - height = sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count; + height = sizes[i].first.height + (getClientCoord().height-mPadding*2 - total_height)/v_stretched_count; } else height = sizes[i].first.height; From d07fe91cfef85dc8a530bd12237bf3ece7ef6388 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:53:59 +0200 Subject: [PATCH 215/521] Don't use MW_Dialog skin with plain Widgets After MyGUI commit cfdaf5f , the 'Client' area will be used for every type of widget, whereas previously it would only be used for some widgets like 'Window'. Use 'Window' widget where the client was always used. This fixes a wrong margin when built with cfdaf5f or later. --- files/mygui/openmw_hud.layout | 10 +++++----- files/mygui/openmw_jail_screen.layout | 6 +++--- files/mygui/openmw_loading_screen.layout | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8fe25a5dc..366b0c4c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ - + - + - - + + - + diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8..76aa05b86 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ - + - + - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e..69df20022 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - + From 7dec773ea95379538aa02a8907381c3864cabcf5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 23:03:14 +0200 Subject: [PATCH 216/521] Fix global map arrow/button not showing for a split second when the window is opened for the first time --- apps/openmw/mwgui/mapwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7d81b6ab3..ed9dabd2d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1002,6 +1002,9 @@ namespace MWGui mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + // Redraw children in proper order + mGlobalMap->getParent()->_updateChilds(); } } From fe6f9ffff439e685ce0dea794543a2ac4ea348c1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:29:34 +0200 Subject: [PATCH 217/521] Fix skins incorrectly named 'Client' to avoid a collision with new MyGUI feature cfdaf5f --- .../openmw_chargen_class_description.layout | 2 +- files/mygui/openmw_dialogue_window.layout | 2 +- files/mygui/openmw_hud_box.skin.xml | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 43b0518fd..906ca2352 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b02..1ed399572 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1..a1c4f608b 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ - + - + - + - + - + @@ -36,11 +36,11 @@ - + - + @@ -48,11 +48,11 @@ - + - + From 58f96884332bea595ef4b1ec51896a92c7d9ae28 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:41:50 +0200 Subject: [PATCH 218/521] Use client coordinates in HBox/VBox --- components/widgets/box.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ce8ce951..eeddc22dd 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -171,9 +171,11 @@ namespace Gui total_width += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } @@ -191,19 +193,19 @@ namespace Gui continue; bool vstretch = w->getUserString ("VStretch") == "true"; - int max_height = getSize().height - mPadding*2; + int max_height = getClientCoord().height - mPadding*2; int height = vstretch ? max_height : sizes[i].first.height; MyGUI::IntCoord widgetCoord; widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + widgetCoord.top = mPadding + (getClientCoord().height-mPadding*2 - height) / 2; int width = 0; if (sizes[i].second) { if (h_stretched_count == 0) throw std::logic_error("unexpected"); - width = sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count; + width = sizes[i].first.width + (getClientCoord().width-mPadding*2 - total_width)/h_stretched_count; } else width = sizes[i].first.width; @@ -317,13 +319,14 @@ namespace Gui total_height += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } - int curY = 0; for (unsigned int i = 0; i < count; ++i) { @@ -337,19 +340,19 @@ namespace Gui continue; bool hstretch = w->getUserString ("HStretch") == "true"; - int maxWidth = getSize().width - mPadding*2; + int maxWidth = getClientCoord().width - mPadding*2; int width = hstretch ? maxWidth : sizes[i].first.width; MyGUI::IntCoord widgetCoord; widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + widgetCoord.left = mPadding + (getClientCoord().width-mPadding*2 - width) / 2; int height = 0; if (sizes[i].second) { if (v_stretched_count == 0) throw std::logic_error("unexpected"); - height = sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count; + height = sizes[i].first.height + (getClientCoord().height-mPadding*2 - total_height)/v_stretched_count; } else height = sizes[i].first.height; From aaa727757d63c2c626355d0491adedb1c2a8f8cc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 22:53:59 +0200 Subject: [PATCH 219/521] Don't use MW_Dialog skin with plain Widgets After MyGUI commit cfdaf5f , the 'Client' area will be used for every type of widget, whereas previously it would only be used for some widgets like 'Window'. Use 'Window' widget where the client was always used. This fixes a wrong margin when built with cfdaf5f or later. --- files/mygui/openmw_hud.layout | 10 +++++----- files/mygui/openmw_jail_screen.layout | 6 +++--- files/mygui/openmw_loading_screen.layout | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8fe25a5dc..366b0c4c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ - + - + - - + + - + diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8..76aa05b86 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ - + - + - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e..69df20022 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - + From f004622530f6c690dbc687652e975701bb47767c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 20 Sep 2017 23:03:14 +0200 Subject: [PATCH 220/521] Fix global map arrow/button not showing for a split second when the window is opened for the first time --- apps/openmw/mwgui/mapwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7d81b6ab3..ed9dabd2d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1002,6 +1002,9 @@ namespace MWGui mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + // Redraw children in proper order + mGlobalMap->getParent()->_updateChilds(); } } From c72aa19d6d8a91c3ce34659e5d5a8bb4826bc0db Mon Sep 17 00:00:00 2001 From: Date: Wed, 20 Sep 2017 23:53:12 -0500 Subject: [PATCH 221/521] first pass on optimization of nif parsing functions from the file stream --- components/files/constrainedfilestream.cpp | 2 +- components/nif/nifstream.cpp | 132 +--------------- components/nif/nifstream.hpp | 170 ++++++++++++++++++--- 3 files changed, 151 insertions(+), 153 deletions(-) diff --git a/components/files/constrainedfilestream.cpp b/components/files/constrainedfilestream.cpp index 4f76139d9..b239ec6a1 100644 --- a/components/files/constrainedfilestream.cpp +++ b/components/files/constrainedfilestream.cpp @@ -8,7 +8,7 @@ namespace { // somewhat arbitrary though 64KB buffers didn't seem to improve performance any -const size_t sBufferSize = 4096; +const size_t sBufferSize = 8192; } namespace Files diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index d0fc9bab0..08a7466fa 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -6,138 +6,8 @@ namespace Nif { //Private functions -uint8_t NIFStream::read_byte() -{ - uint8_t byte; - inp->read((char*)&byte, 1); - return byte; -} -uint16_t NIFStream::read_le16() -{ - uint8_t buffer[2]; - inp->read((char*)buffer, 2); - return buffer[0] | (buffer[1]<<8); -} -uint32_t NIFStream::read_le32() -{ - uint8_t buffer[4]; - inp->read((char*)buffer, 4); - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); -} -float NIFStream::read_le32f() -{ - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; -} -//Public functions -osg::Vec2f NIFStream::getVector2() -{ - osg::Vec2f vec; - for(size_t i = 0;i < 2;i++) - vec._v[i] = getFloat(); - return vec; -} -osg::Vec3f NIFStream::getVector3() -{ - osg::Vec3f vec; - for(size_t i = 0;i < 3;i++) - vec._v[i] = getFloat(); - return vec; -} -osg::Vec4f NIFStream::getVector4() -{ - osg::Vec4f vec; - for(size_t i = 0;i < 4;i++) - vec._v[i] = getFloat(); - return vec; -} -Matrix3 NIFStream::getMatrix3() -{ - Matrix3 mat; - for(size_t i = 0;i < 3;i++) - { - for(size_t j = 0;j < 3;j++) - mat.mValues[i][j] = getFloat(); - } - return mat; -} -osg::Quat NIFStream::getQuaternion() -{ - osg::Quat quat; - quat.w() = getFloat(); - quat.x() = getFloat(); - quat.y() = getFloat(); - quat.z() = getFloat(); - return quat; -} -Transformation NIFStream::getTrafo() -{ - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; -} -std::string NIFStream::getString(size_t length) -{ - std::vector str (length+1, 0); - - inp->read(&str[0], length); - - return &str[0]; -} -std::string NIFStream::getString() -{ - size_t size = read_le32(); - return getString(size); -} -std::string NIFStream::getVersionString() -{ - std::string result; - std::getline(*inp, result); - return result; -} - -void NIFStream::getUShorts(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); -} -void NIFStream::getFloats(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); -} -void NIFStream::getVector2s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); -} -void NIFStream::getVector3s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); -} -void NIFStream::getVector4s(std::vector &vec, size_t size) -{ - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); -} -void NIFStream::getQuaternions(std::vector &quat, size_t size) -{ - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); -} +//Public functions } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 860c62e64..d33771f45 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -2,7 +2,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP - +#include #include #include #include @@ -26,10 +26,44 @@ class NIFStream { /// Input stream Files::IStreamPtr inp; - uint8_t read_byte(); - uint16_t read_le16(); - uint32_t read_le32(); - float read_le32f(); + uint8_t read_byte() { + uint8_t byte; + inp->read((char*)&byte, 1); + return byte; + } + + uint16_t read_le16() { + alignas(2) uint8_t buffer[2]; + inp->read((char*)buffer, 2); + return static_cast(*((uint16_t*)buffer)); + } + uint32_t read_le32() { + alignas(4) uint8_t buffer[4]; + inp->read((char*)buffer, 4); + return static_cast(*((uint32_t*)buffer)); + } + uint64_t read_le64() { + alignas(8) uint8_t buffer[8]; + inp->read((char*)buffer, 8); + return static_cast(*((uint64_t*)buffer)); + } + __m128 read_le96() { + alignas(8) uint8_t buffer[16]; + inp->read((char*)buffer, 12); + return static_cast<__m128>(*((__m128*)buffer)); + } + __m128 read_le128() { + alignas(16) uint8_t buffer[16]; + inp->read((char*)buffer, 16); + return static_cast<__m128>(*((__m128*)buffer)); + } + float read_le32f() { + union { + uint32_t i; + float f; + } u = { read_le32() }; + return u.f; + } public: @@ -46,26 +80,120 @@ public: unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } - osg::Vec2f getVector2(); - osg::Vec3f getVector3(); - osg::Vec4f getVector4(); - Matrix3 getMatrix3(); - osg::Quat getQuaternion(); - Transformation getTrafo(); + osg::Vec2f getVector2() { + union { + uint64_t i; + float f[2]; + } u = { read_le64() }; + osg::Vec2f vec; + for (size_t i = 0;i < 2;i++) + vec._v[i] = u.f[i]; + return vec; + } + osg::Vec3f getVector3() { + union { + __m128 i; + float f[4]; + } u = { read_le96() }; + osg::Vec3f vec; + for (size_t i = 0;i < 3;i++) + vec._v[i] = u.f[i]; + return vec; + } + osg::Vec4f getVector4() { + union { + __m128 i; + float f[4]; + } u = { read_le128() }; + osg::Vec4f vec; + for (size_t i = 0;i < 4;i++) + vec._v[i] = u.f[i]; + return vec; + } + Matrix3 getMatrix3() { + Matrix3 mat; + alignas(16) union { + float f[9]; + uint8_t buffer[36]; + } u; + inp->read((char*)u.buffer, 36); + for (size_t i = 0;i < 3;i++) + { + for (size_t j = 0;j < 3;j++) + mat.mValues[i][j] = u.f[3*i+j]; + } + return mat; + } + osg::Quat getQuaternion() { + union { + __m128 i; + float f[4]; + } u = { read_le128() }; + osg::Quat quat; + quat.w() = u.f[0]; + quat.x() = u.f[1]; + quat.y() = u.f[2]; + quat.z() = u.f[3]; + return quat; + } + Transformation getTrafo() { + Transformation t; + t.pos = getVector3(); + t.rotation = getMatrix3(); + t.scale = getFloat(); + return t; + } ///Read in a string of the given length - std::string getString(size_t length); + std::string getString(size_t length) { + std::vector str(length + 1, 0); + + inp->read(&str[0], length); + + return &str[0]; + } ///Read in a string of the length specified in the file - std::string getString(); + std::string getString() { + size_t size = read_le32(); + return getString(size); + } ///This is special since the version string doesn't start with a number, and ends with "\n" - std::string getVersionString(); - - void getUShorts(std::vector &vec, size_t size); - void getFloats(std::vector &vec, size_t size); - void getVector2s(std::vector &vec, size_t size); - void getVector3s(std::vector &vec, size_t size); - void getVector4s(std::vector &vec, size_t size); - void getQuaternions(std::vector &quat, size_t size); + std::string getVersionString() { + std::string result; + std::getline(*inp, result); + return result; + } + + void getUShorts(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getUShort(); + } + void getFloats(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getFloat(); + } + void getVector2s(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); + } + void getVector3s(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); + } + void getVector4s(std::vector &vec, size_t size) { + vec.resize(size); + for (size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); + } + void getQuaternions(std::vector &quat, size_t size) { + quat.resize(size); + for (size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); + } }; } From 5da532a36c696cad5b226c22f5de2847daaac320 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Sep 2017 10:32:34 +0400 Subject: [PATCH 222/521] Do not play draw weapon animation when equip a new weapon (bug #4056) --- apps/openmw/mwmechanics/character.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bfe8812e6..861135dfb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1116,6 +1116,11 @@ bool CharacterController::updateWeaponState() priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; + + // We should not play equipping animation and sound during weapon->weapon transition + bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell && + mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; + if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut && mHitState != CharState_Hit) { @@ -1138,13 +1143,16 @@ bool CharacterController::updateWeaponState() else { getWeaponGroup(weaptype, weapgroup); - mAnimation->showWeapons(false); mAnimation->setWeaponGroup(weapgroup); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "equip start", "equip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_EquipingWeap; + if (!isStillWeapon) + { + mAnimation->showWeapons(false); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, + 1.0f, "equip start", "equip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_EquipingWeap; + } if(isWerewolf) { @@ -1158,7 +1166,7 @@ bool CharacterController::updateWeaponState() } } - if(!soundid.empty()) + if(!soundid.empty() && !isStillWeapon) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); From 16d9773c6c75e2069104da1302d3a31a3620a7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:25:36 +0200 Subject: [PATCH 223/521] fix water shader artifacts at shores --- apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 29 ++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2329e7afa..68c07c1ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -30; + const float clipFudge = -5; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c04233fcf..b5d7d1a6a 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,6 +31,8 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness +const float REFLECTION_BUMP_SUPRESS_DEPTH = 150.0; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) + const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -74,6 +76,13 @@ uniform float near; uniform float far; uniform vec3 nodePosition; +float transformDepth(float depth) // helper for transforming refraction depth + { + float z_n = 2.0 * depth - 1.0; + depth = 2.0 * near * far / (far + near - z_n * (far - near)); + return depth - depthPassthrough; + } + void main(void) { vec3 worldPos = position.xyz + nodePosition.xyz; @@ -147,8 +156,12 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); + float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); + + float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPRESS_DEPTH,0,1); + // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; // refraction #if REFRACTION @@ -165,10 +178,7 @@ void main(void) vec3 waterColor = WATER_COLOR; waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - + float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); float waterDepth = refractionDepth - depthPassthrough; if (cameraPos.z > 0.0) @@ -185,6 +195,15 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; + +/*float nonRefractionDepth = texture2D(refractionDepthMap, screenCoords).x; +z_n = 2.0 * nonRefractionDepth - 1.0; +nonRefractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); + +float realWaterDepth = nonRefractionDepth - depthPassthrough; +*/ +//gl_FragData[0] = vec4(refractionSuppressor,0,0,0); + #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif From c43baf6e946efa4a4baf25e1aba048a3d660abbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:31:26 +0200 Subject: [PATCH 224/521] remove commented code --- files/shaders/water_fragment.glsl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index b5d7d1a6a..6e4edfb84 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -195,15 +195,6 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; - -/*float nonRefractionDepth = texture2D(refractionDepthMap, screenCoords).x; -z_n = 2.0 * nonRefractionDepth - 1.0; -nonRefractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - -float realWaterDepth = nonRefractionDepth - depthPassthrough; -*/ -//gl_FragData[0] = vec4(refractionSuppressor,0,0,0); - #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif From 658fa0fdae4039714bd7563a2312c82c9db9124a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:33:57 +0200 Subject: [PATCH 225/521] fix typo --- files/shaders/water_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 6e4edfb84..867a24a70 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPRESS_DEPTH = 150.0; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float REFLECTION_BUMP_SUPPRESS_DEPTH = 150; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -158,7 +158,7 @@ void main(void) float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPRESS_DEPTH,0,1); + float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; From 090a8408b828192498209342bcab29d8bdd12357 Mon Sep 17 00:00:00 2001 From: Date: Thu, 21 Sep 2017 22:37:19 -0500 Subject: [PATCH 226/521] made nif basic type read optimizations more portable --- components/nif/nifstream.hpp | 146 +++++++++++++++-------------------- 1 file changed, 63 insertions(+), 83 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index d33771f45..35c042e7d 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -2,7 +2,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP -#include + #include #include #include @@ -21,50 +21,38 @@ namespace Nif class NIFFile; +template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + pIStream->read((char*)dest, numInstances * sizeof(T)); +#else + char buffer[numInstances * sizeof(T)]; + pIStream->read((char*)buffer, numInstances * sizeof(T)); + /* + Due to the loop iterations being known at compile time, + this nested loop will most likely be unrolled + */ + for (uint32_t i = 0; i < numInstances; i++) + { + dest[i] = 0; + for (uint32_t byte = 0; byte < sizeof(T); byte++) + dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + } +#endif +} + +template type inline readLittleEndianType(Files::IStreamPtr &pIStream) +{ + type val; + readLittleEndianBufferOfType<1,type>(pIStream, (type*)&val); + return val; +} + class NIFStream { /// Input stream Files::IStreamPtr inp; - uint8_t read_byte() { - uint8_t byte; - inp->read((char*)&byte, 1); - return byte; - } - - uint16_t read_le16() { - alignas(2) uint8_t buffer[2]; - inp->read((char*)buffer, 2); - return static_cast(*((uint16_t*)buffer)); - } - uint32_t read_le32() { - alignas(4) uint8_t buffer[4]; - inp->read((char*)buffer, 4); - return static_cast(*((uint32_t*)buffer)); - } - uint64_t read_le64() { - alignas(8) uint8_t buffer[8]; - inp->read((char*)buffer, 8); - return static_cast(*((uint64_t*)buffer)); - } - __m128 read_le96() { - alignas(8) uint8_t buffer[16]; - inp->read((char*)buffer, 12); - return static_cast<__m128>(*((__m128*)buffer)); - } - __m128 read_le128() { - alignas(16) uint8_t buffer[16]; - inp->read((char*)buffer, 16); - return static_cast<__m128>(*((__m128*)buffer)); - } - float read_le32f() { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; - } - public: NIFFile * const file; @@ -73,67 +61,59 @@ public: void skip(size_t size) { inp->ignore(size); } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - unsigned int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } + char getChar() + { + return readLittleEndianType(inp); + } + short getShort() + { + return readLittleEndianType(inp); + } + unsigned short getUShort() + { + return readLittleEndianType(inp); + } + int getInt() + { + return readLittleEndianType(inp); + } + unsigned int getUInt() + { + return readLittleEndianType(inp); + } + float getFloat() + { + return readLittleEndianType(inp); + } osg::Vec2f getVector2() { - union { - uint64_t i; - float f[2]; - } u = { read_le64() }; osg::Vec2f vec; - for (size_t i = 0;i < 2;i++) - vec._v[i] = u.f[i]; + readLittleEndianBufferOfType<2,float>(inp, (float*)&vec._v[0]); return vec; } osg::Vec3f getVector3() { - union { - __m128 i; - float f[4]; - } u = { read_le96() }; osg::Vec3f vec; - for (size_t i = 0;i < 3;i++) - vec._v[i] = u.f[i]; + readLittleEndianBufferOfType<3, float>(inp, (float*)&vec._v[0]); return vec; } osg::Vec4f getVector4() { - union { - __m128 i; - float f[4]; - } u = { read_le128() }; osg::Vec4f vec; - for (size_t i = 0;i < 4;i++) - vec._v[i] = u.f[i]; + readLittleEndianBufferOfType<4, float>(inp, (float*)&vec._v[0]); return vec; } Matrix3 getMatrix3() { Matrix3 mat; - alignas(16) union { - float f[9]; - uint8_t buffer[36]; - } u; - inp->read((char*)u.buffer, 36); - for (size_t i = 0;i < 3;i++) - { - for (size_t j = 0;j < 3;j++) - mat.mValues[i][j] = u.f[3*i+j]; - } + readLittleEndianBufferOfType<9, float>(inp, (float*)&mat.mValues); return mat; } osg::Quat getQuaternion() { - union { - __m128 i; - float f[4]; - } u = { read_le128() }; + float f[4]; + readLittleEndianBufferOfType<4, float>(inp, (float*)&f); osg::Quat quat; - quat.w() = u.f[0]; - quat.x() = u.f[1]; - quat.y() = u.f[2]; - quat.z() = u.f[3]; + quat.w() = f[0]; + quat.x() = f[1]; + quat.y() = f[2]; + quat.z() = f[3]; return quat; } Transformation getTrafo() { @@ -154,7 +134,7 @@ public: } ///Read in a string of the length specified in the file std::string getString() { - size_t size = read_le32(); + size_t size = readLittleEndianType(inp); return getString(size); } ///This is special since the version string doesn't start with a number, and ends with "\n" From 8834066dea932defa23f8345210eca2ecf2739c3 Mon Sep 17 00:00:00 2001 From: Date: Thu, 21 Sep 2017 23:47:09 -0500 Subject: [PATCH 227/521] make streaming to a type array in nif a direct copy from the file into the vector --- components/nif/nifstream.hpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 35c042e7d..4d7e39ecb 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -41,6 +41,25 @@ template inline void readLittleEndianBufferO #endif } +template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + pIStream->read((char*)dest, numInstances * sizeof(T)); +#else + char buffer[numInstances * sizeof(T)]; + pIStream->read((char*)buffer, numInstances * sizeof(T)); + /* + Due to the loop iterations being known at compile time, + this nested loop will most likely be unrolled + */ + for (uint32_t i = 0; i < numInstances; i++) + { + dest[i] = 0; + for (uint32_t byte = 0; byte < sizeof(T); byte++) + dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + } +#endif +} template type inline readLittleEndianType(Files::IStreamPtr &pIStream) { type val; @@ -146,28 +165,23 @@ public: void getUShorts(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getUShort(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getFloats(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector2s(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector3s(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector4s(std::vector &vec, size_t size) { vec.resize(size); - for (size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getQuaternions(std::vector &quat, size_t size) { quat.resize(size); From 4580024d76cbff2b3de7313f3ae13793f6e16637 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 11 Sep 2017 14:49:55 +0400 Subject: [PATCH 228/521] Unequip all items from dead corpse when take all items (bug #4095) --- apps/openmw/mwgui/container.cpp | 50 +++++++++++++------- apps/openmw/mwgui/inventoryitemmodel.cpp | 32 +++++++++++-- apps/openmw/mwscript/containerextensions.cpp | 3 +- apps/openmw/mwworld/containerstore.cpp | 6 +-- apps/openmw/mwworld/containerstore.hpp | 4 +- apps/openmw/mwworld/inventorystore.cpp | 5 ++ apps/openmw/mwworld/inventorystore.hpp | 3 +- 7 files changed, 74 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c9be21322..0ba4839e7 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -211,31 +212,48 @@ namespace MWGui void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) + return; + + // transfer everything into the player's inventory + ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); + mModel->update(); + + // unequip all items to avoid unequipping/reequipping + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // transfer everything into the player's inventory - ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); - mModel->update(); + MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); for (size_t i=0; igetItemCount(); ++i) { - if (i==0) - { - // play the sound of the first object - MWWorld::Ptr item = mModel->getItem(i).mBase; - std::string sound = item.getClass().getUpSoundId(item); - MWBase::Environment::get().getWindowManager()->playSound(sound); - } - const ItemStack& item = mModel->getItem(i); + if (invStore.isEquipped(item.mBase) == false) + continue; + + invStore.unequipItem(item.mBase, mPtr); + } + } - if (!onTakeItem(item, item.mCount)) - break; + mModel->update(); - mModel->moveItem(item, item.mCount, playerModel); + for (size_t i=0; igetItemCount(); ++i) + { + if (i==0) + { + // play the sound of the first object + MWWorld::Ptr item = mModel->getItem(i).mBase; + std::string sound = item.getClass().getUpSoundId(item); + MWBase::Environment::get().getWindowManager()->playSound(sound); } - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + const ItemStack& item = mModel->getItem(i); + + if (!onTakeItem(item, item.mCount)) + break; + + mModel->moveItem(item, item.mCount, playerModel); } + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 2fe540f22..222243ec1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -1,5 +1,10 @@ #include "inventoryitemmodel.hpp" +#include + +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" @@ -45,16 +50,33 @@ MWWorld::Ptr InventoryItemModel::copyItem (const ItemStack& item, size_t count, return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner); } - void InventoryItemModel::removeItem (const ItemStack& item, size_t count) { - MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor); - int removed = store.remove(item.mBase, count, mActor); + int removed = 0; + // Re-equipping makes sense only if a target has inventory + if (mActor.getClass().hasInventoryStore(mActor)) + { + MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor); + removed = store.remove(item.mBase, count, mActor, true); + } + else + { + MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor); + removed = store.remove(item.mBase, count, mActor); + } + + std::stringstream error; if (removed == 0) - throw std::runtime_error("Item to remove not found in container store"); + { + error << "Item '" << item.mBase.getCellRef().getRefId() << "' was not found in container store to remove"; + throw std::runtime_error(error.str()); + } else if (removed < static_cast(count)) - throw std::runtime_error("Not enough items in the stack to remove"); + { + error << "Not enough items '" << item.mBase.getCellRef().getRefId() << "' in the stack to remove (" << static_cast(count) << " requested, " << removed << " found)"; + throw std::runtime_error(error.str()); + } } MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index dfc066bcd..8457b33cb 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -143,8 +143,7 @@ namespace MWScript if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) itemName = iter->getClass().getName(*iter); - // Actors should not equip a replacement when items are removed with RemoveItem - int numRemoved = store.remove(item, count, ptr, false); + int numRemoved = store.remove(item, count, ptr); // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index eef10b905..cd04a425b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -408,13 +408,13 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons return it; } -int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement) +int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor) { int toRemove = count; for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) - toRemove -= remove(*iter, toRemove, actor, equipReplacement); + toRemove -= remove(*iter, toRemove, actor); flagAsModified(); @@ -422,7 +422,7 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const return count - toRemove; } -int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) +int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor) { assert(this == item.getContainerStore()); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f27ff1db9..dbb82cbda 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -142,12 +142,12 @@ namespace MWWorld ContainerStoreIterator add(const std::string& id, int count, const Ptr& actorPtr); ///< Utility to construct a ManualRef and call add(ptr, count, actorPtr, true) - int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement = true); + int remove(const std::string& itemId, int count, const Ptr& actor); ///< Remove \a count item(s) designated by \a itemId from this container. /// /// @return the number of items actually removed - virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); + virtual int remove(const Ptr& item, int count, const Ptr& actor); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index a6394757f..b599b3583 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -654,6 +654,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( return mSelectedEnchantItem; } +int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) +{ + return remove(item, count, actor, false); +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { int retCount = ContainerStore::remove(item, count, actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 90f7f7788..851abf408 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -177,7 +177,8 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other - virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); + virtual int remove(const Ptr& item, int count, const Ptr& actor); + virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed From 8df79625e8d691109ea8dc0e53500d769ebe8373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 10:53:02 +0200 Subject: [PATCH 229/521] fix water shader --- apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 68c07c1ab..9679533be 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; + const float clipFudge = -6; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 867a24a70..bb56e95c6 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -76,7 +76,7 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float transformDepth(float depth) // helper for transforming refraction depth +float transformDepth(float depth) // helper for transforming water depth { float z_n = 2.0 * depth - 1.0; depth = 2.0 * near * far / (far + near - z_n * (far - near)); @@ -156,27 +156,30 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); +#if REFRACTION float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); +#else + float shore = 1.0; +#endif // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; // refraction #if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP*shore)).rgb; // brighten up the refraction underwater refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; #endif - // specular vec3 R = reflect(vVec, normal); float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; vec3 waterColor = WATER_COLOR; waterColor = waterColor * length(gl_LightModel.ambient.xyz); + #if REFRACTION float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); float waterDepth = refractionDepth - depthPassthrough; From 6260bb1366c91240d391d2c4e0e2b367422a7c12 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 14:51:06 +0400 Subject: [PATCH 230/521] Implement SwimAttack1-3 and SwimDeathKnockDown/Out animations --- apps/openmw/mwmechanics/character.cpp | 39 +++++++++++++++++++-------- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index df62ca490..681ca7f07 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -621,6 +621,12 @@ void CharacterController::playDeath(float startpoint, CharacterState death) case CharState_SwimDeath: mCurrentDeath = "swimdeath"; break; + case CharState_SwimDeathKnockDown: + mCurrentDeath = "swimdeathknockdown"; + break; + case CharState_SwimDeathKnockOut: + mCurrentDeath = "swimdeathknockout"; + break; case CharState_DeathKnockDown: mCurrentDeath = "deathknockdown"; break; @@ -674,7 +680,16 @@ void CharacterController::playRandomDeath(float startpoint) MWBase::Environment::get().getWorld()->useDeathCamera(); } - if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath")) + bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + if(isSwimming && mAnimation->hasAnimation("swimdeathknockdown") && mHitState == CharState_KnockDown) + { + mDeathState = CharState_SwimDeathKnockDown; + } + else if(isSwimming && mAnimation->hasAnimation("swimdeathknockout") && mHitState == CharState_KnockOut) + { + mDeathState = CharState_SwimDeathKnockOut; + } + else if(isSwimming && mAnimation->hasAnimation("swimdeath")) { mDeathState = CharState_SwimDeath; } @@ -876,16 +891,17 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else if(evt.compare(off, len, "hit") == 0) { - if (groupname == "attack1") + if (groupname == "attack1" || groupname == "swimattack1") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") + else if (groupname == "attack2" || groupname == "swimattack2") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") + else if (groupname == "attack3" || groupname == "swimattack1") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else mPtr.getClass().hit(mPtr, mAttackStrength); } - else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0 + else if (!groupname.empty() + && (groupname.compare(0, groupname.size()-1, "attack") == 0 || groupname.compare(0, groupname.size()-1, "swimattack") == 0) && evt.compare(off, len, "start") == 0) { std::multimap::const_iterator hitKey = key; @@ -905,11 +921,11 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: } if (!hasHitKey) { - if (groupname == "attack1") + if (groupname == "attack1" || groupname == "swimattack1") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); - else if (groupname == "attack2") + else if (groupname == "attack2" || groupname == "swimattack2") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); - else if (groupname == "attack3") + else if (groupname == "attack3" || groupname == "swimattack3") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); } } @@ -1035,13 +1051,14 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { + bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); int roll = Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) - mCurrentWeapon = "attack1"; + mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack1") ? "swimattack1" : "attack1"; else if (roll == 1) - mCurrentWeapon = "attack2"; + mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack2") ? "swimattack2" : "attack2"; else - mCurrentWeapon = "attack3"; + mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack3") ? "swimattack3" : "attack3"; } if (!mCurrentWeapon.empty()) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9bcad0994..cc057e50d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -97,6 +97,8 @@ enum CharacterState { CharState_Death4, CharState_Death5, CharState_SwimDeath, + CharState_SwimDeathKnockDown, + CharState_SwimDeathKnockOut, CharState_DeathKnockDown, CharState_DeathKnockOut, From 3eb1308c0de1c291fbcabd1fcfbd5de0a9d64ef6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 15:26:35 +0400 Subject: [PATCH 231/521] Implement SwimKnockdown/out animations --- apps/openmw/mwmechanics/character.cpp | 61 +++++++++++++++++++-------- apps/openmw/mwmechanics/character.hpp | 3 ++ 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 681ca7f07..02da5ea56 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -245,21 +245,40 @@ void CharacterController::refreshHitRecoilAnims() bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); + bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { - mHitState = CharState_KnockOut; - mCurrentHit = "knockout"; + if (isSwimming && mAnimation->hasAnimation("swimknockout")) + { + mHitState = CharState_SwimKnockOut; + mCurrentHit = "swimknockout"; + } + else + { + mHitState = CharState_KnockOut; + mCurrentHit = "knockout"; + } + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul); mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true); } else if(knockdown && mAnimation->hasAnimation("knockdown")) { - mHitState = CharState_KnockDown; - mCurrentHit = "knockdown"; + if (isSwimming && mAnimation->hasAnimation("swimknockdown")) + { + mHitState = CharState_SwimKnockDown; + mCurrentHit = "swimknockdown"; + } + else + { + mHitState = CharState_KnockDown; + mCurrentHit = "knockdown"; + } + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } else if (recovery) @@ -282,7 +301,7 @@ void CharacterController::refreshHitRecoilAnims() } // Cancel upper body animations - if (mHitState == CharState_KnockDown || mHitState == CharState_KnockOut) + if (isKnockedOut() || isKnockedDown()) { if (mUpperBodyState > UpperCharState_WeapEquiped) { @@ -307,9 +326,9 @@ void CharacterController::refreshHitRecoilAnims() mPtr.getClass().getCreatureStats(mPtr).setBlock(false); mHitState = CharState_None; } - else if (mHitState == CharState_KnockOut && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0) + else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0) { - mHitState = CharState_KnockDown; + mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0); } @@ -680,16 +699,15 @@ void CharacterController::playRandomDeath(float startpoint) MWBase::Environment::get().getWorld()->useDeathCamera(); } - bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); - if(isSwimming && mAnimation->hasAnimation("swimdeathknockdown") && mHitState == CharState_KnockDown) + if(mHitState == CharState_SwimKnockDown && mAnimation->hasAnimation("swimdeathknockdown")) { mDeathState = CharState_SwimDeathKnockDown; } - else if(isSwimming && mAnimation->hasAnimation("swimdeathknockout") && mHitState == CharState_KnockOut) + else if(mHitState == CharState_SwimKnockOut && mAnimation->hasAnimation("swimdeathknockout")) { mDeathState = CharState_SwimDeathKnockOut; } - else if(isSwimming && mAnimation->hasAnimation("swimdeath")) + else if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath")) { mDeathState = CharState_SwimDeath; } @@ -1138,8 +1156,8 @@ bool CharacterController::updateWeaponState() bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell && mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; - if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut - && mHitState != CharState_Hit) + if(weaptype != mWeaponType && !isKnockedOut() && + !isKnockedDown() && mHitState != CharState_Hit) { forcestateupdate = true; @@ -1372,13 +1390,13 @@ bool CharacterController::updateWeaponState() } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); - if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) mAttackStrength = complete; } else { animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); - if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) { float attackStrength = complete; if (!mPtr.getClass().isNpc()) @@ -1416,7 +1434,7 @@ bool CharacterController::updateWeaponState() complete = 0.f; mUpperBodyState = UpperCharState_MaxAttackToMinHit; } - else if (mHitState == CharState_KnockDown) + else if (isKnockedDown()) { if (mUpperBodyState > UpperCharState_WeapEquiped) mUpperBodyState = UpperCharState_WeapEquiped; @@ -1900,7 +1918,7 @@ void CharacterController::update(float duration) if (!mSkipAnim) { - if(mHitState != CharState_KnockDown && mHitState != CharState_KnockOut) + if(!isKnockedDown() && !isKnockedOut()) { if (rot != osg::Vec3f()) world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true); @@ -2237,9 +2255,16 @@ bool CharacterController::isReadyToBlock() const return updateCarriedLeftVisible(mWeaponType); } +bool CharacterController::isKnockedDown() const +{ + return mHitState == CharState_KnockDown || + mHitState == CharState_SwimKnockDown; +} + bool CharacterController::isKnockedOut() const { - return mHitState == CharState_KnockOut; + return mHitState == CharState_KnockOut || + mHitState == CharState_SwimKnockOut; } bool CharacterController::isAttackingOrSpell() const diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cc057e50d..3944c0278 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -105,6 +105,8 @@ enum CharacterState { CharState_Hit, CharState_KnockDown, CharState_KnockOut, + CharState_SwimKnockDown, + CharState_SwimKnockOut, CharState_Block }; @@ -267,6 +269,7 @@ public: bool isAttackPrepairing() const; bool isReadyToBlock() const; + bool isKnockedDown() const; bool isKnockedOut() const; bool isSneaking() const; bool isRunning() const; From 1c6cfad3cc28354774def881e3afb518141f90a0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 15:49:42 +0400 Subject: [PATCH 232/521] Implement SwimHit animation --- apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++++++++++---- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 02da5ea56..adcd0ad68 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -283,13 +283,23 @@ void CharacterController::refreshHitRecoilAnims() } else if (recovery) { - std::string anim = chooseRandomGroup("hit"); - if (mAnimation->hasAnimation(anim)) + std::string anim = isSwimming ? chooseRandomGroup("swimhit") : chooseRandomGroup("hit"); + if (isSwimming && mAnimation->hasAnimation(anim)) { - mHitState = CharState_Hit; + mHitState = CharState_SwimHit; mCurrentHit = anim; mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); } + else + { + anim = chooseRandomGroup("hit"); + if (mAnimation->hasAnimation(anim)) + { + mHitState = CharState_Hit; + mCurrentHit = anim; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0); + } + } } else if (block && mAnimation->hasAnimation("shield")) { @@ -1157,7 +1167,7 @@ bool CharacterController::updateWeaponState() mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; if(weaptype != mWeaponType && !isKnockedOut() && - !isKnockedDown() && mHitState != CharState_Hit) + !isKnockedDown() && !isRecovery()) { forcestateupdate = true; @@ -2267,6 +2277,12 @@ bool CharacterController::isKnockedOut() const mHitState == CharState_SwimKnockOut; } +bool CharacterController::isRecovery() const +{ + return mHitState == CharState_Hit || + mHitState == CharState_SwimHit; +} + bool CharacterController::isAttackingOrSpell() const { return mUpperBodyState != UpperCharState_Nothing && diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3944c0278..b6dc96776 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -103,6 +103,7 @@ enum CharacterState { CharState_DeathKnockOut, CharState_Hit, + CharState_SwimHit, CharState_KnockDown, CharState_KnockOut, CharState_SwimKnockDown, @@ -271,6 +272,7 @@ public: bool isReadyToBlock() const; bool isKnockedDown() const; bool isKnockedOut() const; + bool isRecovery() const; bool isSneaking() const; bool isRunning() const; bool isAttackingOrSpell() const; From bcad431cc52be0185f0238b8b0f9071b9ab5f04c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 22 Sep 2017 16:07:00 +0400 Subject: [PATCH 233/521] Implement SwimTurnLeft/Right animations --- apps/openmw/mwmechanics/character.cpp | 24 +++++++++++++++++------- apps/openmw/mwmechanics/character.hpp | 3 +++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index adcd0ad68..0e53f77df 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -186,6 +186,8 @@ static const StateInfo sMovementList[] = { { CharState_TurnLeft, "turnleft" }, { CharState_TurnRight, "turnright" }, + { CharState_SwimTurnLeft, "swimturnleft" }, + { CharState_SwimTurnRight, "swimturnright" }, }; static const StateInfo *sMovementListEnd = &sMovementList[sizeof(sMovementList)/sizeof(sMovementList[0])]; @@ -564,7 +566,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update), // the idle animation should be displayed if ((mUpperBodyState != UpperCharState_Nothing - || (mMovementState != CharState_None && mMovementState != CharState_TurnLeft && mMovementState != CharState_TurnRight) + || (mMovementState != CharState_None && !isTurning()) || mHitState != CharState_None) && !mPtr.getClass().isBipedal(mPtr)) idle = CharState_None; @@ -1875,22 +1877,22 @@ void CharacterController::update(float duration) else if(rot.z() != 0.0f && !inwater && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) - movestate = CharState_TurnRight; + movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; else if(rot.z() < 0.0f) - movestate = CharState_TurnLeft; + movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; } } mTurnAnimationThreshold -= duration; - if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) + if (isTurning()) mTurnAnimationThreshold = 0.05f; - else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) + else if (movestate == CharState_None && isTurning() && mTurnAnimationThreshold > 0) { movestate = mMovementState; } - if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight) + if(!isTurning()) clearAnimQueue(); if(mAnimQueue.empty() || inwater || sneak) @@ -1915,7 +1917,7 @@ void CharacterController::update(float duration) if (inJump) mMovementAnimationControlled = false; - if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight) + if (isTurning()) { if (duration > 0) mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast(osg::PI))); @@ -2277,6 +2279,14 @@ bool CharacterController::isKnockedOut() const mHitState == CharState_SwimKnockOut; } +bool CharacterController::isTurning() const +{ + return mMovementState == CharState_TurnLeft || + mMovementState == CharState_TurnRight || + mMovementState == CharState_SwimTurnLeft || + mMovementState == CharState_SwimTurnRight; +} + bool CharacterController::isRecovery() const { return mHitState == CharState_Hit || diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b6dc96776..af90c18b8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -88,6 +88,8 @@ enum CharacterState { CharState_TurnLeft, CharState_TurnRight, + CharState_SwimTurnLeft, + CharState_SwimTurnRight, CharState_Jump, @@ -275,6 +277,7 @@ public: bool isRecovery() const; bool isSneaking() const; bool isRunning() const; + bool isTurning() const; bool isAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell); From f274bc84cc16fd3f7e8519421a3807751c6b8a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:03:09 +0200 Subject: [PATCH 234/521] fix depth computation in water shader --- files/shaders/water_fragment.glsl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index bb56e95c6..88ca33335 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPPRESS_DEPTH = 150; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float REFLECTION_BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -76,7 +76,7 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float transformDepth(float depth) // helper for transforming water depth +float linearizeDepth(float depth) // helper for transforming water depth { float z_n = 2.0 * depth - 1.0; depth = 2.0 * near * far / (far + near - z_n * (far - near)); @@ -157,12 +157,11 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); #if REFRACTION - float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); + float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); + float shore = clamp(realWaterDepth / (REFLECTION_BUMP_SUPPRESS_DEPTH * (far - near)),0,1); #else float shore = 1.0; #endif - // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; @@ -181,8 +180,7 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); - float waterDepth = refractionDepth - depthPassthrough; + float waterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); if (cameraPos.z > 0.0) refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); @@ -200,5 +198,5 @@ void main(void) gl_FragData[0].w = 1.0; #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endif +#endi } From 28f58d5a3251c8ab21792674979d24ee64d601d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:06:03 +0200 Subject: [PATCH 235/521] add deleted letter in macro --- files/shaders/water_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 88ca33335..db319ac70 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -198,5 +198,5 @@ void main(void) gl_FragData[0].w = 1.0; #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endi +#endif } From 9dececcbd25ddcd67394cd0b1f59bc138c18a178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:10:05 +0200 Subject: [PATCH 236/521] rename a constant in water shader --- files/shaders/water_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index db319ac70..1e3a1e17b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -158,7 +158,7 @@ void main(void) #if REFRACTION float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / (REFLECTION_BUMP_SUPPRESS_DEPTH * (far - near)),0,1); + float shore = clamp(realWaterDepth / (BUMP_SUPPRESS_DEPTH * (far - near)),0,1); #else float shore = 1.0; #endif From 30a213a9b3bccfcfad3e50b5eb96ecb50c6e8d70 Mon Sep 17 00:00:00 2001 From: Date: Fri, 22 Sep 2017 21:08:25 -0500 Subject: [PATCH 237/521] updates for nifstream optimization including fixing the non-x86 path for little endian reads --- components/nif/nifstream.hpp | 84 ++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 4d7e39ecb..290800042 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -14,6 +14,8 @@ #include #include +#include + #include "niftypes.hpp" namespace Nif @@ -21,49 +23,62 @@ namespace Nif class NIFFile; -template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) +/* + readLittleEndianBufferOfType: This template should only be used with non POD data types +*/ +template inline void readLittleEndianBufferOfType(Files::IStreamPtr &pIStream, T* dest) { #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) pIStream->read((char*)dest, numInstances * sizeof(T)); #else - char buffer[numInstances * sizeof(T)]; - pIStream->read((char*)buffer, numInstances * sizeof(T)); + uint8_t* destByteBuffer = (uint8_t*)dest; + pIStream->read((char*)dest, numInstances * sizeof(T)); /* Due to the loop iterations being known at compile time, this nested loop will most likely be unrolled + For example, for 2 instances of a 4 byte data type, you should get the below result */ + union { + IntegerT i; + T t; + } u; for (uint32_t i = 0; i < numInstances; i++) { - dest[i] = 0; + u = { 0 }; for (uint32_t byte = 0; byte < sizeof(T); byte++) - dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + u.i |= (((IntegerT)destByteBuffer[i * sizeof(T) + byte]) << (byte * 8)); + dest[i] = u.t; } #endif } -template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) +/* + readLittleEndianDynamicBufferOfType: This template should only be used with non POD data types +*/ +template inline void readLittleEndianDynamicBufferOfType(Files::IStreamPtr &pIStream, T* dest, uint32_t numInstances) { #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) pIStream->read((char*)dest, numInstances * sizeof(T)); #else - char buffer[numInstances * sizeof(T)]; - pIStream->read((char*)buffer, numInstances * sizeof(T)); - /* - Due to the loop iterations being known at compile time, - this nested loop will most likely be unrolled - */ + uint8_t* destByteBuffer = (uint8_t*)dest; + pIStream->read((char*)dest, numInstances * sizeof(T)); + union { + IntegerT i; + T t; + } u; for (uint32_t i = 0; i < numInstances; i++) { - dest[i] = 0; + u.i = 0; for (uint32_t byte = 0; byte < sizeof(T); byte++) - dest[i] |= ((T)buffer[i * sizeof(T) + byte]) << (byte * 8); + u.i |= ((IntegerT)destByteBuffer[i * sizeof(T) + byte]) << (byte * 8); + dest[i] = u.t; } #endif } -template type inline readLittleEndianType(Files::IStreamPtr &pIStream) +template type inline readLittleEndianType(Files::IStreamPtr &pIStream) { type val; - readLittleEndianBufferOfType<1,type>(pIStream, (type*)&val); + readLittleEndianBufferOfType<1,type,IntegerT>(pIStream, (type*)&val); return val; } @@ -82,52 +97,52 @@ public: char getChar() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } short getShort() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } unsigned short getUShort() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } int getInt() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } unsigned int getUInt() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } float getFloat() { - return readLittleEndianType(inp); + return readLittleEndianType(inp); } osg::Vec2f getVector2() { osg::Vec2f vec; - readLittleEndianBufferOfType<2,float>(inp, (float*)&vec._v[0]); + readLittleEndianBufferOfType<2,float,uint32_t>(inp, (float*)&vec._v[0]); return vec; } osg::Vec3f getVector3() { osg::Vec3f vec; - readLittleEndianBufferOfType<3, float>(inp, (float*)&vec._v[0]); + readLittleEndianBufferOfType<3, float,uint32_t>(inp, (float*)&vec._v[0]); return vec; } osg::Vec4f getVector4() { osg::Vec4f vec; - readLittleEndianBufferOfType<4, float>(inp, (float*)&vec._v[0]); + readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&vec._v[0]); return vec; } Matrix3 getMatrix3() { Matrix3 mat; - readLittleEndianBufferOfType<9, float>(inp, (float*)&mat.mValues); + readLittleEndianBufferOfType<9, float,uint32_t>(inp, (float*)&mat.mValues); return mat; } osg::Quat getQuaternion() { float f[4]; - readLittleEndianBufferOfType<4, float>(inp, (float*)&f); + readLittleEndianBufferOfType<4, float,uint32_t>(inp, (float*)&f); osg::Quat quat; quat.w() = f[0]; quat.x() = f[1]; @@ -153,7 +168,7 @@ public: } ///Read in a string of the length specified in the file std::string getString() { - size_t size = readLittleEndianType(inp); + size_t size = readLittleEndianType(inp); return getString(size); } ///This is special since the version string doesn't start with a number, and ends with "\n" @@ -165,23 +180,26 @@ public: void getUShorts(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getFloats(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); } void getVector2s(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + /* The packed storage of each Vec2f is 2 floats exactly */ + readLittleEndianDynamicBufferOfType(inp,(float*) &vec.front(), size*2); } void getVector3s(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + /* The packed storage of each Vec3f is 3 floats exactly */ + readLittleEndianDynamicBufferOfType(inp, (float*) &vec.front(), size*3); } void getVector4s(std::vector &vec, size_t size) { vec.resize(size); - readLittleEndianDynamicBufferOfType(inp, &vec.front(), size); + /* The packed storage of each Vec4f is 4 floats exactly */ + readLittleEndianDynamicBufferOfType(inp, (float*) &vec.front(), size*4); } void getQuaternions(std::vector &quat, size_t size) { quat.resize(size); From 4921e7f5c1e2be8c4820bf8228ce83851ceccb16 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 21:29:40 -0400 Subject: [PATCH 238/521] Get rid of reinterpret cast. --- apps/opencs/model/world/columnimp.cpp | 129 +++++++++++++------------- apps/opencs/model/world/columnimp.hpp | 12 +++ apps/opencs/model/world/commands.cpp | 24 ++--- apps/opencs/model/world/commands.hpp | 6 +- 4 files changed, 93 insertions(+), 78 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 6a19df0d5..18da81b53 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -1,6 +1,7 @@ #include "columnimp.hpp" #include +#include namespace CSMWorld { @@ -86,33 +87,32 @@ namespace CSMWorld const int Size = Land::LAND_GLOBAL_MAP_LOD_SIZE; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_WNAM)) { - // Note: original data is signed - const char* rawData = reinterpret_cast(&land.mWnam[0]); - return QByteArray(rawData, Size); - } - else - { - // Return a blank array - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.mWnam[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandMapLodColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_GLOBAL_MAP_LOD_SIZE) + if (values.size() != Land::LAND_GLOBAL_MAP_LOD_SIZE) throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_WNAM); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.mWnam[i] = rawData[i]; + copy.mWnam[i] = values[i]; } record.setModified(copy); @@ -134,33 +134,32 @@ namespace CSMWorld const int Size = Land::LAND_NUM_VERTS * 3; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VNML)) { - // Note: original data is signed - const char* rawData = reinterpret_cast(&land.getLandData()->mNormals[0]); - return QByteArray(rawData, Size); - } - else - { - // Return a blank array - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mNormals[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandNormalsColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const signed char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * 3) + if (values.size() != Land::LAND_NUM_VERTS * 3) throw std::runtime_error("invalid land normals data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VNML); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mNormals[i] = rawData[i]; + copy.getLandData()->mNormals[i] = values[i]; } record.setModified(copy); @@ -179,36 +178,35 @@ namespace CSMWorld QVariant LandHeightsColumn::get(const Record& record) const { - const int Size = Land::LAND_NUM_VERTS * sizeof(float); + const int Size = Land::LAND_NUM_VERTS; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VHGT)) { - // Note: original data is float - const char* rawData = reinterpret_cast(&land.getLandData()->mHeights[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mHeights[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandHeightsColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const float* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * sizeof(float)) + if (values.size() != Land::LAND_NUM_VERTS) throw std::runtime_error("invalid land heights data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VHGT); - int count = array.count() / sizeof(float); - for (int i = 0; i < count; ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mHeights[i] = rawData[i]; + copy.getLandData()->mHeights[i] = values[i]; } record.setModified(copy); @@ -230,32 +228,32 @@ namespace CSMWorld const int Size = Land::LAND_NUM_VERTS * 3; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VCLR)) { - // Note: original data is unsigned char - const char* rawData = reinterpret_cast(&land.getLandData()->mColours[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mColours[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandColoursColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const unsigned char* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_VERTS * 3) + if (values.size() != Land::LAND_NUM_VERTS * 3) throw std::runtime_error("invalid land colours data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VCLR); - for (int i = 0; i < array.count(); ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mColours[i] = rawData[i]; + copy.getLandData()->mColours[i] = values[i]; } record.setModified(copy); @@ -274,36 +272,35 @@ namespace CSMWorld QVariant LandTexturesColumn::get(const Record& record) const { - const int Size = Land::LAND_NUM_TEXTURES * sizeof(uint16_t); + const int Size = Land::LAND_NUM_TEXTURES; const Land& land = record.get(); + DataType values(Size, 0); + if (land.isDataLoaded(Land::DATA_VTEX)) { - // Note: original data is uint16_t - const char* rawData = reinterpret_cast(&land.getLandData()->mTextures[0]); - return QByteArray(rawData, Size); - } - else - { - return QByteArray(Size, 0); + for (int i = 0; i < Size; ++i) + values[i] = land.getLandData()->mTextures[i]; } + + QVariant variant; + variant.setValue(values); + return variant; } void LandTexturesColumn::set(Record& record, const QVariant& data) { - QByteArray array = data.toByteArray(); - const uint16_t* rawData = reinterpret_cast(array.data()); + DataType values = data.value(); - if (array.count() != Land::LAND_NUM_TEXTURES * sizeof(uint16_t)) + if (values.size() != Land::LAND_NUM_TEXTURES) throw std::runtime_error("invalid land textures data"); Land copy = record.get(); copy.setDataLoaded(Land::DATA_VTEX); - int count = array.count() / sizeof(uint16_t); - for (int i = 0; i < count; ++i) + for (int i = 0; i < values.size(); ++i) { - copy.getLandData()->mTextures[i] = rawData[i]; + copy.getLandData()->mTextures[i] = values[i]; } record.setModified(copy); diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 025b064c6..d653ddece 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2,10 +2,12 @@ #define CSM_WOLRD_COLUMNIMP_H #include +#include #include #include #include +#include #include #include @@ -2470,6 +2472,8 @@ namespace CSMWorld struct LandMapLodColumn : public Column { + using DataType = QVector; + LandMapLodColumn(); QVariant get(const Record& record) const override; @@ -2479,6 +2483,8 @@ namespace CSMWorld struct LandNormalsColumn : public Column { + using DataType = QVector; + LandNormalsColumn(); QVariant get(const Record& record) const override; @@ -2488,6 +2494,8 @@ namespace CSMWorld struct LandHeightsColumn : public Column { + using DataType = QVector; + LandHeightsColumn(); QVariant get(const Record& record) const override; @@ -2497,6 +2505,8 @@ namespace CSMWorld struct LandColoursColumn : public Column { + using DataType = QVector; + LandColoursColumn(); QVariant get(const Record& record) const override; @@ -2506,6 +2516,8 @@ namespace CSMWorld struct LandTexturesColumn : public Column { + using DataType = QVector; + LandTexturesColumn(); QVariant get(const Record& record) const override; diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b654eb00d..79900c6c4 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -58,23 +58,21 @@ void CSMWorld::ImportLandTexturesCommand::redo() // Original data int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).toByteArray(); - const uint16_t* textureData = reinterpret_cast(mOld.data()); + mOld = mLands.data(mLands.getModelIndex(getOriginId(), textureColumn)).value(); // Need to make a copy so the old values can be looked up - QByteArray newTextureByteArray(mOld.data(), mOld.size()); - uint16_t* newTextureData = reinterpret_cast(newTextureByteArray.data()); + DataType copy(mOld); // Perform touch/copy/etc... onRedo(); // Find all indices used std::unordered_set texIndices; - for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) + for (int i = 0; i < mOld.size(); ++i) { // All indices are offset by 1 for a default texture - if (textureData[i] > 0) - texIndices.insert(textureData[i] - 1); + if (mOld[i] > 0) + texIndices.insert(mOld[i] - 1); } std::vector oldTextures; @@ -97,8 +95,8 @@ void CSMWorld::ImportLandTexturesCommand::redo() for (int i = 0; i < Land::LAND_NUM_TEXTURES; ++i) { // All indices are offset by 1 for a default texture - if (textureData[i] == oldIndex + 1) - newTextureData[i] = newIndex + 1; + if (mOld[i] == oldIndex + 1) + copy[i] = newIndex + 1; } } } @@ -107,14 +105,18 @@ void CSMWorld::ImportLandTexturesCommand::redo() int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mOldState = mLands.data(mLands.getModelIndex(getDestinationId(), stateColumn)).toInt(); - mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), newTextureByteArray); + QVariant variant; + variant.setValue(copy); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant); } void CSMWorld::ImportLandTexturesCommand::undo() { // Restore to previous int textureColumn = mLands.findColumnIndex(Columns::ColumnId_LandTexturesIndex); - mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), mOld); + QVariant variant; + variant.setValue(mOld); + mLands.setData(mLands.getModelIndex(getDestinationId(), textureColumn), variant); int stateColumn = mLands.findColumnIndex(Columns::ColumnId_Modification); mLands.setData(mLands.getModelIndex(getDestinationId(), stateColumn), mOldState); diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index aab0c5410..0f9d3591c 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,12 +3,14 @@ #include "record.hpp" +#include #include #include #include #include #include +#include #include #include @@ -55,6 +57,8 @@ namespace CSMWorld protected: + using DataType = QVector; + virtual const std::string& getOriginId() const = 0; virtual const std::string& getDestinationId() const = 0; @@ -63,7 +67,7 @@ namespace CSMWorld IdTable& mLands; IdTable& mLtexs; - QByteArray mOld; + DataType mOld; int mOldState; std::vector mCreatedTextures; }; From 054e6a780e2c8fa4bbf1863751020ab036e5ad96 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 22:43:45 -0400 Subject: [PATCH 239/521] Use map for texture lookup. --- apps/opencs/model/world/idtable.cpp | 39 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index b41eea8f8..2c066ff6c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -340,6 +341,15 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import { ImportResults results; + // Map existing textures to ids + std::map reverseLookupMap; + for (int i = 0; i < idCollection()->getSize(); ++i) + { + auto& record = static_cast&>(idCollection()->getRecord(i)); + if (record.isModified()) + reverseLookupMap.emplace(record.get().mTexture, idCollection()->getId(i)); + } + for (const std::string& id : ids) { int plugin, index; @@ -354,8 +364,16 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import continue; } - // Try a direct mapping to the current plugin first. Otherwise iterate until one is found. - // Iteration is deterministic to avoid duplicates. + // Look for a pre-existing record + auto& record = static_cast&>(idCollection()->getRecord(oldRow)); + auto searchIt = reverseLookupMap.find(record.get().mTexture); + if (searchIt != reverseLookupMap.end()) + { + results.recordMapping.push_back(std::make_pair(id, searchIt->second)); + continue; + } + + // Iterate until an unused index or found, or the index has completely wrapped around. int startIndex = index; do { std::string newId = LandTexture::createUniqueRecordId(0, index); @@ -370,21 +388,8 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import break; } - // Id is taken, check if same handle and texture. Note that mId is the handle. - const LandTexture& oldLtex = dynamic_cast&>(idCollection()->getRecord(oldRow)).get(); - const LandTexture& newLtex = dynamic_cast&>(idCollection()->getRecord(newRow)).get(); - if (oldLtex.mId == newLtex.mId && oldLtex.mTexture == newLtex.mTexture) - { - // It's a match - results.recordMapping.push_back(std::make_pair(id, newId)); - break; - } - - // Determine next index. Spread out the indices to reduce conflicts. - size_t MaxIndex = std::numeric_limits::max() - 1; - size_t Prime = (1 << 13) - 1; // A mersenne prime - - index = (index + Prime) % MaxIndex; + const size_t MaxIndex = std::numeric_limits::max() - 1; + index = (index + 1) % MaxIndex; } while (index != startIndex); } From 3981f79d38af642f423b4adb5666b98a596a24f9 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 22:59:50 -0400 Subject: [PATCH 240/521] Change flag for base land textures --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2c066ff6c..54d65ac3f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -332,7 +332,7 @@ Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) cons Qt::ItemFlags flags = IdTable::flags(index); if (!idCollection()->getRecord(index.row()).isModified()) - flags &= ~Qt::ItemIsEditable; + flags &= ~Qt::ItemIsEnabled; return flags; } From 1fe1ec63c43af800d3988081b802e690ad8d0a34 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 22 Sep 2017 23:33:50 -0400 Subject: [PATCH 241/521] Fix Qt4 build --- apps/opencs/model/world/columnimp.hpp | 7 +++++++ apps/opencs/model/world/commands.hpp | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index d653ddece..e36e386c9 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2537,4 +2537,11 @@ namespace CSMWorld }; } +// This is required to access the type as a QVariant. +Q_DECLARE_METATYPE(CSMWorld::LandMapLodColumn::DataType) +//Q_DECLARE_METATYPE(CSMWorld::LandNormalsColumn::DataType) // Same as LandMapLodColumn::DataType +Q_DECLARE_METATYPE(CSMWorld::LandHeightsColumn::DataType) +Q_DECLARE_METATYPE(CSMWorld::LandColoursColumn::DataType) +Q_DECLARE_METATYPE(CSMWorld::LandTexturesColumn::DataType) + #endif diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 0f9d3591c..be86dd508 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,17 +3,16 @@ #include "record.hpp" -#include #include #include #include #include #include -#include #include #include +#include "columnimp.hpp" #include "universalid.hpp" #include "nestedtablewrapper.hpp" @@ -57,7 +56,7 @@ namespace CSMWorld protected: - using DataType = QVector; + using DataType = LandTexturesColumn::DataType; virtual const std::string& getOriginId() const = 0; virtual const std::string& getDestinationId() const = 0; From a57f6ac2af8fdb759b9f93c15bc451969fac598a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 23 Sep 2017 08:25:58 +0400 Subject: [PATCH 242/521] Fix a typo in attack animation name --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0e53f77df..6e1e075fb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -925,7 +925,7 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop); else if (groupname == "attack2" || groupname == "swimattack2") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash); - else if (groupname == "attack3" || groupname == "swimattack1") + else if (groupname == "attack3" || groupname == "swimattack3") mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust); else mPtr.getClass().hit(mPtr, mAttackStrength); From 825de71b294867a177cfd44543da10b0f4d45fa2 Mon Sep 17 00:00:00 2001 From: Date: Sat, 23 Sep 2017 11:10:05 -0500 Subject: [PATCH 243/521] removed an iostream include used for debug prints from nifstream.hpp --- components/nif/nifstream.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 290800042..d00069be7 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -14,8 +14,6 @@ #include #include -#include - #include "niftypes.hpp" namespace Nif From b5f5268ff347a6730cac4526829c12ef3a2c44ba Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 23 Sep 2017 18:54:17 +0200 Subject: [PATCH 244/521] Clean up faraway projectiles --- apps/openmw/mwworld/projectilemanager.cpp | 62 ++++++++++++++++++++--- apps/openmw/mwworld/projectilemanager.hpp | 5 ++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 6e716cb54..ede8c34c4 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -149,6 +149,7 @@ namespace MWWorld , mResourceSystem(resourceSystem) , mRendering(rendering) , mPhysics(physics) + , mCleanupTimer(0.0f) { } @@ -326,10 +327,49 @@ namespace MWWorld void ProjectileManager::update(float dt) { + periodicCleanup(dt); moveProjectiles(dt); moveMagicBolts(dt); } + void ProjectileManager::periodicCleanup(float dt) + { + mCleanupTimer -= dt; + if (mCleanupTimer <= 0.0f) + { + mCleanupTimer = 2.0f; + + auto isCleanable = [](const ProjectileManager::State& state) -> bool + { + const float farawayThreshold = 72000.0f; + osg::Vec3 playerPos = MWMechanics::getPlayer().getRefData().getPosition().asVec3(); + return (state.mNode->getPosition() - playerPos).length2() >= farawayThreshold*farawayThreshold; + }; + + for (std::vector::iterator it = mProjectiles.begin(); it != mProjectiles.end();) + { + if (isCleanable(*it)) + { + cleanupProjectile(*it); + it = mProjectiles.erase(it); + } + else + ++it; + } + + for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();) + { + if (isCleanable(*it)) + { + cleanupMagicBolt(*it); + it = mMagicBolts.erase(it); + } + else + ++it; + } + } + } + void ProjectileManager::moveMagicBolts(float duration) { for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();) @@ -468,20 +508,30 @@ namespace MWWorld } } + void ProjectileManager::cleanupProjectile(ProjectileManager::ProjectileState& state) + { + mParent->removeChild(state.mNode); + } + + void ProjectileManager::cleanupMagicBolt(ProjectileManager::MagicBoltState& state) + { + mParent->removeChild(state.mNode); + for (size_t soundIter = 0; soundIter != state.mSounds.size(); soundIter++) + { + MWBase::Environment::get().getSoundManager()->stopSound(state.mSounds.at(soundIter)); + } + } + void ProjectileManager::clear() { for (std::vector::iterator it = mProjectiles.begin(); it != mProjectiles.end(); ++it) { - mParent->removeChild(it->mNode); + cleanupProjectile(*it); } mProjectiles.clear(); for (std::vector::iterator it = mMagicBolts.begin(); it != mMagicBolts.end(); ++it) { - mParent->removeChild(it->mNode); - for (size_t soundIter = 0; soundIter != it->mSounds.size(); soundIter++) - { - MWBase::Environment::get().getSoundManager()->stopSound(it->mSounds.at(soundIter)); - } + cleanupMagicBolt(*it); } mMagicBolts.clear(); } diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index 1ef72a048..0dfbf6080 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -68,6 +68,7 @@ namespace MWWorld Resource::ResourceSystem* mResourceSystem; MWRender::RenderingManager* mRendering; MWPhysics::PhysicsSystem* mPhysics; + float mCleanupTimer; struct State { @@ -116,6 +117,10 @@ namespace MWWorld std::vector mMagicBolts; std::vector mProjectiles; + void cleanupProjectile(ProjectileState& state); + void cleanupMagicBolt(MagicBoltState& state); + void periodicCleanup(float dt); + void moveProjectiles(float dt); void moveMagicBolts(float dt); From 91adfc9fc0d91afb373b243ee18f81458356de8d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 23 Sep 2017 20:59:06 +0400 Subject: [PATCH 245/521] AiWander: reset spawn position, if an actor was moved to another cell (bug #4010) --- apps/openmw/mwmechanics/aiwander.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b44b187ad..7f412b4d2 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -200,6 +200,7 @@ namespace MWMechanics stopWalking(actor, storage); currentCell = actor.getCell(); storage.mPopulateAvailableNodes = true; + mStoredInitialActorPosition = false; } mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); From 9b04a7c1e66c5f090f78c3ad0c4ad44bc46d9e4b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Sep 2017 16:26:41 +0400 Subject: [PATCH 246/521] Fix idle animations playing --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6e1e075fb..ec65255bc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1892,7 +1892,7 @@ void CharacterController::update(float duration) movestate = mMovementState; } - if(!isTurning()) + if(movestate != CharState_None && !isTurning()) clearAnimQueue(); if(mAnimQueue.empty() || inwater || sneak) From 7d703a13a3024e2428928fb34f246cc3838d4fa7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 24 Sep 2017 16:28:05 +0400 Subject: [PATCH 247/521] Fix a crash in the World::isUnderwater() if the cell is empty --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 40bc13c94..2a25d5bbc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2123,6 +2123,9 @@ namespace MWWorld bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const { + if (!cell) + return false; + if (!(cell->getCell()->hasWater())) { return false; } From b22fedf4ae922a0b3dab3c9f7d7b3374a921fdc8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:13:22 +0200 Subject: [PATCH 248/521] Check 'sYes' in addition to 'sOk' for message box's default keyfocus --- apps/openmw/mwgui/messagebox.cpp | 30 +++++++++++------------------- apps/openmw/mwgui/messagebox.hpp | 1 - 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ab43df0f1..f9c445d36 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -228,8 +228,7 @@ namespace MWGui int buttonHeight = 0; MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - std::vector::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) + for(std::vector::const_iterator it = buttons.begin(); it != buttons.end(); ++it) { MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, @@ -289,8 +288,7 @@ namespace MWGui MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { buttonCord.left = left; buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding; @@ -319,8 +317,7 @@ namespace MWGui int top = textPadding + textSize.height + textButtonPadding; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; @@ -354,25 +351,20 @@ namespace MWGui } // Set key focus to "Ok" button - std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + std::vector keywords { "sOk", "sYes" }; + for(std::vector::const_iterator button = mButtons.begin(); button != mButtons.end(); ++button) { - if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok)) + for (const std::string& keyword : keywords) { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button); - (*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed); - break; + if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), (*button)->getCaption())) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button); + return; + } } } } - void InteractiveMessageBox::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) - { - if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter || _key == MyGUI::KeyCode::Space) - buttonActivated(_sender); - } - void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) { buttonActivated (pressed); diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index b4121fed3..38e6590b7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -81,7 +81,6 @@ namespace MWGui private: void buttonActivated (MyGUI::Widget* _widget); - void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char); MessageBoxManager& mMessageBoxManager; MyGUI::EditBox* mMessageWidget; From e7ad01297753e0184bd34c817a4ee79552560052 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:34:34 +0200 Subject: [PATCH 249/521] Pass repeat key events to the GUI For example, one can scroll to the last element in a list by holding down the 'Down Arrow' key. --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ components/sdlutil/sdlinputwrapper.cpp | 11 ++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e4fa8fc2b..cc41b3831 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -679,6 +679,9 @@ namespace MWInput bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); } + if (arg.repeat) + return; + if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); mJoystickLastUsed = false; diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index a76de00d1..634c4884f 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -85,14 +85,11 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v mMouseListener->mouseReleased(evt.button, evt.button.button); break; case SDL_KEYDOWN: - if (!evt.key.repeat) - { - mKeyboardListener->keyPressed(evt.key); + mKeyboardListener->keyPressed(evt.key); - if (!isModifierHeld(KMOD_ALT) && evt.key.keysym.sym >= SDLK_F1 && evt.key.keysym.sym <= SDLK_F12) - { - mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F1 + (evt.key.keysym.sym - SDLK_F1)); - } + if (!isModifierHeld(KMOD_ALT) && evt.key.keysym.sym >= SDLK_F1 && evt.key.keysym.sym <= SDLK_F12) + { + mViewer->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_F1 + (evt.key.keysym.sym - SDLK_F1)); } break; From c11fe6788fff68a73444c60409d6551f13678995 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:52:39 +0200 Subject: [PATCH 250/521] Add basic keyboard navigation for the GUI (Shift)Tab cycles, arrow keys move to the next button in that direction, Enter/Space accepts. Note: Unless MyGUI is hacked to bits, clicking on an empty space will annoyingly reset the key focus. Not sure how to deal with that yet. The visual highlight for selected buttons requires MyGUI commit 632d007429d0bf0c7d7f6c5db4a08353a63dd839 or later to appear (to be released in 3.2.3). --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/windowmanager.hpp | 4 + apps/openmw/mwgui/keyboardnavigation.cpp | 140 +++++++++++++++++++++++ apps/openmw/mwgui/keyboardnavigation.hpp | 27 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 5 + apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- files/mygui/openmw_button.skin.xml | 1 + 8 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 apps/openmw/mwgui/keyboardnavigation.cpp create mode 100644 apps/openmw/mwgui/keyboardnavigation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 00ae2fa4a..43952afdb 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -42,7 +42,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen itemchargeview + draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4560ab270..37c3ce0d3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include "../mwgui/mode.hpp" namespace Loading @@ -368,6 +370,8 @@ namespace MWBase virtual void writeFog(MWWorld::CellStore* cell) = 0; virtual const MWGui::TextColours& getTextColours() = 0; + + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text) = 0; }; } diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp new file mode 100644 index 000000000..840a12f1e --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -0,0 +1,140 @@ +#include "keyboardnavigation.hpp" + +#include +#include +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +namespace MWGui +{ + +/// Recursively get all child widgets that accept keyboard input +void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) +{ + MyGUI::EnumeratorWidgetPtr enumerator = parent->getEnumerator(); + while (enumerator.next()) + { + MyGUI::Widget* w = enumerator.current(); + if (!w->getVisible() || !w->getEnabled()) + continue; + if (w->getNeedKeyFocus()) + results.push_back(w); + else + getKeyFocusWidgets(w, results); + } +} + +KeyboardNavigation::KeyboardNavigation() +{ +} + +KeyboardNavigation::~KeyboardNavigation() +{ +} + +bool isButtonFocus() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + return focus->getTypeName().find("Button") != std::string::npos; +} + +enum Direction +{ + D_Left, + D_Up, + D_Right, + D_Down, + D_Next, + D_Prev +}; + +bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) +{ + switch (key.getValue()) + { + case MyGUI::KeyCode::ArrowLeft: + return switchFocus(D_Left, false); + case MyGUI::KeyCode::ArrowRight: + return switchFocus(D_Right, false); + case MyGUI::KeyCode::ArrowUp: + return switchFocus(D_Up, false); + case MyGUI::KeyCode::ArrowDown: + return switchFocus(D_Down, false); + case MyGUI::KeyCode::Tab: + return switchFocus(MyGUI::InputManager::getInstance().isShiftPressed() ? D_Prev : D_Next, true); + case MyGUI::KeyCode::Return: + case MyGUI::KeyCode::NumpadEnter: + case MyGUI::KeyCode::Space: + return accept(); + default: + return false; + } +} + +bool KeyboardNavigation::switchFocus(int direction, bool wrap) +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus) + return false; + + if (!isButtonFocus() && direction != D_Prev && direction != D_Next) + return false; + + MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + while (window->getParent()) + window = window->getParent(); + + MyGUI::VectorWidgetPtr keyFocusList; + getKeyFocusWidgets(window, keyFocusList); + + if (keyFocusList.empty()) + return false; + + MyGUI::VectorWidgetPtr::iterator found = std::find(keyFocusList.begin(), keyFocusList.end(), focus); + if (found == keyFocusList.end()) + return false; + + bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); + + int index = found - keyFocusList.begin(); + index = forward ? (index+1) : (index-1); + if (wrap) + index = (index + keyFocusList.size())%keyFocusList.size(); + else + index = std::min(std::max(0, index), static_cast(keyFocusList.size())-1); + + MyGUI::Widget* next = keyFocusList[index]; + int vertdiff = next->getTop() - focus->getTop(); + int horizdiff = next->getLeft() - focus->getLeft(); + if (direction == D_Right && horizdiff <= 0) + return false; + else if (direction == D_Left && horizdiff >= 0) + return false; + else if (direction == D_Down && vertdiff <= 0) + return false; + else if (direction == D_Up && vertdiff >= 0) + return false; + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]); + return true; +} + +bool KeyboardNavigation::accept() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus) + return false; + //MyGUI::Button* button = focus->castType(false); + //if (button && button->getEnabled()) + if (focus->getTypeName().find("Button") != std::string::npos && focus->getEnabled()) + { + focus->eventMouseButtonClick(focus); + return true; + } + return false; +} + + +} diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp new file mode 100644 index 000000000..86cc67962 --- /dev/null +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_MWGUI_KEYBOARDNAVIGATION_H +#define OPENMW_MWGUI_KEYBOARDNAVIGATION_H + +#include + +namespace MWGui +{ + + class KeyboardNavigation + { + public: + KeyboardNavigation(); + ~KeyboardNavigation(); + + /// @return Was the key handled by this class? + bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + + private: + bool switchFocus(int direction, bool wrap); + + /// Send button press event to focused button + bool accept(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1526949a3..5d7a54735 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -112,6 +112,7 @@ #include "controllers.hpp" #include "jailscreen.hpp" #include "itemchargeview.hpp" +#include "keyboardnavigation.hpp" namespace { @@ -248,6 +249,8 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); + mKeyboardNavigation.reset(new KeyboardNavigation()); + mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); //set up the hardware cursor manager @@ -433,6 +436,8 @@ namespace MWGui WindowManager::~WindowManager() { + mKeyboardNavigation.reset(); + MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); @@ -2202,4 +2207,11 @@ namespace MWGui return mTextColours; } + bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) + { + if (!mKeyboardNavigation->injectKeyPress(key, text)) + return MyGUI::InputManager::getInstance().injectKeyPress(key, text); + else + return true; + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4f06afb7d..3e17046df 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -122,6 +122,7 @@ namespace MWGui class ScreenFader; class DebugWindow; class JailScreen; + class KeyboardNavigation; class WindowManager : public MWBase::WindowManager { @@ -397,6 +398,8 @@ namespace MWGui virtual const MWGui::TextColours& getTextColours(); + virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + private: const MWWorld::ESMStore* mStore; Resource::ResourceSystem* mResourceSystem; @@ -522,6 +525,8 @@ namespace MWGui MWGui::TextColours mTextColours; + std::unique_ptr mKeyboardNavigation; + /** * Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property. * Supported syntax: diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cc41b3831..33f1edb6c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -676,7 +676,7 @@ namespace MWInput { consumed = SDL_IsTextInputActive() && ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable - bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + bool guiFocus = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); setPlayerControlsEnabled(!guiFocus); } if (arg.repeat) diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 5aee8de7a..ac9bf042d 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -71,6 +71,7 @@ + From 1ad14b232fd93d4f96493169830969f42b2fe498 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:57:01 +0200 Subject: [PATCH 251/521] Adjust ImageButton to accept key focus and use the 'highlighted' texture --- components/widgets/imagebutton.cpp | 54 +++++++++++++++++++++++++----- components/widgets/imagebutton.hpp | 11 ++++++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 8e3f8ed69..ab0739c2c 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -5,6 +5,15 @@ namespace Gui { + ImageButton::ImageButton() + : Base() + , mMouseFocus(false) + , mMousePress(false) + , mKeyFocus(false) + { + setNeedKeyFocus(true); + } + void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value) { if (_key == "ImageHighlighted") @@ -24,22 +33,36 @@ namespace Gui } void ImageButton::onMouseSetFocus(Widget* _old) { - setImageTexture(mImageHighlighted); - ImageBox::onMouseSetFocus(_old); + mMouseFocus = true; + updateImage(); + Base::onMouseSetFocus(_old); } void ImageButton::onMouseLostFocus(Widget* _new) { - setImageTexture(mImageNormal); - ImageBox::onMouseLostFocus(_new); + mMouseFocus = false; + updateImage(); + Base::onMouseLostFocus(_new); } void ImageButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) - setImageTexture(mImagePushed); + { + mMousePress = true; + updateImage(); + } + Base::onMouseButtonPressed(_left, _top, _id); + } - ImageBox::onMouseButtonPressed(_left, _top, _id); + void ImageButton::updateImage() + { + if (mMousePress) + setImageTexture(mImagePushed); + else if (mMouseFocus || mKeyFocus) + setImageTexture(mImageHighlighted); + else + setImageTexture(mImageNormal); } MyGUI::IntSize ImageButton::getRequestedSize() @@ -70,8 +93,23 @@ namespace Gui void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) { if (_id == MyGUI::MouseButton::Left) - setImageTexture(mImageHighlighted); + { + mMousePress = false; + updateImage(); + } + + Base::onMouseButtonReleased(_left, _top, _id); + } - ImageBox::onMouseButtonReleased(_left, _top, _id); + void ImageButton::onKeySetFocus(MyGUI::Widget *_old) + { + mKeyFocus = true; + updateImage(); + } + + void ImageButton::onKeyLostFocus(MyGUI::Widget *_new) + { + mKeyFocus = false; + updateImage(); } } diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index a539f15c9..509b1c8c2 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -16,19 +16,30 @@ namespace Gui public: MyGUI::IntSize getRequestedSize(); + ImageButton(); + /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) void setImage(const std::string& image); + private: + void updateImage(); + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onMouseLostFocus(MyGUI::Widget* _new); virtual void onMouseSetFocus(MyGUI::Widget* _old); virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id); virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id); + virtual void onKeySetFocus(MyGUI::Widget* _old); + virtual void onKeyLostFocus(MyGUI::Widget* _new); std::string mImageHighlighted; std::string mImageNormal; std::string mImagePushed; + + bool mMouseFocus; + bool mMousePress; + bool mKeyFocus; }; } From c203a0774a5cabd46919c149b82c3c38895de90b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 16:58:05 +0200 Subject: [PATCH 252/521] Adjust some layouts to take better advantage of keyboard navigation --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +-- apps/openmw/mwgui/confirmationdialog.cpp | 5 ++++ apps/openmw/mwgui/dialogue.cpp | 11 ++++----- apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/mainmenu.cpp | 24 +++++++++++++++---- files/mygui/openmw_confirmation_dialog.layout | 1 + .../openmw_interactive_messagebox.layout | 1 + files/mygui/openmw_savegame_dialog.layout | 1 + files/mygui/openmw_trade_window.layout | 7 +++--- 9 files changed, 39 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index fa5bfbe2f..6da1f7806 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,8 +139,6 @@ namespace MWDialogue // If the dialogue window was already open, keep the existing history bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); - win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -156,6 +154,7 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); + win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); creatureStats.talkedToPlayer(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 33f8dbe3e..f3a06f245 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,6 +3,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { ConfirmationDialog::ConfirmationDialog() : @@ -38,6 +41,8 @@ namespace MWGui mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton); + center(); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2e80301d2..9f59cd443 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -259,9 +259,8 @@ namespace MWGui getWidget(mTopicsList, "TopicsList"); mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); - byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + getWidget(mGoodbyeButton, "ByeButton"); + mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); getWidget(mDispositionBar, "Disposition"); getWidget(mDispositionText,"DispositionText"); @@ -360,6 +359,8 @@ namespace MWGui void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + mGoodbye = false; mEnabled = true; bool sameActor = (mPtr == actor); @@ -528,10 +529,8 @@ namespace MWGui onScrollbarMoved(mScrollBar, 0); } - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); bool goodbyeEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() || mGoodbye; - byeButton->setEnabled(goodbyeEnabled); + mGoodbyeButton->setEnabled(goodbyeEnabled); bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye; mTopicsList->setEnabled(topicsEnabled); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5b5ae5b68..9f0b2245a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -169,6 +169,7 @@ namespace MWGui MyGUI::ScrollBar* mScrollBar; MyGUI::ProgressBar* mDispositionBar; MyGUI::TextBox* mDispositionText; + MyGUI::Button* mGoodbyeButton; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5a435b9cf..265b08fd6 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -56,9 +56,24 @@ namespace MWGui if (visible) updateMenu(); - showBackground( - MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && - MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); + bool isMainMenu = + MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && + MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; + + showBackground(isMainMenu); + + if (visible) + { + if (isMainMenu) + { + if (mButtons["loadgame"]->getVisible()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["loadgame"]); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["newgame"]); + } + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["return"]); + } Layout::setVisible (visible); } @@ -231,7 +246,8 @@ namespace MWGui buttons.push_back("exitgame"); // Create new buttons if needed - for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + std::vector allButtons { "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame"}; + for (std::vector::iterator it = allButtons.begin(); it != allButtons.end(); ++it) { if (mButtons.find(*it) == mButtons.end()) { diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index 39e77cb93..c5eb573a7 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -10,6 +10,7 @@ + diff --git a/files/mygui/openmw_interactive_messagebox.layout b/files/mygui/openmw_interactive_messagebox.layout index 50bc178ed..410426656 100644 --- a/files/mygui/openmw_interactive_messagebox.layout +++ b/files/mygui/openmw_interactive_messagebox.layout @@ -9,6 +9,7 @@ + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index f18218430..a7b7703de 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -46,6 +46,7 @@ + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 6d5dfb89b..f9f24581f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -48,6 +48,10 @@ + + + + @@ -60,9 +64,6 @@ - - - From 5482ad0482cc242069a80df6a3adb21bd38b8600 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 17:03:31 +0200 Subject: [PATCH 253/521] Fix tab completion in console to not cycle key focus --- apps/openmw/mwgui/keyboardnavigation.cpp | 3 +++ files/mygui/openmw_console.layout | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 840a12f1e..ba09ce369 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -82,6 +82,9 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) if (!isButtonFocus() && direction != D_Prev && direction != D_Next) return false; + if ((direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + return false; + MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); while (window->getParent()) window = window->getParent(); diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index 854568f9b..103cdcf14 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -18,6 +18,7 @@ + From 01391b7eed79925623348a29cdd1ee4abe35edb8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 17:10:53 +0200 Subject: [PATCH 254/521] Rename WindowBase's open/close to onOpen/onClose --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/birth.cpp | 4 ++-- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/class.cpp | 8 ++++---- apps/openmw/mwgui/class.hpp | 4 ++-- apps/openmw/mwgui/console.cpp | 4 ++-- apps/openmw/mwgui/console.hpp | 4 ++-- apps/openmw/mwgui/container.cpp | 4 ++-- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 4 ++-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 ++-- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 6 +++--- apps/openmw/mwgui/mapwindow.hpp | 4 ++-- apps/openmw/mwgui/merchantrepair.cpp | 2 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ++-- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/race.cpp | 6 +++--- apps/openmw/mwgui/race.hpp | 4 ++-- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 4 ++-- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/savegamedialog.cpp | 4 ++-- apps/openmw/mwgui/savegamedialog.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 2 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 6 +++--- apps/openmw/mwgui/spellcreationdialog.hpp | 4 ++-- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.hpp | 2 +- apps/openmw/mwgui/textinput.cpp | 4 ++-- apps/openmw/mwgui/textinput.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 4 ++-- apps/openmw/mwgui/waitdialog.hpp | 4 ++-- apps/openmw/mwgui/windowbase.cpp | 8 ++++---- apps/openmw/mwgui/windowbase.hpp | 8 ++++---- 51 files changed, 82 insertions(+), 82 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 7379f3613..c68bad02a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -101,7 +101,7 @@ namespace MWGui update(); } - void AlchemyWindow::open() + void AlchemyWindow::onOpen() { mAlchemy->setAlchemist (MWMechanics::getPlayer()); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index e1f48d4a3..8b7bcaaca 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -24,7 +24,7 @@ namespace MWGui public: AlchemyWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index ecc011fc1..b4a6b7d2f 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -64,9 +64,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void BirthDialog::open() + void BirthDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); updateBirths(); updateSpells(); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index c8ec9da09..c13d49838 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -20,7 +20,7 @@ namespace MWGui void setBirthId(const std::string &raceId); void setNextButtonShow(bool shown); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e1f5a165e..2278b5141 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -125,9 +125,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void PickClassDialog::open() + void PickClassDialog::onOpen() { - WindowModal::open (); + WindowModal::onOpen (); updateClasses(); updateStats(); } @@ -341,9 +341,9 @@ namespace MWGui } } - void InfoBoxDialog::open() + void InfoBoxDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Fix layout layoutVertically(mTextBox, 4); layoutVertically(mButtonBar, 6); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 8206d6b03..2b205d12f 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -21,7 +21,7 @@ namespace MWGui std::string getText() const; void setButtons(ButtonList &buttons); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -100,7 +100,7 @@ namespace MWGui void setClassId(const std::string &classId); void setNextButtonShow(bool shown); - virtual void open(); + virtual void onOpen(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index aeff7dc39..62690a0f1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -145,14 +145,14 @@ namespace MWGui mCompilerContext.setExtensions (&mExtensions); } - void Console::open() + void Console::onOpen() { // Give keyboard focus to the combo box whenever the console is // turned on MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::close() + void Console::onClose() { // Apparently, hidden widgets can retain key focus // Remove for MyGUI 3.2.2 diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 98e46a559..1232036ca 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -39,8 +39,8 @@ namespace MWGui Console(int w, int h, bool consoleOnlyScripts); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); virtual void exit(); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index c9be21322..4f9201f06 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -172,9 +172,9 @@ namespace MWGui mSortModel = NULL; } - void ContainerWindow::close() + void ContainerWindow::onClose() { - WindowBase::close(); + WindowBase::onClose(); if (dynamic_cast(mModel) // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 520bce9d9..65cfa35c7 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -34,7 +34,7 @@ namespace MWGui ContainerWindow(DragAndDrop* dragAndDrop); void openContainer(const MWWorld::Ptr& container, bool loot=false); - virtual void close(); + virtual void onClose(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 9f59cd443..d9954a792 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -73,9 +73,9 @@ namespace MWGui setVisible(false); } - void PersuasionDialog::open() + void PersuasionDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 9f0b2245a..682baef3c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -28,7 +28,7 @@ namespace MWGui public: PersuasionDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index c7d2ef7de..25568da07 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -60,7 +60,7 @@ namespace MWGui delete mItemSelectionDialog; } - void EnchantingDialog::open() + void EnchantingDialog::onOpen() { center(); } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index cb7c6c0d0..7c49ae54a 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -19,7 +19,7 @@ namespace MWGui EnchantingDialog(); virtual ~EnchantingDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 6eb0c554e..dcfb075db 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -363,7 +363,7 @@ namespace MWGui dirtyPreview(); } - void InventoryWindow::open() + void InventoryWindow::onOpen() { if (!mPtr.isEmpty()) { diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 761464540..fb5be3493 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -35,7 +35,7 @@ namespace MWGui public: InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); - virtual void open(); + virtual void onOpen(); /// start trading, disables item drag&drop void setTrading(bool trading); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index e96cc8b70..73b196cf8 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -211,7 +211,7 @@ namespace button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); } - void open() + void onOpen() { if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ()) { @@ -240,7 +240,7 @@ namespace updateShowingPages(); } - void close() + void onClose() { mModel->unload (); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index da8e93279..a068d71f3 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -128,7 +128,7 @@ namespace MWGui setAttributeValues(); } - void LevelupDialog::open() + void LevelupDialog::onOpen() { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index d49f7536d..36810665e 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -11,7 +11,7 @@ namespace MWGui public: LevelupDialog(); - virtual void open(); + virtual void onOpen(); private: MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index ed9dabd2d..7bc66fab4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -943,7 +943,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); } - void MapWindow::open() + void MapWindow::onOpen() { ensureGlobalMapLoaded(); @@ -1107,9 +1107,9 @@ namespace MWGui return MyGUI::TextIterator::getOnlyText(mTextEdit->getCaption()); } - void EditNoteDialog::open() + void EditNoteDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 312447a24..eae1cec7e 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -169,7 +169,7 @@ namespace MWGui public: EditNoteDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void showDeleteButton(bool show); @@ -218,7 +218,7 @@ namespace MWGui void ensureGlobalMapLoaded(); - virtual void open(); + virtual void onOpen(); void onFrame(float dt); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9e27c0154..9c706851f 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -111,7 +111,7 @@ void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) mList->setViewOffset(MyGUI::IntPoint(0, static_cast(mList->getViewOffset().top + _rel*0.3f))); } -void MerchantRepair::open() +void MerchantRepair::onOpen() { center(); // Reset scrollbars diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 8dcdfee12..5006b08a4 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -12,7 +12,7 @@ class MerchantRepair : public WindowBase public: MerchantRepair(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index f9c445d36..6b5ba506b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -200,7 +200,7 @@ namespace MWGui , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { - WindowModal::open(); + WindowModal::onOpen(); int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 10; // padding between the text-widget und the button-widget diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index e912193bf..19dd6fa03 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -590,9 +590,9 @@ namespace MWGui mParent->onAssignMagicCancel(); } - void MagicSelectionDialog::open () + void MagicSelectionDialog::onOpen () { - WindowModal::open(); + WindowModal::onOpen(); mMagicList->setModel(new SpellModel(MWMechanics::getPlayer())); mMagicList->resetScrollbars(); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 64db9043e..d07cdef3d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -94,7 +94,7 @@ namespace MWGui public: MagicSelectionDialog(QuickKeysMenu* parent); - virtual void open(); + virtual void onOpen(); virtual void exit(); private: diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 047f65263..374a5d3d8 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -120,9 +120,9 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } - void RaceDialog::open() + void RaceDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); updateRaces(); updateSkills(); @@ -183,7 +183,7 @@ namespace MWGui updateSpellPowers(); } - void RaceDialog::close() + void RaceDialog::onClose() { mPreviewImage->setRenderItemTexture(NULL); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index b762745cd..911bce577 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -51,8 +51,8 @@ namespace MWGui void setGender(Gender gender) { mGenderIndex = gender == GM_Male ? 0 : 1; } void setNextButtonShow(bool shown); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 390a1f83c..00af45695 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -50,7 +50,7 @@ Recharge::Recharge() setVisible(false); } -void Recharge::open() +void Recharge::onOpen() { center(); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index cc3db14df..d963e9d66 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -22,7 +22,7 @@ class Recharge : public WindowBase public: Recharge(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 4d6441450..f917cef0f 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -46,7 +46,7 @@ Repair::Repair() mToolIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onSelectItem); } -void Repair::open() +void Repair::onOpen() { center(); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index c50ba861a..44c380b51 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -19,7 +19,7 @@ class Repair : public WindowBase public: Repair(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index bf18e7355..61a7a2ac0 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -101,9 +101,9 @@ namespace MWGui okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); } - void ReviewDialog::open() + void ReviewDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); mUpdateSkillArea = true; } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index f21f2fa9d..34dd5a7d4 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -45,7 +45,7 @@ namespace MWGui void configureSkills(const SkillList& major, const SkillList& minor); void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value); - virtual void open(); + virtual void onOpen(); void onFrame(float duration); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 84d4ca959..7a4c3a22e 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -118,9 +118,9 @@ namespace MWGui accept(); } - void SaveGameDialog::open() + void SaveGameDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); mSaveNameEdit->setCaption (""); if (mSaving) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index be0e47cab..2a49cf48a 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -17,7 +17,7 @@ namespace MWGui public: SaveGameDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index f46199c80..4e8547d33 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -553,7 +553,7 @@ namespace MWGui updateControlsBox (); } - void SettingsWindow::open() + void SettingsWindow::onOpen() { updateControlsBox (); resetScrollbars(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 2ac06dcaa..447331574 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -15,7 +15,7 @@ namespace MWGui public: SettingsWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 354253fa4..6a36554d8 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -96,9 +96,9 @@ namespace MWGui mConstantEffect = constant; } - void EditEffectDialog::open() + void EditEffectDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); center(); } @@ -415,7 +415,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } - void SpellCreationDialog::open() + void SpellCreationDialog::onOpen() { center(); } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 6cdf74d10..d12115c88 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -23,7 +23,7 @@ namespace MWGui public: EditEffectDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void setConstantEffect(bool constant); @@ -150,7 +150,7 @@ namespace MWGui public: SpellCreationDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); void startSpellMaking(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 5ce3fd1fe..9261912b4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -62,7 +62,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); } - void SpellWindow::open() + void SpellWindow::onOpen() { updateSpells(); } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index dcce10f9d..f8fead9ea 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -37,7 +37,7 @@ namespace MWGui virtual void onPinToggled(); virtual void onTitleDoubleClicked(); - virtual void open(); + virtual void onOpen(); SpellView* mSpellView; SpellIcons* mSpellIcons; diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 1fe3cb68d..487953e00 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -37,7 +37,7 @@ namespace MWGui void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } void updateSkillArea(); - virtual void open() { onWindowResize(mMainWidget->castType()); } + virtual void onOpen() { onWindowResize(mMainWidget->castType()); } private: void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 958b52dc0..169c9e742 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -42,9 +42,9 @@ namespace MWGui setText("LabelT", label); } - void TextInputDialog::open() + void TextInputDialog::onOpen() { - WindowModal::open(); + WindowModal::onOpen(); // Make sure the edit box has focus MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 57dd34dd6..ccfa19c87 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -20,7 +20,7 @@ namespace MWGui void setNextButtonShow(bool shown); void setTextLabel(const std::string &label); - virtual void open(); + virtual void onOpen(); /** Event : Dialog finished, OK button clicked.\n signature : void method()\n diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 82218fef1..d2e771918 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -55,7 +55,7 @@ namespace MWGui mProgressBar.setVisible(false); } - void TrainingWindow::open() + void TrainingWindow::onOpen() { center(); } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 7c4582062..95a35be7f 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -14,7 +14,7 @@ namespace MWGui public: TrainingWindow(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ba58a9c69..476d19bd6 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -35,7 +35,7 @@ namespace MWGui getWidget(mProgressText, "ProgressText"); } - void WaitDialogProgressBar::open() + void WaitDialogProgressBar::onOpen() { center(); } @@ -85,7 +85,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode(); } - void WaitDialog::open() + void WaitDialog::onOpen() { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 13df1f8ae..829659d16 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -13,7 +13,7 @@ namespace MWGui public: WaitDialogProgressBar(); - virtual void open(); + virtual void onOpen(); void setProgress(int cur, int total); @@ -27,7 +27,7 @@ namespace MWGui public: WaitDialog(); - virtual void open(); + virtual void onOpen(); virtual void exit(); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 99b74529e..1ba4c7ed6 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -23,9 +23,9 @@ void WindowBase::setVisible(bool visible) mMainWidget->setVisible(visible); if (visible) - open(); + onOpen(); else if (wasVisible && !visible) - close(); + onClose(); // This is needed as invisible widgets can retain key focus. // Remove for MyGUI 3.2.2 @@ -64,13 +64,13 @@ WindowModal::WindowModal(const std::string& parLayout) { } -void WindowModal::open() +void WindowModal::onOpen() { MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed } -void WindowModal::close() +void WindowModal::onClose() { MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 43fb8901e..400dc0ce4 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -22,9 +22,9 @@ namespace MWGui typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; /// Notify that window has been made visible - virtual void open() {} + virtual void onOpen() {} /// Notify that window has been hidden - virtual void close () {} + virtual void onClose () {} /// Gracefully exits the window virtual void exit() {} /// Sets the visibility of the window @@ -42,8 +42,8 @@ namespace MWGui { public: WindowModal(const std::string& parLayout); - virtual void open(); - virtual void close(); + virtual void onOpen(); + virtual void onClose(); virtual void exit() {} }; From 622e3ebd60f2de42e7a6e15a947c7bab1a6db606 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 20:43:53 +0200 Subject: [PATCH 255/521] Remove excessive padding in some GUI layouts --- ...openmw_chargen_generate_class_result.layout | 2 +- files/mygui/openmw_recharge_dialog.layout | 2 +- files/mygui/openmw_repair.layout | 2 +- files/mygui/openmw_savegame_dialog.layout | 2 +- files/mygui/openmw_tooltips.layout | 18 +++++++++--------- files/mygui/openmw_wait_dialog.layout | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/files/mygui/openmw_chargen_generate_class_result.layout b/files/mygui/openmw_chargen_generate_class_result.layout index 83595fafd..d49f57dde 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -3,7 +3,7 @@ - + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index d620aadab..200d345e3 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index 340711bb1..abc429594 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_savegame_dialog.layout b/files/mygui/openmw_savegame_dialog.layout index a7b7703de..236eaaa61 100644 --- a/files/mygui/openmw_savegame_dialog.layout +++ b/files/mygui/openmw_savegame_dialog.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index a7eeabfa5..c038066f1 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -32,7 +32,7 @@ - + @@ -44,7 +44,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -77,7 +77,7 @@ - + @@ -137,7 +137,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -277,7 +277,7 @@ - + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 112fa6001..4bc60ceb4 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -2,7 +2,7 @@ - + From 3820416277802709b03d29749535443b1c3913d7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 20:46:08 +0200 Subject: [PATCH 256/521] Refactor the unholy mess that is WindowManager::updateVisible GUI modes are now defined in a general and extensible way. The next commits are going to take advantage of this. --- apps/openmw/mwgui/journalwindow.cpp | 10 +- apps/openmw/mwgui/journalwindow.hpp | 6 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mainmenu.hpp | 4 +- apps/openmw/mwgui/messagebox.cpp | 3 +- apps/openmw/mwgui/windowbase.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 314 +++++++++++-------------- apps/openmw/mwgui/windowmanagerimp.hpp | 19 ++ 8 files changed, 177 insertions(+), 182 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 73b196cf8..a0e424021 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -44,7 +44,7 @@ namespace static char const LeftTopicIndex [] = "LeftTopicIndex"; static char const RightTopicIndex [] = "RightTopicIndex"; - struct JournalWindowImpl : MWGui::WindowBase, MWGui::JournalBooks, MWGui::JournalWindow + struct JournalWindowImpl : MWGui::JournalBooks, MWGui::JournalWindow { struct DisplayState { @@ -94,7 +94,7 @@ namespace } JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) - : WindowBase("openmw_journal.layout"), JournalBooks (Model) + : JournalBooks (Model), JournalWindow() { mMainWidget->setVisible(false); center(); @@ -603,3 +603,9 @@ MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model { return new JournalWindowImpl (Model, questList); } + +MWGui::JournalWindow::JournalWindow() + :WindowBase("openmw_journal.layout") +{ + +} diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cc645ca44..c9bf0ef0a 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H +#include "windowbase.hpp" + #include namespace MWBase { class WindowManager; } @@ -9,8 +11,10 @@ namespace MWGui { struct JournalViewModel; - struct JournalWindow + struct JournalWindow : public WindowBase { + JournalWindow(); + /// construct a new instance of the one JournalWindow implementation static JournalWindow * create (std::shared_ptr Model, bool questList); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 265b08fd6..657f0e4ec 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -22,7 +22,7 @@ namespace MWGui { MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) - : Layout("openmw_mainmenu.layout") + : WindowBase("openmw_mainmenu.layout") , mWidth (w), mHeight (h) , mVFS(vfs), mButtonBox(0) , mBackground(NULL) diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index fe256dc8e..612f7d1bd 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_GAME_MWGUI_MAINMENU_H #define OPENMW_GAME_MWGUI_MAINMENU_H -#include "layout.hpp" +#include "windowbase.hpp" namespace Gui { @@ -20,7 +20,7 @@ namespace MWGui class SaveGameDialog; class VideoWidget; - class MainMenu : public Layout + class MainMenu : public WindowBase { int mWidth; int mHeight; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6b5ba506b..dd0495051 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -77,6 +77,7 @@ namespace MWGui if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { mLastButtonPressed = mInterMessageBoxe->readPressedButton(); + mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; mInterMessageBoxe = NULL; MWBase::Environment::get().getInputManager()->changeInputMode( @@ -200,7 +201,7 @@ namespace MWGui , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { - WindowModal::onOpen(); + setVisible(true); int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 10; // padding between the text-widget und the button-widget diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 1ba4c7ed6..5ed564737 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -15,6 +15,7 @@ using namespace MWGui; WindowBase::WindowBase(const std::string& parLayout) : Layout(parLayout) { + mMainWidget->setVisible(false); } void WindowBase::setVisible(bool visible) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5d7a54735..81edc4a00 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -320,51 +320,103 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); mRecharge = new Recharge(); + mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); + mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); + mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); + mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); mMap->renderGlobalMap(); trackWindow(mMap, "map"); mStatsWindow = new StatsWindow(mDragAndDrop); trackWindow(mStatsWindow, "stats"); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); + mSpellWindow = new SpellWindow(mDragAndDrop); + trackWindow(mSpellWindow, "spells"); + + mGuiModeStates[GM_Inventory] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); + mGuiModeStates[GM_None] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); + + mTradeWindow = new TradeWindow(); + trackWindow(mTradeWindow, "barter"); + + mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); + mConsole = new Console(w,h, mConsoleOnlyScripts); trackWindow(mConsole, "console"); + mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); + mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); - mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); - mTradeWindow = new TradeWindow(); - trackWindow(mTradeWindow, "barter"); mSpellBuyingWindow = new SpellBuyingWindow(); + mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); + mTravelWindow = new TravelWindow(); + mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); + mDialogueWindow = new DialogueWindow(); trackWindow(mDialogueWindow, "dialogue"); + mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); + mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); + mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); + mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); + mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); + mBookWindow = new BookWindow(); + mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); + mCountDialog = new CountDialog(); mSettingsWindow = new SettingsWindow(); + mGuiModeStates[GM_Settings] = GuiModeState(mSettingsWindow); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); trackWindow(mAlchemyWindow, "alchemy"); - mSpellWindow = new SpellWindow(mDragAndDrop); - trackWindow(mSpellWindow, "spells"); + mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); + mQuickKeysMenu = new QuickKeysMenu(); + mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); + mLevelupDialog = new LevelupDialog(); + mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); + mWaitDialog = new WaitDialog(); + mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); + mGuiModeStates[GM_RestBed] = GuiModeState(mWaitDialog); + mSpellCreationDialog = new SpellCreationDialog(); + mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); + mEnchantingDialog = new EnchantingDialog(); + mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); + mTrainingWindow = new TrainingWindow(); + mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); + mMerchantRepair = new MerchantRepair(); + mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); + mRepair = new Repair(); + mGuiModeStates[GM_Repair] = GuiModeState(mRepair); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); + mJailScreen = new JailScreen(); + mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen); std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) @@ -531,196 +583,77 @@ namespace MWGui { if (!mMap) return; // UI not created yet - // Start out by hiding everything except the HUD - mMap->setVisible(false); - mMenu->setVisible(false); - mStatsWindow->setVisible(false); - mConsole->setVisible(false); - mJournal->setVisible(false); - mDialogueWindow->setVisible(false); - mContainerWindow->setVisible(false); - mInventoryWindow->setVisible(false); - mScrollWindow->setVisible(false); - mBookWindow->setVisible(false); - mTradeWindow->setVisible(false); - mSpellBuyingWindow->setVisible(false); - mTravelWindow->setVisible(false); - mSettingsWindow->setVisible(false); - mAlchemyWindow->setVisible(false); - mSpellWindow->setVisible(false); - mQuickKeysMenu->setVisible(false); - mLevelupDialog->setVisible(false); - mWaitDialog->setVisible(false); - mSpellCreationDialog->setVisible(false); - mEnchantingDialog->setVisible(false); - mTrainingWindow->setVisible(false); - mMerchantRepair->setVisible(false); - mRepair->setVisible(false); - mCompanionWindow->setVisible(false); - mInventoryWindow->setTrading(false); - mRecharge->setVisible(false); - mVideoBackground->setVisible(false); - mJailScreen->setVisible(false); - mHud->setVisible(mHudEnabled && mGuiEnabled); - mToolTips->setVisible(mGuiEnabled); + bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper); + + mHud->setVisible(mHudEnabled && mGuiEnabled && !loading); + mToolTips->setVisible(mGuiEnabled && !loading); bool gameMode = !isGuiMode(); mInputBlocker->setVisible (gameMode); - setCursorVisible(!gameMode); + + if (loading) + setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); + else + setCursorVisible(!gameMode); if (gameMode) setKeyFocusWidget (NULL); - if (!mGuiEnabled) - { - if (containsMode(GM_Console)) - mConsole->setVisible(true); - return; - } - // Icons of forced hidden windows are displayed setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map))); setWeaponVisibility((mAllowed & GW_Inventory) && (!mInventoryWindow->pinned() || (mForceHidden & GW_Inventory))); setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic))); setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats))); - // If in game mode (or interactive messagebox), show only the pinned windows + // If in game mode (or interactive messagebox), show the pinned windows if (mGuiModes.empty()) { - mInventoryWindow->setGuiMode(GM_None); mMap->setVisible(mMap->pinned() && !(mForceHidden & GW_Map) && (mAllowed & GW_Map)); mStatsWindow->setVisible(mStatsWindow->pinned() && !(mForceHidden & GW_Stats) && (mAllowed & GW_Stats)); mInventoryWindow->setVisible(mInventoryWindow->pinned() && !(mForceHidden & GW_Inventory) && (mAllowed & GW_Inventory)); mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); - return; } - if(mGuiModes.size() != 0) + GuiMode mode = mGuiModes.back(); + + mInventoryWindow->setTrading(mode == GM_Barter); + mInventoryWindow->setGuiMode(mode); + + // For the inventory mode, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; + mGuiModeStates[GM_Inventory].mVisibilityMask.resize(4); + mGuiModeStates[GM_Inventory].mVisibilityMask[0] = eff & GW_Map; + mGuiModeStates[GM_Inventory].mVisibilityMask[1] = eff & GW_Inventory; + mGuiModeStates[GM_Inventory].mVisibilityMask[2] = eff & GW_Magic; + mGuiModeStates[GM_Inventory].mVisibilityMask[3] = eff & GW_Stats; + if (getMode() == GM_Inventory) + mGuiModeStates[GM_Inventory].update(true); + + switch (mode) { - GuiMode mode = mGuiModes.back(); - - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - mConsole->setVisible(true); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: - { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; - - // Show the windows we want - mMap ->setVisible((eff & GW_Map) != 0); - mStatsWindow ->setVisible((eff & GW_Stats) != 0); - mInventoryWindow->setVisible((eff & GW_Inventory) != 0); - mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible((eff & GW_Magic) != 0); - break; - } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - mInventoryWindow->setGuiMode(mode); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mInventoryWindow->setTrading(true); - mInventoryWindow->setGuiMode(mode); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Recharge: - mRecharge->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - case GM_Journal: - mJournal->setVisible(true); - break; - case GM_Jail: - mJailScreen->setVisible(true); - break; - case GM_LoadingWallpaper: - case GM_Loading: - // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway, - // GM_Loading uses a texture of the last rendered frame so everything previously visible will be rendered. - mHud->setVisible(false); - mToolTips->setVisible(false); - setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()); - break; - default: - // Unsupported mode, switch back to game - break; - } + // FIXME: refactor chargen windows to use modes properly (or not use them at all) + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_RestBed: + // FIXME: use GM_Rest and push the 'bed' argument in some other way + mWaitDialog->bedActivated(); + break; + default: + break; } } @@ -1267,11 +1200,18 @@ namespace MWGui mSpellBuyingWindow->center(); } + void WindowManager::onCursorChange(const std::string &name) + { + mCursorManager->cursorChanged(name); + } + void WindowManager::pushGuiMode(GuiMode mode) { if (mode==GM_Inventory && mAllowed==GW_None) return; + if (!mGuiModes.empty() && mGuiModes.back() == mode) + return; // If this mode already exists somewhere in the stack, just bring it to the front. if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) @@ -1279,23 +1219,29 @@ namespace MWGui mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); } + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(false); + mGuiModes.push_back(mode); + mGuiModeStates[mode].update(true); + bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); updateVisible(); } - void WindowManager::onCursorChange(const std::string &name) - { - mCursorManager->cursorChanged(name); - } - void WindowManager::popGuiMode() { if (!mGuiModes.empty()) + { + mGuiModeStates[mGuiModes.back()].update(false); mGuiModes.pop_back(); + } + + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(true); bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1305,6 +1251,12 @@ namespace MWGui void WindowManager::removeGuiMode(GuiMode mode) { + if (!mGuiModes.empty() && mGuiModes.back() == mode) + { + popGuiMode(); + return; + } + std::vector::iterator it = mGuiModes.begin(); while (it != mGuiModes.end()) { @@ -2214,4 +2166,16 @@ namespace MWGui else return true; } + + void WindowManager::GuiModeState::update(bool visible) + { + for (unsigned int i=0; isetVisible(visible && visibilityMask); + } + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3e17046df..524575c6a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -494,6 +494,25 @@ namespace MWGui std::map mPlayerSkillValues; MyGUI::Gui *mGui; // Gui + + struct GuiModeState + { + GuiModeState(WindowBase* window) + { + mWindows.push_back(window); + } + GuiModeState(const std::vector& windows) + : mWindows(windows) {} + GuiModeState() {} + + void update(bool visible); + + std::vector mWindows; + std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. + }; + // Defines the windows that should be shown in a particular GUI mode. + std::map mGuiModeStates; + // The currently active stack of GUI modes (top mode is the one we are in). std::vector mGuiModes; SDLUtil::SDLCursorManager* mCursorManager; From 84657271c7603aeead51ccee523f12b9608bb165 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 21:26:41 +0200 Subject: [PATCH 257/521] Improve WindowManager API with a generic way of passing a Ptr to the opened GUI window --- apps/openmw/mwbase/windowmanager.hpp | 18 +-- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 6 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/console.cpp | 6 +- apps/openmw/mwgui/console.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 16 +-- apps/openmw/mwgui/enchantingdialog.cpp | 63 ++++------ apps/openmw/mwgui/enchantingdialog.hpp | 5 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/recharge.cpp | 2 +- apps/openmw/mwgui/recharge.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 6 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/soulgemdialog.cpp | 6 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 9 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 3 +- apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 8 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 116 +++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 20 +-- apps/openmw/mwworld/actionopen.cpp | 5 +- apps/openmw/mwworld/actionopen.hpp | 5 +- apps/openmw/mwworld/actionread.cpp | 6 +- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actionrepair.cpp | 2 +- 43 files changed, 125 insertions(+), 235 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 37c3ce0d3..242f358a9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -115,6 +115,7 @@ namespace MWBase virtual void setNewGame(bool newgame) = 0; + virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; virtual void popGuiMode() = 0; @@ -157,8 +158,6 @@ namespace MWBase virtual void updateSpellWindow() = 0; - virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; - /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; @@ -284,21 +283,6 @@ namespace MWBase virtual bool getPlayerSleeping() = 0; virtual void wakeUpPlayer() = 0; - virtual void showCompanionWindow(MWWorld::Ptr actor) = 0; - virtual void startSpellMaking(MWWorld::Ptr actor) = 0; - virtual void startEnchanting(MWWorld::Ptr actor) = 0; - virtual void startRecharge(MWWorld::Ptr soulgem) = 0; - virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; - virtual void startTraining(MWWorld::Ptr actor) = 0; - virtual void startRepair(MWWorld::Ptr actor) = 0; - virtual void startRepairItem(MWWorld::Ptr item) = 0; - virtual void startTravel(const MWWorld::Ptr& actor) = 0; - virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0; - virtual void startTrade(const MWWorld::Ptr& actor) = 0; - virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0; - virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0; - virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0; - virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 65f8c80d8..d6926f11d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -457,11 +457,11 @@ namespace MWClass // by default user can loot friendly actors during death animation if (canLoot && !stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ca6c85aba..e7085bfbc 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -872,11 +872,11 @@ namespace MWClass // by default user can loot friendly actors during death animation if (canLoot && !stats.getAiSequence().isInCombat()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // otherwise wait until death animation if(stats.isDeathAnimationFinished()) - return std::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + return std::shared_ptr(new MWWorld::ActionOpen(ptr)); // death animation is not finished, do nothing return std::shared_ptr (new MWWorld::FailedAction("")); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 6da1f7806..fb4ba1016 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -186,7 +186,7 @@ namespace MWDialogue bool isCompanion = !mActor.getClass().getScript(mActor).empty() && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); if (isCompanion) - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor); } bool DialogueManager::compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index b3296e7a7..ca697d0b6 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -11,6 +11,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/class.hpp" #include "formatting.hpp" @@ -74,10 +75,13 @@ namespace MWGui mPages.clear(); } - void BookWindow::openBook (MWWorld::Ptr book, bool showTakeButton) + void BookWindow::setPtr (const MWWorld::Ptr& book) { mBook = book; + MWWorld::Ptr player = MWMechanics::getPlayer(); + bool showTakeButton = book.getContainerStore() != &player.getClass().getContainerStore(player); + clearPages(); mCurrentPage = 0; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 881b9997c..e8a1a42ff 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void exit(); - void openBook(MWWorld::Ptr book, bool showTakeButton); + void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index fc4a98489..07753ab11 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -103,7 +103,7 @@ void CompanionWindow::onBackgroundSelected() } } -void CompanionWindow::openCompanion(const MWWorld::Ptr& npc) +void CompanionWindow::setPtr(const MWWorld::Ptr& npc) { mPtr = npc; updateEncumbranceBar(); diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index d37f0c4e4..ec70146f2 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -22,7 +22,7 @@ namespace MWGui virtual void resetReference(); - void openCompanion(const MWWorld::Ptr& npc); + void setPtr(const MWWorld::Ptr& npc); void onFrame (); private: diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 62690a0f1..55a03bafd 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -422,7 +422,7 @@ namespace MWGui setCoord(10,10, width-10, height/2); } - void Console::setSelectedObject(const MWWorld::Ptr& object) + void Console::setPtr(const MWWorld::Ptr& object) { if (!object.isEmpty()) { @@ -448,12 +448,12 @@ namespace MWGui void Console::onReferenceUnavailable() { - setSelectedObject(MWWorld::Ptr()); + setPtr(MWWorld::Ptr()); } void Console::resetReference() { ReferenceInterface::resetReference(); - setSelectedObject(MWWorld::Ptr()); + setPtr(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 1232036ca..927fdd5fe 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -25,7 +25,7 @@ namespace MWGui { public: /// Set the implicit object for script execution - void setSelectedObject(const MWWorld::Ptr& object); + void setPtr(const MWWorld::Ptr& object); MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 4f9201f06..6ea2e3e9a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -129,11 +129,13 @@ namespace MWGui dropItem(); } - void ContainerWindow::openContainer(const MWWorld::Ptr& container, bool loot) + void ContainerWindow::setPtr(const MWWorld::Ptr& container) { mPickpocketDetected = false; mPtr = container; + bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); + if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) { // we are stealing stuff diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 65cfa35c7..2758f57c9 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -33,7 +33,7 @@ namespace MWGui public: ContainerWindow(DragAndDrop* dragAndDrop); - void openContainer(const MWWorld::Ptr& container, bool loot=false); + void setPtr(const MWWorld::Ptr& container); virtual void onClose(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d9954a792..d2d97a437 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -336,23 +336,23 @@ namespace MWGui if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) - MWBase::Environment::get().getWindowManager()->startTrade(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); else if (topic == gmst.find("sSpells")->getString()) - MWBase::Environment::get().getWindowManager()->startSpellBuying(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying, mPtr); else if (topic == gmst.find("sTravel")->getString()) - MWBase::Environment::get().getWindowManager()->startTravel(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel, mPtr); else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation, mPtr); else if (topic == gmst.find("sEnchanting")->getString()) - MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mPtr); else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - MWBase::Environment::get().getWindowManager()->startTraining (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training, mPtr); else if (topic == gmst.find("sRepair")->getString()) - MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 25568da07..94e8b329d 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -143,51 +143,36 @@ namespace MWGui } } - void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) + void EnchantingDialog::setPtr (const MWWorld::Ptr& ptr) { mName->setCaption(""); - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(actor); - - mBuyButton->setCaptionWithReplacing("#{sBuy}"); - - mChanceLayout->setVisible(false); - - mPtr = actor; + if (ptr.getClass().isActor()) + { + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(ptr); + mBuyButton->setCaptionWithReplacing("#{sBuy}"); + mChanceLayout->setVisible(false); + mPtr = ptr; + setSoulGem(MWWorld::Ptr()); + mPrice->setVisible(true); + mPriceText->setVisible(true); + } + else + { + mEnchanting.setSelfEnchanting(true); + mEnchanting.setEnchanter(MWMechanics::getPlayer()); + mBuyButton->setCaptionWithReplacing("#{sCreate}"); + bool enabled = Settings::Manager::getBool("show enchant chance","Game"); + mChanceLayout->setVisible(enabled); + mPtr = MWMechanics::getPlayer(); + setSoulGem(ptr); + mPrice->setVisible(false); + mPriceText->setVisible(false); + } - setSoulGem(MWWorld::Ptr()); setItem(MWWorld::Ptr()); - startEditing (); - mPrice->setVisible(true); - mPriceText->setVisible(true); - updateLabels(); - } - - void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) - { - mName->setCaption(""); - - MWWorld::Ptr player = MWMechanics::getPlayer(); - - mEnchanting.setSelfEnchanting(true); - mEnchanting.setEnchanter(player); - - mBuyButton->setCaptionWithReplacing("#{sCreate}"); - - bool enabled = Settings::Manager::getBool("show enchant chance","Game"); - - mChanceLayout->setVisible(enabled); - - mPtr = player; - startEditing(); - - setSoulGem(soulgem); - setItem(MWWorld::Ptr()); - - mPrice->setVisible(false); - mPriceText->setVisible(false); updateLabels(); } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 7c49ae54a..41d6382cc 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -26,8 +26,9 @@ namespace MWGui void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); - void startEnchanting(MWWorld::Ptr actor); - void startSelfEnchanting(MWWorld::Ptr soulgem); + /// Actor Ptr: buy enchantment from this actor + /// Soulgem Ptr: player self-enchant + void setPtr(const MWWorld::Ptr& ptr); virtual void resetReference(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0e1b2cc89..ba4d05d75 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Console, object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 9c706851f..785b5ee48 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -32,7 +32,7 @@ MerchantRepair::MerchantRepair() mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); } -void MerchantRepair::startRepair(const MWWorld::Ptr &actor) +void MerchantRepair::setPtr(const MWWorld::Ptr &actor) { mActor = actor; @@ -145,7 +145,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWMechanics::CreatureStats& actorStats = mActor.getClass().getCreatureStats(mActor); actorStats.setGoldPool(actorStats.getGoldPool() + price); - startRepair(mActor); + setPtr(mActor); } void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 5006b08a4..76ccd28cc 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -16,7 +16,7 @@ public: virtual void exit(); - void startRepair(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor); private: MyGUI::ScrollView* mList; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 00af45695..54473746a 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -67,7 +67,7 @@ void Recharge::exit() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); } -void Recharge::start (const MWWorld::Ptr &item) +void Recharge::setPtr (const MWWorld::Ptr &item) { mGemIcon->setItem(item); mGemIcon->setUserString("ToolTipType", "ItemPtr"); diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index d963e9d66..93f86ab65 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -26,7 +26,7 @@ public: virtual void exit(); - void start (const MWWorld::Ptr& gem); + void setPtr (const MWWorld::Ptr& gem); protected: ItemChargeView* mBox; diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index f917cef0f..295b8254b 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -63,7 +63,7 @@ void Repair::exit() MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } -void Repair::startRepairItem(const MWWorld::Ptr &item) +void Repair::setPtr(const MWWorld::Ptr &item) { MWBase::Environment::get().getWindowManager()->playSound("Item Repair Up"); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 44c380b51..a2573d780 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -23,7 +23,7 @@ public: virtual void exit(); - void startRepairItem (const MWWorld::Ptr& item); + void setPtr (const MWWorld::Ptr& item); protected: ItemChargeView* mRepairBox; diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a5d4c3324..3649afe23 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,6 +12,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/class.hpp" #include "formatting.hpp" @@ -49,13 +50,16 @@ namespace MWGui center(); } - void ScrollWindow::openScroll (MWWorld::Ptr scroll, bool showTakeButton) + void ScrollWindow::setPtr (const MWWorld::Ptr& scroll) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getWindowManager()->playSound("scroll"); mScroll = scroll; + MWWorld::Ptr player = MWMechanics::getPlayer(); + bool showTakeButton = scroll.getContainerStore() != &player.getClass().getContainerStore(player); + MWWorld::LiveCellRef *ref = mScroll.get(); Formatting::BookFormatter formatter; diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 961f1b675..5ae8e972a 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,7 +17,7 @@ namespace MWGui public: ScrollWindow (); - void openScroll (MWWorld::Ptr scroll, bool showTakeButton); + void setPtr (const MWWorld::Ptr& scroll); virtual void exit(); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 0232eb7b3..104c81eab 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -22,13 +22,11 @@ namespace MWGui { if (button == 0) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge); - MWBase::Environment::get().getWindowManager()->startRecharge(mSoulgem); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge, mSoulgem); } else { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); - MWBase::Environment::get().getWindowManager()->startSelfEnchanting(mSoulgem); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mSoulgem); } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 6a7376aa0..592316274 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -88,7 +88,12 @@ namespace MWGui mSpellsWidgetMap.clear(); } - void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor, int startOffset) + void SpellBuyingWindow::setPtr(const MWWorld::Ptr &actor) + { + setPtr(actor, 0); + } + + void SpellBuyingWindow::setPtr(const MWWorld::Ptr& actor, int startOffset) { center(); mPtr = actor; @@ -161,7 +166,7 @@ namespace MWGui MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); - startSpellBuying(mPtr, mSpellsView->getViewOffset().top); + setPtr(mPtr, mSpellsView->getViewOffset().top); MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); } diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 37210819f..b96896e4c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -25,7 +25,8 @@ namespace MWGui public: SpellBuyingWindow(); - void startSpellBuying(const MWWorld::Ptr& actor, int startOffset); + void setPtr(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor, int startOffset); virtual void exit(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6a36554d8..d5982a174 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -352,7 +352,7 @@ namespace MWGui setWidgets(mAvailableEffectsList, mUsedEffectsView); } - void SpellCreationDialog::startSpellMaking (MWWorld::Ptr actor) + void SpellCreationDialog::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; mNameEdit->setCaption(""); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index d12115c88..76038abb4 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -153,7 +153,7 @@ namespace MWGui virtual void onOpen(); virtual void exit(); - void startSpellMaking(MWWorld::Ptr actor); + void setPtr(const MWWorld::Ptr& actor); protected: virtual void onReferenceUnavailable (); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ca0bb48e8..60abf4ac7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -115,7 +115,7 @@ namespace MWGui } } - void TradeWindow::startTrade(const MWWorld::Ptr& actor) + void TradeWindow::setPtr(const MWWorld::Ptr& actor) { mPtr = actor; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 4b03c8d90..984f5a394 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -27,7 +27,7 @@ namespace MWGui public: TradeWindow(); - void startTrade(const MWWorld::Ptr& actor); + void setPtr(const MWWorld::Ptr& actor); void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index d2e771918..3079adb6d 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -65,7 +65,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); } - void TrainingWindow::startTraining (MWWorld::Ptr actor) + void TrainingWindow::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 95a35be7f..e52a889ef 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -18,7 +18,7 @@ namespace MWGui virtual void exit(); - void startTraining(MWWorld::Ptr actor); + void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 3a7afe497..4c4dc436c 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -108,7 +108,7 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0)); } - void TravelWindow::startTravel(const MWWorld::Ptr& actor) + void TravelWindow::setPtr(const MWWorld::Ptr& actor) { center(); mPtr = actor; diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 3230f897f..529d5ebe1 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -26,7 +26,7 @@ namespace MWGui virtual void exit(); - void startTravel(const MWWorld::Ptr& actor); + void setPtr (const MWWorld::Ptr& actor); protected: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 400dc0ce4..73574ce7c 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -8,6 +8,11 @@ namespace MWBase class WindowManager; } +namespace MWWorld +{ + class Ptr; +} + namespace MWGui { class WindowManager; @@ -21,6 +26,9 @@ namespace MWGui // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + /// Open this object in the GUI, for windows that support it + virtual void setPtr(const MWWorld::Ptr& ptr) {} + /// Notify that window has been made visible virtual void onOpen() {} /// Notify that window has been hidden diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 81edc4a00..54ff8c30f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1207,24 +1207,31 @@ namespace MWGui void WindowManager::pushGuiMode(GuiMode mode) { - if (mode==GM_Inventory && mAllowed==GW_None) - return; + pushGuiMode(mode, MWWorld::Ptr()); + } - if (!mGuiModes.empty() && mGuiModes.back() == mode) + void WindowManager::pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg) + { + if (mode==GM_Inventory && mAllowed==GW_None) return; - // If this mode already exists somewhere in the stack, just bring it to the front. - if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + if (mGuiModes.empty() || mGuiModes.back() != mode) { - mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); - } + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } - if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(false); + if (!mGuiModes.empty()) + mGuiModeStates[mGuiModes.back()].update(false); - mGuiModes.push_back(mode); + mGuiModes.push_back(mode); - mGuiModeStates[mode].update(true); + mGuiModeStates[mode].update(true); + } + for (WindowBase* window : mGuiModeStates[mode].mWindows) + window->setPtr(arg); bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1543,52 +1550,11 @@ namespace MWGui mMap->addVisitedLocation (name, x, y); } - void WindowManager::startSpellMaking(MWWorld::Ptr actor) - { - pushGuiMode(GM_SpellCreation); - mSpellCreationDialog->startSpellMaking (actor); - } - - void WindowManager::startEnchanting (MWWorld::Ptr actor) - { - pushGuiMode(GM_Enchanting); - mEnchantingDialog->startEnchanting (actor); - } - - void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) - { - mEnchantingDialog->startSelfEnchanting(soulgem); - } - - void WindowManager::startTraining(MWWorld::Ptr actor) - { - pushGuiMode(GM_Training); - mTrainingWindow->startTraining(actor); - } - - void WindowManager::startRepair(MWWorld::Ptr actor) - { - pushGuiMode(GM_MerchantRepair); - mMerchantRepair->startRepair(actor); - } - - void WindowManager::startRepairItem(MWWorld::Ptr item) - { - pushGuiMode(MWGui::GM_Repair); - mRepair->startRepairItem(item); - } - const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; } - void WindowManager::showCompanionWindow(MWWorld::Ptr actor) - { - pushGuiMode(MWGui::GM_Companion); - mCompanionWindow->openCompanion(actor); - } - void WindowManager::changePointer(const std::string &name) { MyGUI::PointerManager::getInstance().setPointer(name); @@ -1642,11 +1608,6 @@ namespace MWGui return mLoadingScreen; } - void WindowManager::startRecharge(MWWorld::Ptr soulgem) - { - mRecharge->start(soulgem); - } - bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1996,53 +1957,12 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } - void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) - { - mConsole->setSelectedObject(object); - } - void WindowManager::updateSpellWindow() { if (mSpellWindow) mSpellWindow->updateSpells(); } - void WindowManager::startTravel(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_Travel); - mTravelWindow->startTravel(actor); - } - - void WindowManager::startSpellBuying(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_SpellBuying); - mSpellBuyingWindow->startSpellBuying(actor, 0); - } - - void WindowManager::startTrade(const MWWorld::Ptr &actor) - { - pushGuiMode(GM_Barter); - mTradeWindow->startTrade(actor); - } - - void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) - { - pushGuiMode(GM_Container); - mContainerWindow->openContainer(container, loot); - } - - void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) - { - pushGuiMode(GM_Book); - mBookWindow->openBook(item, showTakeButton); - } - - void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) - { - pushGuiMode(GM_Scroll); - mScrollWindow->openScroll(item, showTakeButton); - } - std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 524575c6a..c267f505a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -158,7 +158,8 @@ namespace MWGui virtual void setNewGame(bool newgame); - virtual void pushGuiMode(GuiMode mode); + virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg); + virtual void pushGuiMode (GuiMode mode); virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack @@ -196,8 +197,6 @@ namespace MWGui virtual void updateSpellWindow(); - virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); - ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); @@ -315,21 +314,6 @@ namespace MWGui virtual void updatePlayer(); - virtual void showCompanionWindow(MWWorld::Ptr actor); - virtual void startSpellMaking(MWWorld::Ptr actor); - virtual void startEnchanting(MWWorld::Ptr actor); - virtual void startSelfEnchanting(MWWorld::Ptr soulgem); - virtual void startTraining(MWWorld::Ptr actor); - virtual void startRepair(MWWorld::Ptr actor); - virtual void startRepairItem(MWWorld::Ptr item); - virtual void startRecharge(MWWorld::Ptr soulgem); - virtual void startTravel(const MWWorld::Ptr& actor); - virtual void startSpellBuying(const MWWorld::Ptr &actor); - virtual void startTrade(const MWWorld::Ptr &actor); - virtual void openContainer(const MWWorld::Ptr &container, bool loot); - virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); - virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); - virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 0df451b18..7ff6dd068 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -10,9 +10,8 @@ namespace MWWorld { - ActionOpen::ActionOpen (const MWWorld::Ptr& container, bool loot) + ActionOpen::ActionOpen (const MWWorld::Ptr& container) : Action (false, container) - , mLoot(loot) { } @@ -23,6 +22,6 @@ namespace MWWorld MWMechanics::diseaseContact(actor, getTarget()); - MWBase::Environment::get().getWindowManager()->openContainer(getTarget(), mLoot); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, getTarget()); } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 454cc09f1..3bce25c6b 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -12,12 +12,9 @@ namespace MWWorld virtual void executeImp (const MWWorld::Ptr& actor); public: - ActionOpen (const Ptr& container, bool loot=false); + ActionOpen (const Ptr& container); ///< \param container The Container the Player has activated. - /// \param loot If true, display the "dispose of corpse" button - private: - bool mLoot; }; } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index b3ac772ae..d2dc972fc 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -32,14 +32,12 @@ namespace MWWorld return; } - bool showTakeButton = (getTarget().getContainerStore() != &actor.getClass().getContainerStore(actor)); - LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) - MWBase::Environment::get().getWindowManager()->showScroll(getTarget(), showTakeButton); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll, getTarget()); else - MWBase::Environment::get().getWindowManager()->showBook(getTarget(), showTakeButton); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book, getTarget()); MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index 00a4756dd..c23bf2900 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -16,4 +16,4 @@ namespace MWWorld }; } -#endif // ACTIONOPEN_H +#endif // ACTIONREAD_H diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 8e19927b8..191cf2063 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -23,6 +23,6 @@ namespace MWWorld return; } - MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair, getTarget()); } } From bbafe1e4561fc54da1f240d9083b6592eb6f758d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 21:31:10 +0200 Subject: [PATCH 258/521] Remove redundant player cell variable --- apps/openmw/mwgui/referenceinterface.cpp | 10 ---------- apps/openmw/mwgui/referenceinterface.hpp | 5 +---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 9aaa98f19..6213d9e25 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -1,14 +1,8 @@ #include "referenceinterface.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" - -#include "../mwmechanics/actorutil.hpp" - namespace MWGui { ReferenceInterface::ReferenceInterface() - : mCurrentPlayerCell(NULL) { } @@ -18,8 +12,6 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - MWWorld::CellStore* playerCell = MWMechanics::getPlayer().getCell(); - // check if count of the reference has become 0 if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0) { @@ -29,7 +21,5 @@ namespace MWGui onReferenceUnavailable(); } } - - mCurrentPlayerCell = playerCell; } } diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp index 0ba180de8..6428a5b54 100644 --- a/apps/openmw/mwgui/referenceinterface.hpp +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -17,15 +17,12 @@ namespace MWGui void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable - virtual void resetReference() { mPtr = MWWorld::Ptr(); mCurrentPlayerCell = NULL; } + virtual void resetReference() { mPtr = MWWorld::Ptr(); } protected: virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable MWWorld::Ptr mPtr; - - private: - MWWorld::CellStore* mCurrentPlayerCell; }; } From 269094ba8d84945de1b86b40c4c9db81fe46efbf Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 23:01:34 +0200 Subject: [PATCH 259/521] Restore the previous key focus widget when exiting modal dialog --- apps/openmw/mwgui/windowbase.cpp | 5 +++-- apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 8 ++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index 5ed564737..e563d9aa9 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -67,14 +67,15 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::onOpen() { - MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + // Order important. We need to save the key focus widget before its unset MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed + MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); } void WindowModal::onClose() { - MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); } NoDrop::NoDrop(DragAndDrop *drag, MyGUI::Widget *widget) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 54ff8c30f..2d17db643 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,7 @@ namespace MWGui , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) + , mSaveKeyFocus(NULL) , mCurrentModals() , mHud(NULL) , mMap(NULL) @@ -260,6 +262,8 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + MyGUI::WidgetManager::getInstance().registerUnlinker(this); + // Create all cursors in advance createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); @@ -496,6 +500,8 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); + delete mConsole; delete mMessageBoxManager; delete mHud; @@ -1608,6 +1614,12 @@ namespace MWGui return mLoadingScreen; } + void WindowManager::_unlinkWidget(MyGUI::Widget *widget) + { + if (widget == mSaveKeyFocus) + mSaveKeyFocus = NULL; + } + bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1818,6 +1830,17 @@ namespace MWGui { if (!mCurrentModals.empty()) mCurrentModals.top()->exit(); + + if (mCurrentModals.empty()) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + } + + void WindowManager::addCurrentModal(WindowModal *input) + { + if (mCurrentModals.empty()) + mSaveKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + mCurrentModals.push(input); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1827,6 +1850,9 @@ namespace MWGui if(!mCurrentModals.empty()) if(input == mCurrentModals.top()) mCurrentModals.pop(); + + if (mCurrentModals.empty()) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c267f505a..18ece21f9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -124,7 +124,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; - class WindowManager : public MWBase::WindowManager + class WindowManager : public MWBase::WindowManager, MyGUI::IUnlinkWidget { public: typedef std::pair Faction; @@ -142,6 +142,8 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); + void _unlinkWidget(MyGUI::Widget* widget); + /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); @@ -341,7 +343,7 @@ namespace MWGui /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ - virtual void addCurrentModal(WindowModal* input) {mCurrentModals.push(input);} + virtual void addCurrentModal(WindowModal* input); /// Removes the top Modal /** Used when one Modal adds another Modal @@ -404,6 +406,8 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; + MyGUI::Widget* mSaveKeyFocus; + std::stack mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). From 531e7ac58677dc44fe94c433d2d979caed8710dc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 22 Sep 2017 23:25:20 +0200 Subject: [PATCH 260/521] Allow drag-and-drop to be cancelled (Esc or Inventory key) --- apps/openmw/mwgui/draganddrop.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 14 +++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fa17d974d..fe0ad3374 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -125,6 +125,8 @@ void DragAndDrop::finish() { mIsOnDragAndDrop = false; mSourceSortModel->clearDragItems(); + // since mSourceView doesn't get updated in drag() + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); MyGUI::Gui::getInstance().destroyWidget(mDraggedWidget); mDraggedWidget = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2d17db643..4964af7d8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -755,7 +755,14 @@ namespace MWGui mGarbageDialogs.push_back(dialog); } - void WindowManager::exitCurrentGuiMode() { + void WindowManager::exitCurrentGuiMode() + { + if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->finish(); + return; + } + switch(mGuiModes.back()) { case GM_QuickKeysMenu: mQuickKeysMenu->exit(); @@ -1247,6 +1254,11 @@ namespace MWGui void WindowManager::popGuiMode() { + if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) + { + mDragAndDrop->finish(); + } + if (!mGuiModes.empty()) { mGuiModeStates[mGuiModes.back()].update(false); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 33f1edb6c..3ed259c58 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -177,13 +177,13 @@ namespace MWInput void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { - if (mDragDrop) - return; - resetIdleTime (); int action = channel->getNumber(); + if (mDragDrop && action != A_GameMenu && action != A_Inventory) + return; + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) { //Is a normal button press, so don't change it at all From 20766fb508f6f4a286a786f1b2d63225de11fd8a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 00:00:40 +0200 Subject: [PATCH 261/521] Associate open/close sounds with the GUI mode --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwgui/bookwindow.cpp | 5 ----- apps/openmw/mwgui/scrollwindow.cpp | 7 +------ apps/openmw/mwgui/windowmanagerimp.cpp | 18 ++++++++++++++---- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++-- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 242f358a9..243ec3ccf 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -117,9 +117,9 @@ namespace MWBase virtual void pushGuiMode (MWGui::GuiMode mode, const MWWorld::Ptr& arg) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; - virtual void popGuiMode() = 0; + virtual void popGuiMode(bool noSound=false) = 0; - virtual void removeGuiMode (MWGui::GuiMode mode) = 0; + virtual void removeGuiMode (MWGui::GuiMode mode, bool noSound=false) = 0; ///< can be anywhere in the stack virtual void goToJail(int days) = 0; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ca697d0b6..7cabf68b1 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -85,8 +85,6 @@ namespace MWGui clearPages(); mCurrentPage = 0; - MWBase::Environment::get().getWindowManager()->playSound("book open"); - MWWorld::LiveCellRef *ref = mBook.get(); Formatting::BookFormatter formatter; @@ -100,9 +98,6 @@ namespace MWGui void BookWindow::exit() { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getWindowManager()->playSound("book close"); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 3649afe23..ccbd1d7c0 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -52,9 +52,6 @@ namespace MWGui void ScrollWindow::setPtr (const MWWorld::Ptr& scroll) { - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getWindowManager()->playSound("scroll"); - mScroll = scroll; MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -81,8 +78,6 @@ namespace MWGui void ScrollWindow::exit() { - MWBase::Environment::get().getWindowManager()->playSound("scroll"); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } @@ -110,6 +105,6 @@ namespace MWGui MWWorld::ActionTake take(mScroll); take.execute (MWMechanics::getPlayer()); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll, true); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4964af7d8..70b95351b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -354,6 +354,8 @@ namespace MWGui bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); mJournal = JournalWindow::create(JournalViewModel::create (), questList); mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + mGuiModeStates[GM_Journal].mCloseSound = "book close"; + mGuiModeStates[GM_Journal].mOpenSound = "book open"; mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); mSpellBuyingWindow = new SpellBuyingWindow(); @@ -374,9 +376,13 @@ namespace MWGui mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); + mGuiModeStates[GM_Scroll].mOpenSound = "scroll"; + mGuiModeStates[GM_Scroll].mCloseSound = "scroll"; mBookWindow = new BookWindow(); mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); + mGuiModeStates[GM_Book].mOpenSound = "book open"; + mGuiModeStates[GM_Book].mCloseSound = "book close"; mCountDialog = new CountDialog(); mSettingsWindow = new SettingsWindow(); @@ -840,7 +846,6 @@ namespace MWGui mRepair->exit(); break; case GM_Journal: - playSound("book close"); removeGuiMode(GM_Journal); //Simple way to remove it break; default: @@ -1242,6 +1247,7 @@ namespace MWGui mGuiModes.push_back(mode); mGuiModeStates[mode].update(true); + playSound(mGuiModeStates[mode].mOpenSound); } for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); @@ -1252,7 +1258,7 @@ namespace MWGui updateVisible(); } - void WindowManager::popGuiMode() + void WindowManager::popGuiMode(bool noSound) { if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop) { @@ -1262,6 +1268,8 @@ namespace MWGui if (!mGuiModes.empty()) { mGuiModeStates[mGuiModes.back()].update(false); + if (!noSound) + playSound(mGuiModeStates[mGuiModes.back()].mCloseSound); mGuiModes.pop_back(); } @@ -1274,11 +1282,11 @@ namespace MWGui updateVisible(); } - void WindowManager::removeGuiMode(GuiMode mode) + void WindowManager::removeGuiMode(GuiMode mode, bool noSound) { if (!mGuiModes.empty() && mGuiModes.back() == mode) { - popGuiMode(); + popGuiMode(noSound); return; } @@ -1992,6 +2000,8 @@ namespace MWGui void WindowManager::playSound(const std::string& soundId, float volume, float pitch) { + if (soundId.empty()) + return; MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 18ece21f9..9fa921a4c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -162,8 +162,8 @@ namespace MWGui virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg); virtual void pushGuiMode (GuiMode mode); - virtual void popGuiMode(); - virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + virtual void popGuiMode(bool noSound=false); + virtual void removeGuiMode(GuiMode mode, bool noSound=false); ///< can be anywhere in the stack virtual void goToJail(int days); @@ -497,6 +497,9 @@ namespace MWGui std::vector mWindows; std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. + + std::string mCloseSound; + std::string mOpenSound; }; // Defines the windows that should be shown in a particular GUI mode. std::map mGuiModeStates; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3ed259c58..cf42db04b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1039,12 +1039,10 @@ namespace MWInput && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { - MWBase::Environment::get().getWindowManager()->playSound ("book open"); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal); } else if(MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Journal)) { - MWBase::Environment::get().getWindowManager()->playSound ("book close"); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Journal); } } From 4fff2e2e34eeac62f7c510e63085bf8c676785d9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:18:39 +0200 Subject: [PATCH 262/521] Refactor exitCurrentGuiMode --- apps/openmw/mwgui/alchemywindow.cpp | 9 +- apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/birth.hpp | 2 + apps/openmw/mwgui/bookwindow.cpp | 7 +- apps/openmw/mwgui/bookwindow.hpp | 2 - apps/openmw/mwgui/class.cpp | 9 +- apps/openmw/mwgui/class.hpp | 14 ++- apps/openmw/mwgui/companionwindow.cpp | 9 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 7 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/console.cpp | 5 - apps/openmw/mwgui/console.hpp | 2 - apps/openmw/mwgui/container.cpp | 10 +- apps/openmw/mwgui/container.hpp | 2 - apps/openmw/mwgui/countdialog.cpp | 12 +-- apps/openmw/mwgui/countdialog.hpp | 2 - apps/openmw/mwgui/dialogue.cpp | 16 ++-- apps/openmw/mwgui/dialogue.hpp | 3 +- apps/openmw/mwgui/enchantingdialog.cpp | 7 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 - apps/openmw/mwgui/itemselection.cpp | 3 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwgui/jailscreen.hpp | 2 + apps/openmw/mwgui/mapwindow.cpp | 5 - apps/openmw/mwgui/mapwindow.hpp | 1 - apps/openmw/mwgui/merchantrepair.cpp | 7 +- apps/openmw/mwgui/merchantrepair.hpp | 2 - apps/openmw/mwgui/quickkeysmenu.cpp | 13 +-- apps/openmw/mwgui/quickkeysmenu.hpp | 5 +- apps/openmw/mwgui/race.hpp | 2 + apps/openmw/mwgui/recharge.cpp | 7 +- apps/openmw/mwgui/recharge.hpp | 2 - apps/openmw/mwgui/repair.cpp | 7 +- apps/openmw/mwgui/repair.hpp | 2 - apps/openmw/mwgui/review.hpp | 2 + apps/openmw/mwgui/savegamedialog.cpp | 7 +- apps/openmw/mwgui/savegamedialog.hpp | 2 - apps/openmw/mwgui/scrollwindow.cpp | 7 +- apps/openmw/mwgui/scrollwindow.hpp | 1 - apps/openmw/mwgui/settingswindow.cpp | 7 +- apps/openmw/mwgui/settingswindow.hpp | 2 - apps/openmw/mwgui/spellbuyingwindow.cpp | 7 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 - apps/openmw/mwgui/spellcreationdialog.cpp | 12 +-- apps/openmw/mwgui/spellcreationdialog.hpp | 3 +- apps/openmw/mwgui/textinput.hpp | 2 + apps/openmw/mwgui/tradewindow.cpp | 5 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 7 +- apps/openmw/mwgui/trainingwindow.hpp | 2 - apps/openmw/mwgui/travelwindow.cpp | 7 +- apps/openmw/mwgui/travelwindow.hpp | 2 - apps/openmw/mwgui/waitdialog.cpp | 5 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/windowbase.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 110 +++++----------------- 57 files changed, 101 insertions(+), 284 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index c68bad02a..5b1489821 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -59,7 +59,7 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -103,6 +103,7 @@ namespace MWGui void AlchemyWindow::onOpen() { + mAlchemy->clear(); mAlchemy->setAlchemist (MWMechanics::getPlayer()); InventoryItemModel* model = new InventoryItemModel(MWMechanics::getPlayer()); @@ -129,12 +130,6 @@ namespace MWGui update(); } - void AlchemyWindow::exit() { - mAlchemy->clear(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); - } - void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) { removeIngredient(_sender); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 8b7bcaaca..8dffaaad1 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -25,7 +25,6 @@ namespace MWGui AlchemyWindow(); virtual void onOpen(); - virtual void exit(); private: std::string mSuggestedPotionName; diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index c13d49838..86af14286 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -22,6 +22,8 @@ namespace MWGui void setNextButtonShow(bool shown); virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 7cabf68b1..5abc63c55 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -96,11 +96,6 @@ namespace MWGui setTakeButtonShow(showTakeButton); } - void BookWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); - } - void BookWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -115,7 +110,7 @@ namespace MWGui void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index e8a1a42ff..4f7224ea8 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -14,8 +14,6 @@ namespace MWGui public: BookWindow(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 2278b5141..c63d470d7 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -730,9 +730,10 @@ namespace MWGui exit(); } - void SelectSpecializationDialog::exit() + bool SelectSpecializationDialog::exit() { eventCancel(); + return true; } /* SelectAttributeDialog */ @@ -778,9 +779,10 @@ namespace MWGui exit(); } - void SelectAttributeDialog::exit() + bool SelectAttributeDialog::exit() { eventCancel(); + return true; } @@ -869,9 +871,10 @@ namespace MWGui exit(); } - void SelectSkillDialog::exit() + bool SelectSkillDialog::exit() { eventCancel(); + return true; } /* DescriptionDialog */ diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 2b205d12f..3a2573fd4 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -23,6 +23,8 @@ namespace MWGui virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -67,6 +69,8 @@ namespace MWGui std::string getClassId() const; void setClassId(const std::string &classId); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -102,6 +106,8 @@ namespace MWGui void setNextButtonShow(bool shown); virtual void onOpen(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -142,7 +148,7 @@ namespace MWGui SelectSpecializationDialog(); ~SelectSpecializationDialog(); - virtual void exit(); + virtual bool exit(); ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } @@ -175,7 +181,7 @@ namespace MWGui SelectAttributeDialog(); ~SelectAttributeDialog(); - virtual void exit(); + virtual bool exit(); ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } @@ -206,7 +212,7 @@ namespace MWGui SelectSkillDialog(); ~SelectSkillDialog(); - virtual void exit(); + virtual bool exit(); ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } @@ -262,6 +268,8 @@ namespace MWGui CreateClassDialog(); virtual ~CreateClassDialog(); + bool exit() { return false; } + std::string getName() const; std::string getDescription() const; ESM::Class::Specialization getSpecializationId() const; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 07753ab11..c4e50c8c2 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -139,10 +139,11 @@ void CompanionWindow::updateEncumbranceBar() void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - exit(); + if (exit()) + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); } -void CompanionWindow::exit() +bool CompanionWindow::exit() { if (mModel && mModel->hasProfit(mPtr) && getProfit(mPtr) < 0) { @@ -151,9 +152,9 @@ void CompanionWindow::exit() buttons.push_back("#{sCompanionWarningButtonTwo}"); mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons); mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked); + return false; } - else - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); + return true; } void CompanionWindow::onMessageBoxButtonClicked(int button) diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index ec70146f2..fd66cfa80 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -18,7 +18,7 @@ namespace MWGui public: CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); - virtual void exit(); + virtual bool exit(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index f3a06f245..697d90862 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -46,15 +46,16 @@ namespace MWGui center(); } - void ConfirmationDialog::exit() + bool ConfirmationDialog::exit() { - setVisible(false); - eventCancelClicked(); + return true; } void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { + setVisible(false); + exit(); } diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 745c7a1a5..259579376 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -11,7 +11,7 @@ namespace MWGui ConfirmationDialog(); void askForConfirmation(const std::string& message); void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); - virtual void exit(); + virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 55a03bafd..182b6ef97 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -159,11 +159,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); } - void Console::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Console); - } - void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 927fdd5fe..6257b5617 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -42,8 +42,6 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); - virtual void exit(); - void setFont(const std::string &fntName); void onResChange(int width, int height); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6ea2e3e9a..85afc1aa3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -198,17 +198,9 @@ namespace MWGui } } - void ContainerWindow::exit() - { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); - } - } - void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 2758f57c9..3ae73a01f 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -38,8 +38,6 @@ namespace MWGui virtual void resetReference(); - virtual void exit(); - private: DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 03cf1cab6..cf058caac 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -56,19 +56,9 @@ namespace MWGui mItemEdit->setValue(maxCount); } - void CountDialog::cancel() //Keeping this here as I don't know if anything else relies on it. - { - exit(); - } - - void CountDialog::exit() - { - setVisible(false); - } - void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { - cancel(); + setVisible(false); } void CountDialog::onOkButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 7014b5fad..766612f68 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -15,8 +15,6 @@ namespace MWGui public: CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); - void cancel(); - virtual void exit(); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d2d97a437..48d291325 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -52,7 +52,7 @@ namespace MWGui void PersuasionDialog::onCancel(MyGUI::Widget *sender) { - exit(); + setVisible(false); } void PersuasionDialog::onPersuade(MyGUI::Widget *sender) @@ -88,11 +88,6 @@ namespace MWGui mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); } - void PersuasionDialog::exit() - { - setVisible(false); - } - // -------------------------------------------------------------------------------------------------- Response::Response(const std::string &text, const std::string &title, bool needMargin) @@ -275,18 +270,18 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } - void DialogueWindow::exit() + bool DialogueWindow::exit() { if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) && !mGoodbye) { - // in choice, not allowed to escape, but give access to main menu to allow loading other saves - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + return false; } else { MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); mTopicsList->scrollToTop(); + return true; } } @@ -311,7 +306,8 @@ namespace MWGui void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - exit(); + if (exit()) + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void DialogueWindow::onSelectTopic(const std::string& topic, int id) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 682baef3c..12e2328f4 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -29,7 +29,6 @@ namespace MWGui PersuasionDialog(); virtual void onOpen(); - virtual void exit(); private: MyGUI::Button* mCancelButton; @@ -100,7 +99,7 @@ namespace MWGui public: DialogueWindow(); - virtual void exit(); + virtual bool exit(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 94e8b329d..88973bd46 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -100,11 +100,6 @@ namespace MWGui } } - void EnchantingDialog::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); - } - void EnchantingDialog::updateLabels() { std::stringstream enchantCost; @@ -194,7 +189,7 @@ namespace MWGui void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Enchanting); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 41d6382cc..ace63ae5c 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -21,8 +21,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 095f392b7..effd11d55 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -29,9 +29,10 @@ namespace MWGui center(); } - void ItemSelectionDialog::exit() + bool ItemSelectionDialog::exit() { eventDialogCanceled(); + return true; } void ItemSelectionDialog::openContainer(const MWWorld::Ptr& container) diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 50e15a3fe..07b6452a5 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -21,7 +21,7 @@ namespace MWGui public: ItemSelectionDialog(const std::string& label); - virtual void exit(); + virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/jailscreen.hpp b/apps/openmw/mwgui/jailscreen.hpp index 7a544126d..36d19b5a9 100644 --- a/apps/openmw/mwgui/jailscreen.hpp +++ b/apps/openmw/mwgui/jailscreen.hpp @@ -14,6 +14,8 @@ namespace MWGui void onFrame(float dt); + bool exit() { return false; } + private: int mDays; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 7bc66fab4..8c7ec6bfe 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1114,11 +1114,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } - void EditNoteDialog::exit() - { - setVisible(false); - } - void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget *sender) { setVisible(false); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index eae1cec7e..ed6e4874f 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -170,7 +170,6 @@ namespace MWGui EditNoteDialog(); virtual void onOpen(); - virtual void exit(); void showDeleteButton(bool show); bool getDeleteButtonShown(); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 785b5ee48..d3504ebc3 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -118,11 +118,6 @@ void MerchantRepair::onOpen() mList->setViewOffset(MyGUI::IntPoint(0, 0)); } -void MerchantRepair::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); -} - void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) { MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -150,7 +145,7 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 76ccd28cc..4e4e7164f 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -14,8 +14,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& actor); private: diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 19dd6fa03..6da7b0905 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -64,11 +64,6 @@ namespace MWGui } } - void QuickKeysMenu::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu); - } - void QuickKeysMenu::clear() { mActivatedIndex = -1; @@ -449,11 +444,6 @@ namespace MWGui center(); } - void QuickKeysMenuAssign::exit() - { - setVisible(false); - } - void QuickKeysMenu::write(ESM::ESMWriter &writer) { writer.startRecord(ESM::REC_KEYS); @@ -585,9 +575,10 @@ namespace MWGui exit(); } - void MagicSelectionDialog::exit() + bool MagicSelectionDialog::exit() { mParent->onAssignMagicCancel(); + return true; } void MagicSelectionDialog::onOpen () diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d07cdef3d..c99d482ee 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -22,8 +22,6 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); - virtual void exit(); - void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); void onUnassignButtonClicked(MyGUI::Widget* sender); @@ -77,7 +75,6 @@ namespace MWGui { public: QuickKeysMenuAssign(QuickKeysMenu* parent); - virtual void exit(); private: MyGUI::TextBox* mLabel; @@ -95,7 +92,7 @@ namespace MWGui MagicSelectionDialog(QuickKeysMenu* parent); virtual void onOpen(); - virtual void exit(); + virtual bool exit(); private: MyGUI::Button* mCancelButton; diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 911bce577..c9e31d42d 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -54,6 +54,8 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); + bool exit() { return false; } + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 54473746a..0398112ba 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -62,11 +62,6 @@ void Recharge::onOpen() mBox->resetScrollbars(); } -void Recharge::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); -} - void Recharge::setPtr (const MWWorld::Ptr &item) { mGemIcon->setItem(item); @@ -107,7 +102,7 @@ void Recharge::updateView() void Recharge::onCancel(MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); } void Recharge::onSelectItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 93f86ab65..f4602ce30 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -24,8 +24,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& gem); protected: diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 295b8254b..a461f7b3d 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -58,11 +58,6 @@ void Repair::onOpen() mRepairBox->resetScrollbars(); } -void Repair::exit() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); -} - void Repair::setPtr(const MWWorld::Ptr &item) { MWBase::Environment::get().getWindowManager()->playSound("Item Repair Up"); @@ -145,7 +140,7 @@ void Repair::onItemCancel() void Repair::onCancel(MyGUI::Widget* /*sender*/) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index a2573d780..f31625095 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -21,8 +21,6 @@ public: virtual void onOpen(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& item); protected: diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 34dd5a7d4..8e9ec0ec7 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -31,6 +31,8 @@ namespace MWGui ReviewDialog(); + bool exit() { return false; } + void setPlayerName(const std::string &name); void setRace(const std::string &raceId); void setClass(const ESM::Class& class_); diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 7a4c3a22e..e7c27b268 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -191,11 +191,6 @@ namespace MWGui } - void SaveGameDialog::exit() - { - setVisible(false); - } - void SaveGameDialog::setLoadOrSave(bool load) { mSaving = !load; @@ -217,7 +212,7 @@ namespace MWGui void SaveGameDialog::onCancelButtonClicked(MyGUI::Widget *sender) { - exit(); + setVisible(false); } void SaveGameDialog::onDeleteButtonClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 2a49cf48a..39e3d310a 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -19,8 +19,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setLoadOrSave(bool load); private: diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index ccbd1d7c0..a92ef92ab 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -76,11 +76,6 @@ namespace MWGui setTakeButtonShow(showTakeButton); } - void ScrollWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); - } - void ScrollWindow::setTakeButtonShow(bool show) { mTakeButtonShow = show; @@ -95,7 +90,7 @@ namespace MWGui void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 5ae8e972a..596db06ad 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -18,7 +18,6 @@ namespace MWGui ScrollWindow (); void setPtr (const MWWorld::Ptr& scroll); - virtual void exit(); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 4e8547d33..c239fc12f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -258,7 +258,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -559,11 +559,6 @@ namespace MWGui resetScrollbars(); } - void SettingsWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); - } - void SettingsWindow::onWindowResize(MyGUI::Window *_sender) { layoutControlsBox(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 447331574..4f8607fda 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -17,8 +17,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void updateControlsBox(); protected: diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 592316274..aeb5cfbe5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -31,11 +31,6 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); } - void SpellBuyingWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); - } - bool SpellBuyingWindow::sortSpells (const ESM::Spell* left, const ESM::Spell* right) { std::string leftName = Misc::StringUtils::lowerCase(left->mName); @@ -173,7 +168,7 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellBuying); } void SpellBuyingWindow::updateLabels() diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index b96896e4c..01cc6c2f9 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,8 +28,6 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void setPtr(const MWWorld::Ptr& actor, int startOffset); - virtual void exit(); - protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d5982a174..8d0639d25 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -102,13 +102,13 @@ namespace MWGui center(); } - void EditEffectDialog::exit() + bool EditEffectDialog::exit() { - setVisible(false); if(mEditing) eventEffectModified(mOldEffect); else eventEffectRemoved(mEffect); + return true; } void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) @@ -275,6 +275,7 @@ namespace MWGui void EditEffectDialog::onCancelButtonClicked (MyGUI::Widget* sender) { + setVisible(false); exit(); } @@ -362,7 +363,7 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) @@ -420,11 +421,6 @@ namespace MWGui center(); } - void SpellCreationDialog::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); - } - void SpellCreationDialog::onReferenceUnavailable () { MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 76038abb4..f7bb8a101 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -24,7 +24,7 @@ namespace MWGui EditEffectDialog(); virtual void onOpen(); - virtual void exit(); + virtual bool exit(); void setConstantEffect(bool constant); @@ -151,7 +151,6 @@ namespace MWGui SpellCreationDialog(); virtual void onOpen(); - virtual void exit(); void setPtr(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index ccfa19c87..56c6632e1 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -22,6 +22,8 @@ namespace MWGui void setTextLabel(const std::string &label); virtual void onOpen(); + bool exit() { return false; } + /** Event : Dialog finished, OK button clicked.\n signature : void method()\n */ diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 60abf4ac7..2a6c61a16 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -171,11 +171,11 @@ namespace MWGui return mPtr.getClass().getServices(mPtr); } - void TradeWindow::exit() + bool TradeWindow::exit() { mTradeModel->abort(); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel()->abort(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + return true; } void TradeWindow::onItemSelected (int index) @@ -362,6 +362,7 @@ namespace MWGui void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 984f5a394..55164b934 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -34,7 +34,7 @@ namespace MWGui int getMerchantServices(); - virtual void exit(); + virtual bool exit(); virtual void resetReference(); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 3079adb6d..ca6f2246e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -60,11 +60,6 @@ namespace MWGui center(); } - void TrainingWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - } - void TrainingWindow::setPtr (const MWWorld::Ptr& actor) { mPtr = actor; @@ -124,7 +119,7 @@ namespace MWGui void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index e52a889ef..d4785194a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,8 +16,6 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); - void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 4c4dc436c..02df6bd8e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -45,11 +45,6 @@ namespace MWGui mSelect->getHeight()); } - void TravelWindow::exit() - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - } - void TravelWindow::addDestination(const std::string& name,ESM::Position pos,bool interior) { int price; @@ -194,7 +189,7 @@ namespace MWGui void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); } void TravelWindow::updateLabels() diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 529d5ebe1..5ae466047 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -24,8 +24,6 @@ namespace MWGui public: TravelWindow(); - virtual void exit(); - void setPtr (const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 476d19bd6..b39b1a8ab 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -79,10 +79,9 @@ namespace MWGui mProgressBar.setVisible (false); } - void WaitDialog::exit() + bool WaitDialog::exit() { - if(!mProgressBar.isVisible()) //Only exit if not currently waiting - MWBase::Environment::get().getWindowManager()->popGuiMode(); + return (!mProgressBar.isVisible()); //Only exit if not currently waiting } void WaitDialog::onOpen() diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 829659d16..9bf8279be 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -29,7 +29,7 @@ namespace MWGui virtual void onOpen(); - virtual void exit(); + virtual bool exit(); void onFrame(float dt); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 73574ce7c..e6817358f 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -34,7 +34,7 @@ namespace MWGui /// Notify that window has been hidden virtual void onClose () {} /// Gracefully exits the window - virtual void exit() {} + virtual bool exit() {return true;} /// Sets the visibility of the window virtual void setVisible(bool visible); /// Returns the visibility state of the window @@ -52,7 +52,7 @@ namespace MWGui WindowModal(const std::string& parLayout); virtual void onOpen(); virtual void onClose(); - virtual void exit() {} + virtual bool exit() {return true;} }; /// A window that cannot be the target of a drag&drop action. diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 70b95351b..31a072fd1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -769,89 +769,19 @@ namespace MWGui return; } - switch(mGuiModes.back()) { - case GM_QuickKeysMenu: - mQuickKeysMenu->exit(); - break; - case GM_MainMenu: - removeGuiMode(GM_MainMenu); //Simple way to remove it - break; - case GM_Settings: - mSettingsWindow->exit(); - break; - case GM_Console: - mConsole->exit(); - break; - case GM_Scroll: - mScrollWindow->exit(); - break; - case GM_Book: - mBookWindow->exit(); - break; - case GM_Alchemy: - mAlchemyWindow->exit(); - break; - case GM_Rest: - mWaitDialog->exit(); - break; - case GM_RestBed: - mWaitDialog->exit(); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - break; - case GM_Inventory: - removeGuiMode(GM_Inventory); //Simple way to remove it - break; - case GM_Container: - mContainerWindow->exit(); - break; - case GM_Companion: - mCompanionWindow->exit(); - break; - case GM_Dialogue: - mDialogueWindow->exit(); - break; - case GM_Barter: - mTradeWindow->exit(); - break; - case GM_SpellBuying: - mSpellBuyingWindow->exit(); - break; - case GM_Travel: - mTravelWindow->exit(); - break; - case GM_SpellCreation: - mSpellCreationDialog->exit(); - break; - case GM_Recharge: - mRecharge->exit(); - break; - case GM_Enchanting: - mEnchantingDialog->exit(); - break; - case GM_Training: - mTrainingWindow->exit(); - break; - case GM_MerchantRepair: - mMerchantRepair->exit(); - break; - case GM_Repair: - mRepair->exit(); - break; - case GM_Journal: - removeGuiMode(GM_Journal); //Simple way to remove it - break; - default: - // Unsupported mode, switch back to game - break; + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + for (WindowBase* window : state.mWindows) + { + if (!window->exit()) + { + // unable to exit window, but give access to main menu + if (!MyGUI::InputManager::getInstance().isModalAny()) + pushGuiMode (MWGui::GM_MainMenu); + return; + } } + + popGuiMode(); } void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) @@ -1267,10 +1197,11 @@ namespace MWGui if (!mGuiModes.empty()) { - mGuiModeStates[mGuiModes.back()].update(false); - if (!noSound) - playSound(mGuiModeStates[mGuiModes.back()].mCloseSound); + const GuiMode mode = mGuiModes.back(); mGuiModes.pop_back(); + mGuiModeStates[mode].update(false); + if (!noSound) + playSound(mGuiModeStates[mode].mCloseSound); } if (!mGuiModes.empty()) @@ -1849,10 +1780,11 @@ namespace MWGui void WindowManager::exitCurrentModal() { if (!mCurrentModals.empty()) - mCurrentModals.top()->exit(); - - if (mCurrentModals.empty()) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + { + if (!mCurrentModals.top()->exit()) + return; + mCurrentModals.top()->setVisible(false); + } } void WindowManager::addCurrentModal(WindowModal *input) From be19f51013ece60db26a860388778c1b5b6f103c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:55:28 +0200 Subject: [PATCH 263/521] Adjust some more windows to be keyboard friendlier --- apps/openmw/mwgui/birth.cpp | 1 + apps/openmw/mwgui/class.cpp | 1 + apps/openmw/mwgui/dialogue.cpp | 3 +++ apps/openmw/mwgui/race.cpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.cpp | 1 + apps/openmw/mwgui/spellview.cpp | 1 + files/mygui/openmw_inventory_window.layout | 5 +++++ files/mygui/openmw_trade_window.layout | 5 +++++ 8 files changed, 19 insertions(+) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index b4a6b7d2f..92f29e3ef 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -69,6 +69,7 @@ namespace MWGui WindowModal::onOpen(); updateBirths(); updateSpells(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList); } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c63d470d7..33daa0ad1 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -130,6 +130,7 @@ namespace MWGui WindowModal::onOpen (); updateClasses(); updateStats(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 48d291325..2effcc700 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -526,7 +526,10 @@ namespace MWGui } bool goodbyeEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() || mGoodbye; + bool goodbyeWasEnabled = mGoodbyeButton->getEnabled(); mGoodbyeButton->setEnabled(goodbyeEnabled); + if (goodbyeEnabled && !goodbyeWasEnabled) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye; mTopicsList->setEnabled(topicsEnabled); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 374a5d3d8..2b407ac93 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -163,6 +163,8 @@ namespace MWGui size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10; mHeadRotate->setScrollPosition(initialPos); onHeadRotate(mHeadRotate, initialPos); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mRaceList); } void RaceDialog::setRaceId(const std::string &raceId) diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8d0639d25..d5dee1139 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -419,6 +419,7 @@ namespace MWGui void SpellCreationDialog::onOpen() { center(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); } void SpellCreationDialog::onReferenceUnavailable () diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index ebda8873c..4268b33a0 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -106,6 +106,7 @@ namespace MWGui Gui::SharedStateButton* t = mScrollView->createWidget(skin, MyGUI::IntCoord(0, 0, 0, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); + t->setNeedKeyFocus(true); t->setCaption(spell.mName); t->setTextAlign(MyGUI::Align::Left); adjustSpellWidget(spell, i, t); diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index bb707fa0d..6221799b5 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -32,18 +32,23 @@ + + + + + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index f9f24581f..d1f31c475 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -9,18 +9,23 @@ + + + + + From ad4b91131f998253bf3fedca03f405c79dcc3d11 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 12:58:28 +0200 Subject: [PATCH 264/521] toggleGui renamed to toggleHud, remove unused variable --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ++--- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwscript/guiextensions.cpp | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 243ec3ccf..190768f26 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -229,7 +229,7 @@ namespace MWBase virtual void showCrosshair(bool show) = 0; virtual bool getSubtitlesEnabled() = 0; - virtual bool toggleGui() = 0; + virtual bool toggleHud() = 0; virtual void disallowMouse() = 0; virtual void allowMouse() = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 31a072fd1..2c58336da 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -190,7 +190,6 @@ namespace MWGui , mHitFaderEnabled(Settings::Manager::getBool ("hit fader", "GUI")) , mWerewolfOverlayEnabled(Settings::Manager::getBool ("werewolf overlay", "GUI")) , mHudEnabled(true) - , mGuiEnabled(true) , mCursorVisible(true) , mPlayerName() , mPlayerRaceId() @@ -450,7 +449,7 @@ namespace MWGui mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); - mHud->setVisible(mHudEnabled); + mHud->setVisible(true); mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); @@ -598,8 +597,8 @@ namespace MWGui bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper); - mHud->setVisible(mHudEnabled && mGuiEnabled && !loading); - mToolTips->setVisible(mGuiEnabled && !loading); + mHud->setVisible(mHudEnabled && !loading); + mToolTips->setVisible(mHudEnabled && !loading); bool gameMode = !isGuiMode(); @@ -1477,11 +1476,11 @@ namespace MWGui return mSubtitlesEnabled; } - bool WindowManager::toggleGui() + bool WindowManager::toggleHud() { - mGuiEnabled = !mGuiEnabled; + mHudEnabled = !mHudEnabled; updateVisible(); - return mGuiEnabled; + return mHudEnabled; } bool WindowManager::getRestEnabled() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 9fa921a4c..17707d2c3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -260,8 +260,8 @@ namespace MWGui virtual void showCrosshair(bool show); virtual bool getSubtitlesEnabled(); - /// Turn visibility of *all* GUI elements on or off (HUD and all windows, except the console) - virtual bool toggleGui(); + /// Turn visibility of HUD on or off + virtual bool toggleHud(); virtual void disallowMouse(); virtual void allowMouse(); @@ -468,7 +468,6 @@ namespace MWGui bool mHitFaderEnabled; bool mWerewolfOverlayEnabled; bool mHudEnabled; - bool mGuiEnabled; bool mCursorVisible; void setCursorVisible(bool visible); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf42db04b..cd17c5175 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -289,7 +289,7 @@ namespace MWInput showQuickKeysMenu(); break; case A_ToggleHUD: - MWBase::Environment::get().getWindowManager()->toggleGui(); + MWBase::Environment::get().getWindowManager()->toggleHud(); break; case A_ToggleDebug: MWBase::Environment::get().getWindowManager()->toggleDebugWindow(); diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 254da56d6..6f2c146b1 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -209,7 +209,7 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - bool state = MWBase::Environment::get().getWindowManager()->toggleGui(); + bool state = MWBase::Environment::get().getWindowManager()->toggleHud(); runtime.getContext().report(state ? "GUI -> On" : "GUI -> Off"); if (!state) From 35110fb2f8e1b43b6200a307c33d3bc50066a941 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 13:31:22 +0200 Subject: [PATCH 265/521] Remove unused and slightly broken custom button titles in ConfirmationDialog --- apps/openmw/mwgui/confirmationdialog.cpp | 8 -------- apps/openmw/mwgui/confirmationdialog.hpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 697d90862..65b079d85 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -19,14 +19,6 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ConfirmationDialog::onOkButtonClicked); } - void ConfirmationDialog::askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage) - { - mCancelButton->setCaptionWithReplacing(cancelMessage); - mOkButton->setCaptionWithReplacing(confirmMessage); - - askForConfirmation(message); - } - void ConfirmationDialog::askForConfirmation(const std::string& message) { setVisible(true); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 259579376..ab52549ec 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -10,7 +10,6 @@ namespace MWGui public: ConfirmationDialog(); void askForConfirmation(const std::string& message); - void askForConfirmation(const std::string& message, const std::string& confirmMessage, const std::string& cancelMessage); virtual bool exit(); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8c7ec6bfe..d3c1ec292 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -701,7 +701,7 @@ namespace MWGui void MapWindow::onNoteEditDelete() { ConfirmationDialog* confirmation = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - confirmation->askForConfirmation("#{sDeleteNote}", "#{sYes}", "#{sNo}"); + confirmation->askForConfirmation("#{sDeleteNote}"); confirmation->eventCancelClicked.clear(); confirmation->eventOkClicked.clear(); confirmation->eventOkClicked += MyGUI::newDelegate(this, &MapWindow::onNoteEditDeleteConfirm); From 5f440a29bda58ce9f5afa80e02148155b4d1cc37 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 13:49:09 +0200 Subject: [PATCH 266/521] Remember key focus per GUI mode Among other things, this will remember the focused button in the container window, allowing quick looting of multiple containers. --- apps/openmw/mwgui/keyboardnavigation.cpp | 25 +++++++++++++++++++++ apps/openmw/mwgui/keyboardnavigation.hpp | 10 ++++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 28 +++++++++++------------- apps/openmw/mwgui/windowmanagerimp.hpp | 6 +---- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index ba09ce369..c97532df5 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -28,10 +28,35 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu KeyboardNavigation::KeyboardNavigation() { + MyGUI::WidgetManager::getInstance().registerUnlinker(this); } KeyboardNavigation::~KeyboardNavigation() { + MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); +} + +void KeyboardNavigation::saveFocus(int mode) +{ + mKeyFocus[mode] = MyGUI::InputManager::getInstance().getKeyFocusWidget(); +} + +void KeyboardNavigation::restoreFocus(int mode) +{ + std::map::const_iterator found = mKeyFocus.find(mode); + if (found != mKeyFocus.end()) + { + MyGUI::Widget* w = found->second; + if (w && w->getVisible() && w->getEnabled()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second); + } +} + +void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) +{ + for (std::pair& w : mKeyFocus) + if (w.second == widget) + w.second = nullptr; } bool isButtonFocus() diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 86cc67962..fff36d862 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -2,11 +2,12 @@ #define OPENMW_MWGUI_KEYBOARDNAVIGATION_H #include +#include namespace MWGui { - class KeyboardNavigation + class KeyboardNavigation : public MyGUI::IUnlinkWidget { public: KeyboardNavigation(); @@ -15,11 +16,18 @@ namespace MWGui /// @return Was the key handled by this class? bool injectKeyPress(MyGUI::KeyCode key, unsigned int text); + void saveFocus(int mode); + void restoreFocus(int mode); + + void _unlinkWidget(MyGUI::Widget* widget); + private: bool switchFocus(int direction, bool wrap); /// Send button press event to focused button bool accept(); + + std::map mKeyFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2c58336da..6306ef81a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -137,7 +137,6 @@ namespace MWGui , mWorkQueue(workQueue) , mViewer(viewer) , mConsoleOnlyScripts(consoleOnlyScripts) - , mSaveKeyFocus(NULL) , mCurrentModals() , mHud(NULL) , mMap(NULL) @@ -261,8 +260,6 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); - MyGUI::WidgetManager::getInstance().registerUnlinker(this); - // Create all cursors in advance createCursors(); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); @@ -505,8 +502,6 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - MyGUI::WidgetManager::getInstance().unregisterUnlinker(this); - delete mConsole; delete mMessageBoxManager; delete mHud; @@ -1171,8 +1166,10 @@ namespace MWGui } if (!mGuiModes.empty()) + { + mKeyboardNavigation->saveFocus(mGuiModes.back()); mGuiModeStates[mGuiModes.back()].update(false); - + } mGuiModes.push_back(mode); mGuiModeStates[mode].update(true); @@ -1181,6 +1178,8 @@ namespace MWGui for (WindowBase* window : mGuiModeStates[mode].mWindows) window->setPtr(arg); + mKeyboardNavigation->restoreFocus(mode); + bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1197,6 +1196,7 @@ namespace MWGui if (!mGuiModes.empty()) { const GuiMode mode = mGuiModes.back(); + mKeyboardNavigation->saveFocus(mode); mGuiModes.pop_back(); mGuiModeStates[mode].update(false); if (!noSound) @@ -1204,7 +1204,11 @@ namespace MWGui } if (!mGuiModes.empty()) - mGuiModeStates[mGuiModes.back()].update(true); + { + const GuiMode mode = mGuiModes.back(); + mGuiModeStates[mode].update(true); + mKeyboardNavigation->restoreFocus(mode); + } bool gameMode = !isGuiMode(); MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); @@ -1564,12 +1568,6 @@ namespace MWGui return mLoadingScreen; } - void WindowManager::_unlinkWidget(MyGUI::Widget *widget) - { - if (widget == mSaveKeyFocus) - mSaveKeyFocus = NULL; - } - bool WindowManager::getCursorVisible() { return mCursorVisible; @@ -1789,7 +1787,7 @@ namespace MWGui void WindowManager::addCurrentModal(WindowModal *input) { if (mCurrentModals.empty()) - mSaveKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + mKeyboardNavigation->saveFocus(getMode()); mCurrentModals.push(input); } @@ -1803,7 +1801,7 @@ namespace MWGui mCurrentModals.pop(); if (mCurrentModals.empty()) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveKeyFocus); + mKeyboardNavigation->restoreFocus(getMode()); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 17707d2c3..30d19e9f1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -124,7 +124,7 @@ namespace MWGui class JailScreen; class KeyboardNavigation; - class WindowManager : public MWBase::WindowManager, MyGUI::IUnlinkWidget + class WindowManager : public MWBase::WindowManager { public: typedef std::pair Faction; @@ -142,8 +142,6 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); - void _unlinkWidget(MyGUI::Widget* widget); - /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); @@ -406,8 +404,6 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - MyGUI::Widget* mSaveKeyFocus; - std::stack mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). From 65a707348caf471eed2d7f5211aff7de6f1575a3 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 14:27:10 +0200 Subject: [PATCH 267/521] Make Tab select the first widget if none is selected --- apps/openmw/mwgui/keyboardnavigation.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index c97532df5..8ce26e1d0 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -13,6 +14,9 @@ namespace MWGui /// Recursively get all child widgets that accept keyboard input void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) { + if (!parent->getVisible() || !parent->getEnabled()) + return; + MyGUI::EnumeratorWidgetPtr enumerator = parent->getEnumerator(); while (enumerator.next()) { @@ -101,6 +105,22 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + if (!focus && (direction == D_Next || direction == D_Prev)) + { + // if nothing is selected, select the first widget + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + } + if (!focus) return false; From 9ead331741fb4ccd1a2615047739e5c03b9030d6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 14:42:25 +0200 Subject: [PATCH 268/521] Fix pinned windows showing in other GUI modes --- apps/openmw/mwgui/windowmanagerimp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6306ef81a..8266e3e8d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -613,6 +613,8 @@ namespace MWGui setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic))); setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats))); + mInventoryWindow->setGuiMode(getMode()); + // If in game mode (or interactive messagebox), show the pinned windows if (mGuiModes.empty()) { @@ -622,11 +624,17 @@ namespace MWGui mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic)); return; } + else if (getMode() != GM_Inventory) + { + mMap->setVisible(false); + mStatsWindow->setVisible(false); + mSpellWindow->setVisible(false); + mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter); + } GuiMode mode = mGuiModes.back(); mInventoryWindow->setTrading(mode == GM_Barter); - mInventoryWindow->setGuiMode(mode); // For the inventory mode, compute the effective set of windows to show. // This is controlled both by what windows the From 32f9c8058a5e919ed60306e4ce986d839d8bd8bb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 15:06:11 +0200 Subject: [PATCH 269/521] Remove redundant RestBed gui mode --- apps/openmw/mwgui/mode.hpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 10 ++++++---- apps/openmw/mwgui/waitdialog.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 7 +------ apps/openmw/mwscript/guiextensions.cpp | 2 +- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index db851e067..c452a1f5f 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -23,7 +23,6 @@ namespace MWGui GM_Dialogue, // NPC interaction GM_Barter, GM_Rest, - GM_RestBed, GM_SpellBuying, GM_Travel, GM_SpellCreation, diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index b39b1a8ab..afcf23be3 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -79,6 +79,11 @@ namespace MWGui mProgressBar.setVisible (false); } + void WaitDialog::setPtr(const MWWorld::Ptr &ptr) + { + setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + } + bool WaitDialog::exit() { return (!mProgressBar.isVisible()); //Only exit if not currently waiting @@ -100,8 +105,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode (); } - setCanRest(canRest == 0); - onHourSliderChangedPosition(mHourSlider, 0); mHourSlider->setScrollPosition (0); @@ -176,7 +179,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - exit(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Rest); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) @@ -264,7 +267,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mTimeAdvancer.stop(); } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 9bf8279be..19c265204 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -27,14 +27,14 @@ namespace MWGui public: WaitDialog(); + void setPtr(const MWWorld::Ptr &ptr); + virtual void onOpen(); virtual bool exit(); void onFrame(float dt); - void bedActivated() { setCanRest(true); } - bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8266e3e8d..bfd6fd20d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -398,7 +398,6 @@ namespace MWGui mWaitDialog = new WaitDialog(); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); - mGuiModeStates[GM_RestBed] = GuiModeState(mWaitDialog); mSpellCreationDialog = new SpellCreationDialog(); mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); @@ -662,10 +661,6 @@ namespace MWGui case GM_Review: mCharGen->spawnDialog(mode); break; - case GM_RestBed: - // FIXME: use GM_Rest and push the 'bed' argument in some other way - mWaitDialog->bedActivated(); - break; default: break; } @@ -1700,7 +1695,7 @@ namespace MWGui { return !MyGUI::InputManager::getInstance().isModalAny() // TODO: remove this, once we have properly serialized the state of open windows - && (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest || getMode() == GM_RestBed))); + && (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest))); } void WindowManager::playVideo(const std::string &name, bool allowSkipping) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 6f2c146b1..cea176ff6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -57,7 +57,7 @@ namespace MWScript if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), bed)) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Rest, bed); } }; From ba7ae2663f26b7376ab79a878719a6e617021e00 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 21:45:52 +0200 Subject: [PATCH 270/521] Use a generic container to delete windows --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 92 ++++++++++++++------------ apps/openmw/mwgui/windowmanagerimp.hpp | 3 +- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ba4d05d75..ed7273384 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -68,7 +68,7 @@ namespace MWGui HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) - : Layout("openmw_hud.layout") + : WindowBase("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map")) , mHealth(NULL) , mMagicka(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index e2ef52be0..4ea9d7ac3 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -16,7 +16,7 @@ namespace MWGui class SpellIcons; class ItemWidget; - class HUD : public Layout, public LocalMapBase + class HUD : public WindowBase, public LocalMapBase { public: HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bfd6fd20d..47557f369 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -146,7 +146,6 @@ namespace MWGui , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) - , mJournal(NULL) , mDialogueWindow(NULL) , mContainerWindow(NULL) , mDragAndDrop(NULL) @@ -252,6 +251,7 @@ namespace MWGui mKeyboardNavigation.reset(new KeyboardNavigation()); mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); + mWindows.push_back(mLoadingScreen); //set up the hardware cursor manager mCursorManager = new SDLUtil::SDLCursorManager(); @@ -321,112 +321,153 @@ namespace MWGui mRecharge = new Recharge(); mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); + mWindows.push_back(mRecharge); mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); + mWindows.push_back(mMenu); mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); + mWindows.push_back(mMap); mMap->renderGlobalMap(); trackWindow(mMap, "map"); + mStatsWindow = new StatsWindow(mDragAndDrop); + mWindows.push_back(mStatsWindow); trackWindow(mStatsWindow, "stats"); + mInventoryWindow = new InventoryWindow(mDragAndDrop, mViewer->getSceneData()->asGroup(), mResourceSystem); + mWindows.push_back(mInventoryWindow); + mSpellWindow = new SpellWindow(mDragAndDrop); + mWindows.push_back(mSpellWindow); trackWindow(mSpellWindow, "spells"); mGuiModeStates[GM_Inventory] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); mGuiModeStates[GM_None] = GuiModeState({mMap, mInventoryWindow, mSpellWindow, mStatsWindow}); mTradeWindow = new TradeWindow(); + mWindows.push_back(mTradeWindow); trackWindow(mTradeWindow, "barter"); mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); mConsole = new Console(w,h, mConsoleOnlyScripts); + mWindows.push_back(mConsole); trackWindow(mConsole, "console"); mGuiModeStates[GM_Console] = GuiModeState(mConsole); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); - mJournal = JournalWindow::create(JournalViewModel::create (), questList); - mGuiModeStates[GM_Journal] = GuiModeState(mJournal); + JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); + mWindows.push_back(journal); + mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal].mCloseSound = "book close"; mGuiModeStates[GM_Journal].mOpenSound = "book open"; mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); + mSpellBuyingWindow = new SpellBuyingWindow(); + mWindows.push_back(mSpellBuyingWindow); mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); mTravelWindow = new TravelWindow(); + mWindows.push_back(mTravelWindow); mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); mDialogueWindow = new DialogueWindow(); + mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); mContainerWindow = new ContainerWindow(mDragAndDrop); + mWindows.push_back(mContainerWindow); trackWindow(mContainerWindow, "container"); mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); + mWindows.push_back(mHud); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mWindows.push_back(mScrollWindow); mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow); mGuiModeStates[GM_Scroll].mOpenSound = "scroll"; mGuiModeStates[GM_Scroll].mCloseSound = "scroll"; mBookWindow = new BookWindow(); + mWindows.push_back(mBookWindow); mGuiModeStates[GM_Book] = GuiModeState(mBookWindow); mGuiModeStates[GM_Book].mOpenSound = "book open"; mGuiModeStates[GM_Book].mCloseSound = "book close"; mCountDialog = new CountDialog(); + mWindows.push_back(mCountDialog); + mSettingsWindow = new SettingsWindow(); + mWindows.push_back(mSettingsWindow); mGuiModeStates[GM_Settings] = GuiModeState(mSettingsWindow); mConfirmationDialog = new ConfirmationDialog(); + mWindows.push_back(mConfirmationDialog); mAlchemyWindow = new AlchemyWindow(); + mWindows.push_back(mAlchemyWindow); trackWindow(mAlchemyWindow, "alchemy"); mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); mQuickKeysMenu = new QuickKeysMenu(); + mWindows.push_back(mQuickKeysMenu); mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); mLevelupDialog = new LevelupDialog(); + mWindows.push_back(mLevelupDialog); mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); mWaitDialog = new WaitDialog(); + mWindows.push_back(mWaitDialog); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); mSpellCreationDialog = new SpellCreationDialog(); + mWindows.push_back(mSpellCreationDialog); mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); mEnchantingDialog = new EnchantingDialog(); + mWindows.push_back(mEnchantingDialog); mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); mTrainingWindow = new TrainingWindow(); + mWindows.push_back(mTrainingWindow); mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); mMerchantRepair = new MerchantRepair(); + mWindows.push_back(mMerchantRepair); mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); mRepair = new Repair(); + mWindows.push_back(mRepair); mGuiModeStates[GM_Repair] = GuiModeState(mRepair); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); + mWindows.push_back(mCompanionWindow); trackWindow(mCompanionWindow, "companion"); mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); mJailScreen = new JailScreen(); + mWindows.push_back(mJailScreen); mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen); std::string werewolfFaderTex = "textures\\werewolfoverlay.dds"; if (mResourceSystem->getVFS()->exists(werewolfFaderTex)) + { mWerewolfFader = new ScreenFader(werewolfFaderTex); + mWindows.push_back(mWerewolfFader); + } mBlindnessFader = new ScreenFader("black"); + mWindows.push_back(mBlindnessFader); // fall back to player_hit_01.dds if bm_player_hit_01.dds is not available std::string hitFaderTexture = "textures\\bm_player_hit_01.dds"; @@ -438,10 +479,13 @@ namespace MWGui hitFaderCoord = MyGUI::FloatCoord(0.2, 0.25, 0.6, 0.5); } mHitFader = new ScreenFader(hitFaderTexture, hitFaderLayout, hitFaderCoord); + mWindows.push_back(mHitFader); mScreenFader = new ScreenFader("black"); + mWindows.push_back(mScreenFader); mDebugWindow = new DebugWindow(); + mWindows.push_back(mDebugWindow); mInputBlocker = MyGUI::Gui::getInstance().createWidget("",0,0,w,h,MyGUI::Align::Stretch,"InputBlocker"); @@ -501,49 +545,15 @@ namespace MWGui MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); - delete mConsole; + for (WindowBase* window : mWindows) + delete window; + mWindows.clear(); + delete mMessageBoxManager; - delete mHud; - delete mMap; delete mLocalMapRender; - delete mMenu; - delete mStatsWindow; - delete mJournal; - delete mDialogueWindow; - delete mContainerWindow; - delete mInventoryWindow; - delete mToolTips; delete mCharGen; delete mDragAndDrop; - delete mBookWindow; - delete mScrollWindow; - delete mTradeWindow; - delete mSpellBuyingWindow; - delete mTravelWindow; - delete mSettingsWindow; - delete mConfirmationDialog; - delete mAlchemyWindow; - delete mSpellWindow; - delete mLoadingScreen; - delete mLevelupDialog; - delete mWaitDialog; - delete mSpellCreationDialog; - delete mEnchantingDialog; - delete mTrainingWindow; - delete mCountDialog; - delete mQuickKeysMenu; - delete mMerchantRepair; - delete mRepair; delete mSoulgemDialog; - delete mRecharge; - delete mCompanionWindow; - delete mHitFader; - delete mWerewolfFader; - delete mScreenFader; - delete mBlindnessFader; - delete mDebugWindow; - delete mJailScreen; - delete mCursorManager; cleanupGarbage(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 30d19e9f1..90fcf8979 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -417,7 +417,6 @@ namespace MWGui StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; - JournalWindow* mJournal; DialogueWindow *mDialogueWindow; ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; @@ -453,6 +452,8 @@ namespace MWGui DebugWindow* mDebugWindow; JailScreen* mJailScreen; + std::vector mWindows; + Translation::Storage& mTranslationDataStorage; CharacterCreation* mCharGen; From 2b03bc0c5695623ffc5693fae30b875b34ee8f07 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:00:15 +0200 Subject: [PATCH 271/521] Call WindowBase::onFrame() for every active window --- apps/openmw/mwgui/companionwindow.cpp | 3 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/console.hpp | 2 ++ apps/openmw/mwgui/container.hpp | 2 ++ apps/openmw/mwgui/dialogue.cpp | 5 ++-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 5 +--- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/mainmenu.cpp | 2 +- apps/openmw/mwgui/mainmenu.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ apps/openmw/mwgui/spellcreationdialog.hpp | 2 ++ apps/openmw/mwgui/spellwindow.cpp | 15 ++++------ apps/openmw/mwgui/statswindow.cpp | 3 -- apps/openmw/mwgui/tradewindow.cpp | 5 ++++ apps/openmw/mwgui/tradewindow.hpp | 2 ++ apps/openmw/mwgui/trainingwindow.cpp | 1 + apps/openmw/mwgui/windowbase.hpp | 3 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 35 ++++++----------------- 20 files changed, 47 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index c4e50c8c2..90ef32ced 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -116,8 +116,9 @@ void CompanionWindow::setPtr(const MWWorld::Ptr& npc) setTitle(npc.getClass().getName(npc)); } -void CompanionWindow::onFrame() +void CompanionWindow::onFrame(float dt) { + checkReferenceAvailable(); updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index fd66cfa80..23af6bc96 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -23,7 +23,7 @@ namespace MWGui virtual void resetReference(); void setPtr(const MWWorld::Ptr& npc); - void onFrame (); + void onFrame (float dt); private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 6257b5617..a68f1cb43 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -42,6 +42,8 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setFont(const std::string &fntName); void onResChange(int width, int height); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 3ae73a01f..27b0e408b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -36,6 +36,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& container); virtual void onClose(); + void onFrame(float dt) { checkReferenceAvailable(); } + virtual void resetReference(); private: diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2effcc700..ec6dcb2cb 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -630,9 +630,10 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } - void DialogueWindow::onFrame() + void DialogueWindow::onFrame(float dt) { - if(mMainWidget->getVisible() && mPtr.getTypeName() == typeid(ESM::NPC).name()) + checkReferenceAvailable(); + if(mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 12e2328f4..4ac5bd9d0 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -117,7 +117,7 @@ namespace MWGui void clearChoices(); void goodbye(); - void onFrame(); + void onFrame(float dt); // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index ace63ae5c..335e5fda9 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -21,6 +21,8 @@ namespace MWGui virtual void onOpen(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index dcfb075db..735bf3682 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -589,11 +589,8 @@ namespace MWGui mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); } - void InventoryWindow::onFrame() + void InventoryWindow::onFrame(float dt) { - if (!mMainWidget->getVisible()) - return; - updateEncumbranceBar(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fb5be3493..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -40,7 +40,7 @@ namespace MWGui /// start trading, disables item drag&drop void setTrading(bool trading); - void onFrame(); + void onFrame(float dt); void pickUpObject (MWWorld::Ptr object); diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 657f0e4ec..4e629403a 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -197,7 +197,7 @@ namespace MWGui } } - void MainMenu::update(float dt) + void MainMenu::onFrame(float dt) { if (mVideo) { diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 612f7d1bd..1beb9ee16 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -36,7 +36,7 @@ namespace MWGui virtual void setVisible (bool visible); - void update(float dt); + void onFrame(float dt); private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 01cc6c2f9..6eb52366b 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,6 +28,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void setPtr(const MWWorld::Ptr& actor, int startOffset); + void onFrame(float dt) { checkReferenceAvailable(); } + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index f7bb8a101..7bacda385 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -152,6 +152,8 @@ namespace MWGui virtual void onOpen(); + void onFrame(float dt) { checkReferenceAvailable(); } + void setPtr(const MWWorld::Ptr& actor); protected: diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 9261912b4..601204aa1 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -68,16 +68,13 @@ namespace MWGui } void SpellWindow::onFrame(float dt) - { - if (mMainWidget->getVisible()) + { + NoDrop::onFrame(dt); + mUpdateTimer += dt; + if (0.5f < mUpdateTimer) { - NoDrop::onFrame(dt); - mUpdateTimer += dt; - if (0.5f < mUpdateTimer) - { - mUpdateTimer = 0; - mSpellView->incrementalUpdate(); - } + mUpdateTimer = 0; + mSpellView->incrementalUpdate(); } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 17e51e338..bf505b00f 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -297,9 +297,6 @@ namespace MWGui void StatsWindow::onFrame (float dt) { - if (!mMainWidget->getVisible()) - return; - NoDrop::onFrame(dt); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2a6c61a16..feccfd942 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -142,6 +142,11 @@ namespace MWGui onFilterChanged(mFilterAll); } + void TradeWindow::onFrame(float dt) + { + checkReferenceAvailable(); + } + void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) { if (_sender == mFilterAll) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 55164b934..69fdc135b 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -29,6 +29,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); + void onFrame(float dt); + void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index ca6f2246e..c1f7f8ac1 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -195,6 +195,7 @@ namespace MWGui void TrainingWindow::onFrame(float dt) { + checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); if (mFadeTimeRemaining <= 0) diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index e6817358f..6889ad9ec 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -29,6 +29,9 @@ namespace MWGui /// Open this object in the GUI, for windows that support it virtual void setPtr(const MWWorld::Ptr& ptr) {} + /// Called every frame if the window is in an active GUI mode + virtual void onFrame(float duration) {} + /// Notify that window has been made visible virtual void onOpen() {} /// Notify that window has been hidden diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 47557f369..9635f804e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -890,12 +890,19 @@ namespace MWGui void WindowManager::onFrame (float frameDuration) { + if (!mGuiModes.empty()) + { + GuiModeState& state = mGuiModeStates[mGuiModes.back()]; + for (WindowBase* window : state.mWindows) + window->onFrame(frameDuration); + } + if (!mCurrentModals.empty()) + mCurrentModals.top()->onFrame(frameDuration); + mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); - mMenu->update(frameDuration); - if (mLocalMapRender) mLocalMapRender->cleanupCameras(); @@ -909,34 +916,10 @@ namespace MWGui mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); } - mDialogueWindow->onFrame(); - - mInventoryWindow->onFrame(); - updateMap(); - mStatsWindow->onFrame(frameDuration); - mMap->onFrame(frameDuration); - mSpellWindow->onFrame(frameDuration); - - mWaitDialog->onFrame(frameDuration); - mHud->onFrame(frameDuration); - mTrainingWindow->onFrame (frameDuration); - - mTrainingWindow->checkReferenceAvailable(); - mDialogueWindow->checkReferenceAvailable(); - mTradeWindow->checkReferenceAvailable(); - mSpellBuyingWindow->checkReferenceAvailable(); - mSpellCreationDialog->checkReferenceAvailable(); - mEnchantingDialog->checkReferenceAvailable(); - mContainerWindow->checkReferenceAvailable(); - mCompanionWindow->checkReferenceAvailable(); - mConsole->checkReferenceAvailable(); - mCompanionWindow->onFrame(); - mJailScreen->onFrame(frameDuration); - if (mWerewolfFader) mWerewolfFader->update(frameDuration); mBlindnessFader->update(frameDuration); From c6c01870ec299c0f99065d474107bf253a39ec78 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:07:30 +0200 Subject: [PATCH 272/521] Call onResChange for every window --- apps/openmw/mwgui/alchemywindow.hpp | 2 ++ apps/openmw/mwgui/bookwindow.hpp | 2 ++ apps/openmw/mwgui/quickkeysmenu.hpp | 2 ++ apps/openmw/mwgui/scrollwindow.hpp | 2 ++ apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ apps/openmw/mwgui/windowbase.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++++-------- 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 8dffaaad1..a27d9c749 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -26,6 +26,8 @@ namespace MWGui virtual void onOpen(); + void onResChange(int, int) { center(); } + private: std::string mSuggestedPotionName; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 4f7224ea8..b20498feb 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -17,6 +17,8 @@ namespace MWGui void setPtr(const MWWorld::Ptr& book); void setInventoryAllowed(bool allowed); + void onResChange(int, int) { center(); } + protected: void onNextPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index c99d482ee..0070aa55b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -22,6 +22,8 @@ namespace MWGui QuickKeysMenu(); ~QuickKeysMenu(); + void onResChange(int, int) { center(); } + void onItemButtonClicked(MyGUI::Widget* sender); void onMagicButtonClicked(MyGUI::Widget* sender); void onUnassignButtonClicked(MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 596db06ad..35016e5dc 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui void setPtr (const MWWorld::Ptr& scroll); void setInventoryAllowed(bool allowed); + void onResChange(int, int) { center(); } + protected: void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 4f8607fda..c6e48819c 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -19,6 +19,8 @@ namespace MWGui void updateControlsBox(); + void onResChange(int, int) { center(); } + protected: MyGUI::TabControl* mSettingsTab; MyGUI::Button* mOkButton; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 6eb52366b..36f7499a0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -30,6 +30,8 @@ namespace MWGui void onFrame(float dt) { checkReferenceAvailable(); } + void onResChange(int, int) { center(); } + protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index 6889ad9ec..c9f9555b0 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -42,7 +42,11 @@ namespace MWGui virtual void setVisible(bool visible); /// Returns the visibility state of the window bool isVisible(); + void center(); + + /// Called when GUI viewport changes size + virtual void onResChange(int width, int height) {} }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9635f804e..3e55060f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1128,14 +1128,10 @@ namespace MWGui it->first->setSize(size); } - mConsole->onResChange(x, y); - mMenu->onResChange(x, y); - mSettingsWindow->center(); - mAlchemyWindow->center(); - mScrollWindow->center(); - mBookWindow->center(); - mQuickKeysMenu->center(); - mSpellBuyingWindow->center(); + for (WindowBase* window : mWindows) + window->onResChange(x, y); + + // TODO: check if any windows are now off-screen and move them back if so } void WindowManager::onCursorChange(const std::string &name) From e7d2a8a4dc6d205a08ed2c7f372f49d56be6bf15 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:16:56 +0200 Subject: [PATCH 273/521] Call clear() for every window --- apps/openmw/mwgui/companionwindow.hpp | 1 + apps/openmw/mwgui/console.hpp | 1 + apps/openmw/mwgui/container.hpp | 1 + apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwgui/hud.hpp | 2 ++ apps/openmw/mwgui/spellbuyingwindow.hpp | 1 + apps/openmw/mwgui/spellcreationdialog.hpp | 1 + apps/openmw/mwgui/tradewindow.hpp | 1 + apps/openmw/mwgui/trainingwindow.hpp | 2 ++ apps/openmw/mwgui/waitdialog.cpp | 5 +++++ apps/openmw/mwgui/waitdialog.hpp | 1 + apps/openmw/mwgui/windowbase.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 26 ++++++----------------- 14 files changed, 27 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 23af6bc96..891106853 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -24,6 +24,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& npc); void onFrame (float dt); + void clear() { resetReference(); } private: ItemView* mItemView; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index a68f1cb43..f243b8387 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -47,6 +47,7 @@ namespace MWGui void setFont(const std::string &fntName); void onResChange(int width, int height); + void clear() { resetReference(); } // Print a message to the console, in specified color. void print(const std::string &msg, const std::string& color = "#FFFFFF"); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 27b0e408b..a53d4f782 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -35,6 +35,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& container); virtual void onClose(); + void clear() { resetReference(); } void onFrame(float dt) { checkReferenceAvailable(); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 4ac5bd9d0..224ecba66 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -118,6 +118,7 @@ namespace MWGui void goodbye(); void onFrame(float dt); + void clear() { resetReference(); } // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 335e5fda9..39614ebd1 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual void onOpen(); void onFrame(float dt) { checkReferenceAvailable(); } + void clear() { resetReference(); } void setSoulGem (const MWWorld::Ptr& gem); void setItem (const MWWorld::Ptr& item); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 4ea9d7ac3..3dae2157f 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -60,6 +60,8 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); + void clear() { resetEnemy(); } + private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 36f7499a0..649aab3f2 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -29,6 +29,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor, int startOffset); void onFrame(float dt) { checkReferenceAvailable(); } + void clear() { resetReference(); } void onResChange(int, int) { center(); } diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 7bacda385..855016666 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -151,6 +151,7 @@ namespace MWGui SpellCreationDialog(); virtual void onOpen(); + void clear() { resetReference(); } void onFrame(float dt) { checkReferenceAvailable(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 69fdc135b..00f38024d 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -30,6 +30,7 @@ namespace MWGui void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); + void clear() { resetReference(); } void borrowItem (int index, size_t count); void returnItem (int index, size_t count); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index d4785194a..127c85f6a 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -20,6 +20,8 @@ namespace MWGui void onFrame(float dt); + void clear() { resetReference(); } + protected: virtual void onReferenceUnavailable (); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index afcf23be3..cd1d29854 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -262,6 +262,11 @@ namespace MWGui } } + void WaitDialog::clear() + { + mProgressBar.setVisible(false); + } + void WaitDialog::stopWaiting () { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 19c265204..6bd90473f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,6 +34,7 @@ namespace MWGui virtual bool exit(); void onFrame(float dt); + void clear(); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index c9f9555b0..f183c97fe 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -45,6 +45,9 @@ namespace MWGui void center(); + /// Clear any state specific to the running game + virtual void clear() {} + /// Called when GUI viewport changes size virtual void onResChange(int width, int height) {} }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3e55060f8..b512d8fc8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -514,10 +514,6 @@ namespace MWGui void WindowManager::setNewGame(bool newgame) { - // This method will always be called after loading a savegame or starting a new game - // Reset enemy, it could be a dangling pointer from a previous game - mHud->resetEnemy(); - if (newgame) { disallowAll(); @@ -1596,36 +1592,26 @@ namespace MWGui void WindowManager::clear() { + for (WindowBase* window : mWindows) + window->clear(); + if (mLocalMapRender) mLocalMapRender->clear(); - mMap->clear(); - mQuickKeysMenu->clear(); mMessageBoxManager->clear(); - mTrainingWindow->resetReference(); - mDialogueWindow->resetReference(); - mTradeWindow->resetReference(); - mSpellBuyingWindow->resetReference(); - mSpellCreationDialog->resetReference(); - mEnchantingDialog->resetReference(); - mContainerWindow->resetReference(); - mCompanionWindow->resetReference(); - mConsole->resetReference(); - mToolTips->setFocusObject(MWWorld::ConstPtr()); - mInventoryWindow->clear(); - mSelectedSpell.clear(); - mCustomMarkers.clear(); mForceHidden = GW_None; setWerewolfOverlay(false); - mGuiModes.clear(); + while (!mGuiModes.empty()) + popGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); } From f67dbc8aa034adb3ac9740803a943cf7bb732d60 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:24:22 +0200 Subject: [PATCH 274/521] Remove redundant update function --- apps/openmw/engine.cpp | 5 ----- apps/openmw/mwbase/windowmanager.hpp | 7 ------ apps/openmw/mwgui/hud.cpp | 31 ++++++++++++-------------- apps/openmw/mwgui/hud.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++------- apps/openmw/mwgui/windowmanagerimp.hpp | 7 ------ 6 files changed, 18 insertions(+), 47 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f5ec86cc3..3e5ab7ce6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -161,11 +161,6 @@ void OMW::Engine::frame(float frametime) // update GUI mEnvironment.getWindowManager()->onFrame(frametime); - if (mEnvironment.getStateManager()->getState()!= - MWBase::StateManager::State_NoGame) - { - mEnvironment.getWindowManager()->update(); - } unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); osg::Stats* stats = mViewer->getViewerStats(); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 190768f26..43d99b6b3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -102,13 +102,6 @@ namespace MWBase virtual ~WindowManager() {} - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - virtual void update() = 0; - /// @note This method will block until the video finishes playing /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ed7273384..87c1b2f3c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -371,6 +371,20 @@ namespace MWGui if (mIsDrowning) mDrowningFlashTheta += dt * osg::PI*2; + + mSpellIcons->updateWidgets(mEffectBox, true); + + if (mEnemyActorId != -1 && mEnemyHealth->getVisible()) + { + updateEnemyHealthBar(); + } + + if (mIsDrowning) + { + float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f; + + mDrowningFlash->setAlpha(intensity); + } } void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) @@ -602,23 +616,6 @@ namespace MWGui } - void HUD::update() - { - mSpellIcons->updateWidgets(mEffectBox, true); - - if (mEnemyActorId != -1 && mEnemyHealth->getVisible()) - { - updateEnemyHealthBar(); - } - - if (mIsDrowning) - { - float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f; - - mDrowningFlash->setAlpha(intensity); - } - } - void HUD::setEnemy(const MWWorld::Ptr &enemy) { mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId(); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 3dae2157f..fc335d1e7 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -55,8 +55,6 @@ namespace MWGui MyGUI::Widget* getEffectBox() { return mEffectBox; } - void update(); - void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b512d8fc8..c9dec0287 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -581,15 +581,6 @@ namespace MWGui } } - void WindowManager::update() - { - cleanupGarbage(); - - mHud->update(); - - updateActivatedQuickKey (); - } - void WindowManager::updateVisible() { if (!mMap) @@ -926,6 +917,10 @@ namespace MWGui if (mCharGen) mCharGen->onFrame(frameDuration); + + updateActivatedQuickKey (); + + cleanupGarbage(); } void WindowManager::changeCell(const MWWorld::CellStore* cell) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 90fcf8979..773eed4fc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -146,13 +146,6 @@ namespace MWGui /// (and will continually update the window while doing so) virtual void playVideo(const std::string& name, bool allowSkipping); - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - virtual void update(); - /// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this. virtual void setKeyFocusWidget (MyGUI::Widget* widget); From d10985e4814baea6a331a1d94698b949788e039e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 22:42:55 +0200 Subject: [PATCH 275/521] Remove unneeded window pointers --- apps/openmw/mwgui/windowmanagerimp.cpp | 97 +++++++++++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 13 ---- 2 files changed, 42 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c9dec0287..906151ab1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -141,37 +141,24 @@ namespace MWGui , mHud(NULL) , mMap(NULL) , mLocalMapRender(NULL) - , mMenu(NULL) , mToolTips(NULL) , mStatsWindow(NULL) , mMessageBoxManager(NULL) , mConsole(NULL) , mDialogueWindow(NULL) - , mContainerWindow(NULL) , mDragAndDrop(NULL) , mInventoryWindow(NULL) , mScrollWindow(NULL) , mBookWindow(NULL) , mCountDialog(NULL) , mTradeWindow(NULL) - , mSpellBuyingWindow(NULL) - , mTravelWindow(NULL) , mSettingsWindow(NULL) , mConfirmationDialog(NULL) - , mAlchemyWindow(NULL) , mSpellWindow(NULL) , mQuickKeysMenu(NULL) , mLoadingScreen(NULL) - , mLevelupDialog(NULL) , mWaitDialog(NULL) - , mSpellCreationDialog(NULL) - , mEnchantingDialog(NULL) - , mTrainingWindow(NULL) - , mMerchantRepair(NULL) , mSoulgemDialog(NULL) - , mRepair(NULL) - , mRecharge(NULL) - , mCompanionWindow(NULL) , mVideoBackground(NULL) , mVideoWidget(NULL) , mWerewolfFader(NULL) @@ -319,13 +306,13 @@ namespace MWGui mDragAndDrop = new DragAndDrop(); - mRecharge = new Recharge(); - mGuiModeStates[GM_Recharge] = GuiModeState(mRecharge); - mWindows.push_back(mRecharge); + Recharge* recharge = new Recharge(); + mGuiModeStates[GM_Recharge] = GuiModeState(recharge); + mWindows.push_back(recharge); - mMenu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); - mGuiModeStates[GM_MainMenu] = GuiModeState(mMenu); - mWindows.push_back(mMenu); + MainMenu* menu = new MainMenu(w, h, mResourceSystem->getVFS(), mVersionDescription); + mGuiModeStates[GM_MainMenu] = GuiModeState(menu); + mWindows.push_back(menu); mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup()); mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue); @@ -367,23 +354,23 @@ namespace MWGui mMessageBoxManager = new MessageBoxManager(mStore->get().find("fMessageTimePerChar")->getFloat()); - mSpellBuyingWindow = new SpellBuyingWindow(); - mWindows.push_back(mSpellBuyingWindow); - mGuiModeStates[GM_SpellBuying] = GuiModeState(mSpellBuyingWindow); + SpellBuyingWindow* spellBuyingWindow = new SpellBuyingWindow(); + mWindows.push_back(spellBuyingWindow); + mGuiModeStates[GM_SpellBuying] = GuiModeState(spellBuyingWindow); - mTravelWindow = new TravelWindow(); - mWindows.push_back(mTravelWindow); - mGuiModeStates[GM_Travel] = GuiModeState(mTravelWindow); + TravelWindow* travelWindow = new TravelWindow(); + mWindows.push_back(travelWindow); + mGuiModeStates[GM_Travel] = GuiModeState(travelWindow); mDialogueWindow = new DialogueWindow(); mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); - mContainerWindow = new ContainerWindow(mDragAndDrop); - mWindows.push_back(mContainerWindow); - trackWindow(mContainerWindow, "container"); - mGuiModeStates[GM_Container] = GuiModeState({mContainerWindow, mInventoryWindow}); + ContainerWindow* containerWindow = new ContainerWindow(mDragAndDrop); + mWindows.push_back(containerWindow); + trackWindow(containerWindow, "container"); + mGuiModeStates[GM_Container] = GuiModeState({containerWindow, mInventoryWindow}); mHud = new HUD(mCustomMarkers, mDragAndDrop, mLocalMapRender); mWindows.push_back(mHud); @@ -412,49 +399,49 @@ namespace MWGui mConfirmationDialog = new ConfirmationDialog(); mWindows.push_back(mConfirmationDialog); - mAlchemyWindow = new AlchemyWindow(); - mWindows.push_back(mAlchemyWindow); - trackWindow(mAlchemyWindow, "alchemy"); - mGuiModeStates[GM_Alchemy] = GuiModeState(mAlchemyWindow); + AlchemyWindow* alchemyWindow = new AlchemyWindow(); + mWindows.push_back(alchemyWindow); + trackWindow(alchemyWindow, "alchemy"); + mGuiModeStates[GM_Alchemy] = GuiModeState(alchemyWindow); mQuickKeysMenu = new QuickKeysMenu(); mWindows.push_back(mQuickKeysMenu); mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu); - mLevelupDialog = new LevelupDialog(); - mWindows.push_back(mLevelupDialog); - mGuiModeStates[GM_Levelup] = GuiModeState(mLevelupDialog); + LevelupDialog* levelupDialog = new LevelupDialog(); + mWindows.push_back(levelupDialog); + mGuiModeStates[GM_Levelup] = GuiModeState(levelupDialog); mWaitDialog = new WaitDialog(); mWindows.push_back(mWaitDialog); mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); - mSpellCreationDialog = new SpellCreationDialog(); - mWindows.push_back(mSpellCreationDialog); - mGuiModeStates[GM_SpellCreation] = GuiModeState(mSpellCreationDialog); + SpellCreationDialog* spellCreationDialog = new SpellCreationDialog(); + mWindows.push_back(spellCreationDialog); + mGuiModeStates[GM_SpellCreation] = GuiModeState(spellCreationDialog); - mEnchantingDialog = new EnchantingDialog(); - mWindows.push_back(mEnchantingDialog); - mGuiModeStates[GM_Enchanting] = GuiModeState(mEnchantingDialog); + EnchantingDialog* enchantingDialog = new EnchantingDialog(); + mWindows.push_back(enchantingDialog); + mGuiModeStates[GM_Enchanting] = GuiModeState(enchantingDialog); - mTrainingWindow = new TrainingWindow(); - mWindows.push_back(mTrainingWindow); - mGuiModeStates[GM_Training] = GuiModeState(mTrainingWindow); + TrainingWindow* trainingWindow = new TrainingWindow(); + mWindows.push_back(trainingWindow); + mGuiModeStates[GM_Training] = GuiModeState(trainingWindow); - mMerchantRepair = new MerchantRepair(); - mWindows.push_back(mMerchantRepair); - mGuiModeStates[GM_MerchantRepair] = GuiModeState(mMerchantRepair); + MerchantRepair* merchantRepair = new MerchantRepair(); + mWindows.push_back(merchantRepair); + mGuiModeStates[GM_MerchantRepair] = GuiModeState(merchantRepair); - mRepair = new Repair(); - mWindows.push_back(mRepair); - mGuiModeStates[GM_Repair] = GuiModeState(mRepair); + Repair* repair = new Repair(); + mWindows.push_back(repair); + mGuiModeStates[GM_Repair] = GuiModeState(repair); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - mWindows.push_back(mCompanionWindow); - trackWindow(mCompanionWindow, "companion"); - mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, mCompanionWindow}); + CompanionWindow* companionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); + mWindows.push_back(companionWindow); + trackWindow(companionWindow, "companion"); + mGuiModeStates[GM_Companion] = GuiModeState({mInventoryWindow, companionWindow}); mJailScreen = new JailScreen(); mWindows.push_back(mJailScreen); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 773eed4fc..f315bb906 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -405,37 +405,24 @@ namespace MWGui HUD *mHud; MapWindow *mMap; MWRender::LocalMap* mLocalMapRender; - MainMenu *mMenu; ToolTips *mToolTips; StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; DialogueWindow *mDialogueWindow; - ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; InventoryWindow *mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; CountDialog* mCountDialog; TradeWindow* mTradeWindow; - SpellBuyingWindow* mSpellBuyingWindow; - TravelWindow* mTravelWindow; SettingsWindow* mSettingsWindow; ConfirmationDialog* mConfirmationDialog; - AlchemyWindow* mAlchemyWindow; SpellWindow* mSpellWindow; QuickKeysMenu* mQuickKeysMenu; LoadingScreen* mLoadingScreen; - LevelupDialog* mLevelupDialog; WaitDialog* mWaitDialog; - SpellCreationDialog* mSpellCreationDialog; - EnchantingDialog* mEnchantingDialog; - TrainingWindow* mTrainingWindow; - MerchantRepair* mMerchantRepair; SoulgemDialog* mSoulgemDialog; - Repair* mRepair; - Recharge* mRecharge; - CompanionWindow* mCompanionWindow; MyGUI::ImageBox* mVideoBackground; VideoWidget* mVideoWidget; ScreenFader* mWerewolfFader; From f6c227b966e17325541ac7b9b010da8babb1aceb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:02:17 +0200 Subject: [PATCH 276/521] Reset screen faders in clear() Fixes a black screen when loading a game while waiting/resting. --- apps/openmw/mwgui/screenfader.cpp | 6 ++++++ apps/openmw/mwgui/screenfader.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 -- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index be0346e88..1d04e871e 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -119,6 +119,12 @@ namespace MWGui queue(time, percent/100.f); } + void ScreenFader::clear() + { + clearQueue(); + notifyAlphaChanged(0.f); + } + void ScreenFader::setFactor(float factor) { mFactor = factor; diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index b510e133a..19468de3c 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -42,6 +42,8 @@ namespace MWGui void fadeOut(const float time); void fadeTo(const int percent, const float time); + void clear(); + void setFactor (float factor); void setRepeat(bool repeat); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 906151ab1..29425e7c3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1589,8 +1589,6 @@ namespace MWGui mForceHidden = GW_None; - setWerewolfOverlay(false); - while (!mGuiModes.empty()) popGuiMode(); From 222defc6d873f1cb9cc93abeff939ed77e442e6d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:09:41 +0200 Subject: [PATCH 277/521] Extend HUD::clear() --- apps/openmw/mwgui/hud.cpp | 7 +++++++ apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 9 ++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 87c1b2f3c..779e358d3 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -632,6 +632,13 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::clear() + { + unsetSelectedSpell(); + unsetSelectedWeapon(); + resetEnemy(); + } + void HUD::customMarkerCreated(MyGUI::Widget *marker) { marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index fc335d1e7..3542f3ebf 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -58,7 +58,7 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); void resetEnemy(); - void clear() { resetEnemy(); } + void clear(); private: MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 29425e7c3..2cfafd0a2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -506,16 +506,9 @@ namespace MWGui disallowAll(); delete mCharGen; mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); - mGuiModes.clear(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); - mHud->unsetSelectedWeapon(); - mHud->unsetSelectedSpell(); - unsetForceHide(GW_ALL); } else allow(GW_ALL); - - mRestAllowed = !newgame; } WindowManager::~WindowManager() @@ -1338,6 +1331,7 @@ namespace MWGui void WindowManager::disallowAll() { mAllowed = GW_None; + mRestAllowed = false; mBookWindow->setInventoryAllowed (false); mScrollWindow->setInventoryAllowed (false); @@ -1588,6 +1582,7 @@ namespace MWGui mCustomMarkers.clear(); mForceHidden = GW_None; + mRestAllowed = true; while (!mGuiModes.empty()) popGuiMode(); From c0d8bef82fb5964a278bf53005b9135c8954ca63 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:14:53 +0200 Subject: [PATCH 278/521] Call changeInputMode() from updateVisible() --- apps/openmw/mwgui/windowmanagerimp.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2cfafd0a2..8349ca0bc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -495,8 +495,6 @@ namespace MWGui // Set up visibility updateVisible(); - - MWBase::Environment::get().getInputManager()->changeInputMode(false); } void WindowManager::setNewGame(bool newgame) @@ -573,6 +571,8 @@ namespace MWGui bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + mInputBlocker->setVisible (gameMode); if (loading) @@ -761,7 +761,6 @@ namespace MWGui void WindowManager::interactiveMessageBox(const std::string &message, const std::vector &buttons, bool block) { mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); updateVisible(); if (block) @@ -1143,9 +1142,6 @@ namespace MWGui mKeyboardNavigation->restoreFocus(mode); - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1173,9 +1169,6 @@ namespace MWGui mKeyboardNavigation->restoreFocus(mode); } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1196,9 +1189,6 @@ namespace MWGui ++it; } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - updateVisible(); } @@ -1488,7 +1478,6 @@ namespace MWGui void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); updateVisible(); } @@ -1587,7 +1576,6 @@ namespace MWGui while (!mGuiModes.empty()) popGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(false); updateVisible(); } From d58ff4a736d8f5003d5dff234524e6fb697fc69b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 23 Sep 2017 23:47:47 +0200 Subject: [PATCH 279/521] Remove obsolete Container GUI keyboard handling --- apps/openmw/mwgui/container.cpp | 9 --------- apps/openmw/mwgui/container.hpp | 1 - 2 files changed, 10 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 85afc1aa3..90ed1a596 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -46,7 +46,6 @@ namespace MWGui mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ContainerWindow::onKeyPressed); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); setCoord(200,0,600,300); @@ -158,14 +157,6 @@ namespace MWGui setTitle(container.getClass().getName(container)); } - void ContainerWindow::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) - { - if (_key == MyGUI::KeyCode::Space) - onCloseButtonClicked(mCloseButton); - if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter) - onTakeAllButtonClicked(mTakeButton); - } - void ContainerWindow::resetReference() { ReferenceInterface::resetReference(); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a53d4f782..50c69da3b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -62,7 +62,6 @@ namespace MWGui void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); - void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char); /// @return is taking the item allowed? bool onTakeItem(const ItemStack& item, int count); From 331192f2d688ebd7452726e3861434fe9d537619 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 00:23:08 +0200 Subject: [PATCH 280/521] Improve keyboard navigation of book/scroll windows --- apps/openmw/mwgui/bookwindow.cpp | 15 +++++++++++++++ apps/openmw/mwgui/bookwindow.hpp | 2 ++ apps/openmw/mwgui/formatting.cpp | 9 +++++---- apps/openmw/mwgui/keyboardnavigation.cpp | 9 +++++---- apps/openmw/mwgui/scrollwindow.cpp | 21 +++++++++++++++++++-- apps/openmw/mwgui/scrollwindow.hpp | 1 + 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 5abc63c55..ae20b8e43 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -52,6 +52,11 @@ namespace MWGui mRightPage->setNeedMouseFocus(true); mRightPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel); + mNextPageButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mPrevPageButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &BookWindow::onKeyButtonPressed); + if (mNextPageButton->getSize().width == 64) { // english button has a 7 pixel wide strip of garbage on its right edge @@ -94,6 +99,8 @@ namespace MWGui updatePages(); setTakeButtonShow(showTakeButton); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); } void BookWindow::setTakeButtonShow(bool show) @@ -102,6 +109,14 @@ namespace MWGui mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } + void BookWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + prevPage(); + else if (key == MyGUI::KeyCode::ArrowDown) + nextPage(); + } + void BookWindow::setInventoryAllowed(bool allowed) { mTakeButtonAllowed = allowed; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index b20498feb..2459c3464 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -27,6 +27,8 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void setTakeButtonShow(bool show); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); + void nextPage(); void prevPage(); diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index cf4a5b589..a9319048e 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -406,10 +406,11 @@ namespace MWGui MyGUI::EditBox* box = parent->createWidget("NormalText", MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top, parent->getName() + MyGUI::utility::toString(parent->getChildCount())); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setProperty("NeedMouse", "false"); + box->setEditStatic(true); + box->setEditMultiLine(true); + box->setEditWordWrap(true); + box->setNeedMouseFocus(false); + box->setNeedKeyFocus(false); box->setMaxTextLength(text.size()); box->setTextAlign(mBlockStyle.mAlign); box->setTextColour(mTextStyle.mColour); diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 8ce26e1d0..ddfd8f662 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -156,13 +156,14 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) MyGUI::Widget* next = keyFocusList[index]; int vertdiff = next->getTop() - focus->getTop(); int horizdiff = next->getLeft() - focus->getLeft(); - if (direction == D_Right && horizdiff <= 0) + bool isVertical = std::abs(vertdiff) > std::abs(horizdiff); + if (direction == D_Right && (horizdiff <= 0 || isVertical)) return false; - else if (direction == D_Left && horizdiff >= 0) + else if (direction == D_Left && (horizdiff >= 0 || isVertical)) return false; - else if (direction == D_Down && vertdiff <= 0) + else if (direction == D_Down && (vertdiff <= 0 || !isVertical)) return false; - else if (direction == D_Up && vertdiff >= 0) + else if (direction == D_Up && (vertdiff >= 0 || !isVertical)) return false; MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index a92ef92ab..ea811f5b1 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -47,6 +47,9 @@ namespace MWGui adjustButton(mCloseButton); adjustButton(mTakeButton); + mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + mTakeButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ScrollWindow::onKeyButtonPressed); + center(); } @@ -66,14 +69,28 @@ namespace MWGui // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mTextView->setVisibleVScroll(false); if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); + mTextView->setCanvasSize(mTextView->getWidth(), size.height); else - mTextView->setCanvasSize(410, mTextView->getSize().height); + mTextView->setCanvasSize(mTextView->getWidth(), mTextView->getSize().height); mTextView->setVisibleVScroll(true); mTextView->setViewOffset(MyGUI::IntPoint(0,0)); setTakeButtonShow(showTakeButton); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton); + } + + void ScrollWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + int scroll = 0; + if (key == MyGUI::KeyCode::ArrowUp) + scroll = 40; + else if (key == MyGUI::KeyCode::ArrowDown) + scroll = -40; + + if (scroll != 0) + mTextView->setViewOffset(mTextView->getViewOffset() + MyGUI::IntPoint(0, scroll)); } void ScrollWindow::setTakeButtonShow(bool show) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 35016e5dc..adc0bd93e 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -26,6 +26,7 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); void setTakeButtonShow(bool show); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); private: Gui::ImageButton* mCloseButton; From 0e57f1317b6dc7f0ebc6f14d73477296f6160a4e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 11:50:55 +0200 Subject: [PATCH 281/521] Remove redundant setVisible(false) --- apps/openmw/mwgui/jailscreen.cpp | 2 -- apps/openmw/mwgui/journalwindow.cpp | 1 - apps/openmw/mwgui/loadingscreen.cpp | 2 -- apps/openmw/mwgui/recharge.cpp | 2 -- apps/openmw/mwgui/screenfader.cpp | 1 - 5 files changed, 8 deletions(-) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 8ac133d76..11d7466a8 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -26,8 +26,6 @@ namespace MWGui { getWidget(mProgressBar, "ProgressBar"); - setVisible(false); - mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &JailScreen::onJailProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &JailScreen::onJailFinished); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index a0e424021..3a67e857d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -96,7 +96,6 @@ namespace JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) : JournalBooks (Model), JournalWindow() { - mMainWidget->setVisible(false); center(); adviseButtonClick (OptionsBTN, &JournalWindowImpl::notifyOptions ); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 15d9d555f..f22d825dd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -51,8 +51,6 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); - setVisible(false); - findSplashScreens(); } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 0398112ba..32da7876c 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -46,8 +46,6 @@ Recharge::Recharge() mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge); mGemIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onSelectItem); - - setVisible(false); } void Recharge::onOpen() diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 1d04e871e..76e79a348 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -74,7 +74,6 @@ namespace MWGui , mRepeat(false) { mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); - setVisible(false); MyGUI::ImageBox* imageBox = mMainWidget->castType(false); if (imageBox) From 2c4b0cc40800110b3cbcc92e7451c0c17709642b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:11:02 +0200 Subject: [PATCH 282/521] Hide sneak indicator by default --- files/mygui/openmw_hud.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 366b0c4c6..cee3f4682 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -82,6 +82,7 @@ + From 9ed1b165537561dd9b34dbb94a6940f40a4afcd5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:47:50 +0200 Subject: [PATCH 283/521] Extend code that detects whether a key was consumed by the GUI (Fixes #4016) --- apps/openmw/mwgui/windowmanagerimp.cpp | 25 ++++++++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8349ca0bc..6c69dffbc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2000,7 +2000,30 @@ namespace MWGui bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { if (!mKeyboardNavigation->injectKeyPress(key, text)) - return MyGUI::InputManager::getInstance().injectKeyPress(key, text); + { + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool widgetActive = MyGUI::InputManager::getInstance().injectKeyPress(key, text); + if (!widgetActive || !focus) + return false; + // FIXME: MyGUI doesn't allow widgets to state if a given key was actually used, so make a guess + if (focus->getTypeName().find("Button") != std::string::npos) + { + switch (key.getValue()) + { + case MyGUI::KeyCode::ArrowDown: + case MyGUI::KeyCode::ArrowUp: + case MyGUI::KeyCode::ArrowLeft: + case MyGUI::KeyCode::ArrowRight: + case MyGUI::KeyCode::Return: + case MyGUI::KeyCode::NumpadEnter: + case MyGUI::KeyCode::Space: + return true; + default: + return false; + } + } + return false; + } else return true; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cd17c5175..c5b18ff17 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -674,10 +674,11 @@ namespace MWInput bool consumed = false; if (kc != OIS::KC_UNASSIGNED) { - consumed = SDL_IsTextInputActive() && - ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)); // Little trick to check if key is printable - bool guiFocus = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); - setPlayerControlsEnabled(!guiFocus); + consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + if (SDL_IsTextInputActive() && // Little trick to check if key is printable + ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym))) + consumed = true; + setPlayerControlsEnabled(!consumed); } if (arg.repeat) return; From 843106fc616488ca174cd9d30d504254546fe631 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 12:58:14 +0200 Subject: [PATCH 284/521] Handle the wait progress bar as part of the GUI mode --- apps/openmw/mwgui/trainingwindow.cpp | 19 +++++++++++++------ apps/openmw/mwgui/trainingwindow.hpp | 4 ++++ apps/openmw/mwgui/waitdialog.cpp | 20 ++++++++++++-------- apps/openmw/mwgui/waitdialog.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index c1f7f8ac1..13a0a6883 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -51,12 +51,18 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &TrainingWindow::onTrainingProgressChanged); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &TrainingWindow::onTrainingFinished); - - mProgressBar.setVisible(false); } void TrainingWindow::onOpen() { + if (mTimeAdvancer.isRunning()) + { + mProgressBar.setVisible(true); + setVisible(false); + } + else + mProgressBar.setVisible(false); + center(); } @@ -166,15 +172,12 @@ namespace MWGui // add gold to NPC trading gold pool npcStats.setGoldPool(npcStats.getGoldPool() + price); - // go back to game mode - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - // advance time MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getWorld ()->advanceTime (2); + setVisible(false); mProgressBar.setVisible(true); mProgressBar.setProgress(0, 2); mTimeAdvancer.run(2); @@ -191,6 +194,10 @@ namespace MWGui void TrainingWindow::onTrainingFinished() { mProgressBar.setVisible(false); + + // go back to game mode + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 127c85f6a..fb7b10deb 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,10 +16,14 @@ namespace MWGui virtual void onOpen(); + bool exit() { return false; } + void setPtr(const MWWorld::Ptr& actor); void onFrame(float dt); + WindowBase* getProgressBar() { return &mProgressBar; } + void clear() { resetReference(); } protected: diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index cd1d29854..8a360435c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -75,8 +75,6 @@ namespace MWGui mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); - - mProgressBar.setVisible (false); } void WaitDialog::setPtr(const MWWorld::Ptr &ptr) @@ -86,11 +84,22 @@ namespace MWGui bool WaitDialog::exit() { - return (!mProgressBar.isVisible()); //Only exit if not currently waiting + return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } void WaitDialog::onOpen() { + if (mTimeAdvancer.isRunning()) + { + mProgressBar.setVisible(true); + setVisible(false); + return; + } + else + { + mProgressBar.setVisible(false); + } + if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { MWBase::Environment::get().getWindowManager()->popGuiMode (); @@ -262,11 +271,6 @@ namespace MWGui } } - void WaitDialog::clear() - { - mProgressBar.setVisible(false); - } - void WaitDialog::stopWaiting () { MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 6bd90473f..c7ccee025 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -34,12 +34,13 @@ namespace MWGui virtual bool exit(); void onFrame(float dt); - void clear(); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } void wakeUp(); void autosave(); + WindowBase* getProgressBar() { return &mProgressBar; } + protected: MyGUI::TextBox* mDateTimeText; MyGUI::TextBox* mRestText; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6c69dffbc..c572bce54 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -414,7 +414,7 @@ namespace MWGui mWaitDialog = new WaitDialog(); mWindows.push_back(mWaitDialog); - mGuiModeStates[GM_Rest] = GuiModeState(mWaitDialog); + mGuiModeStates[GM_Rest] = GuiModeState({mWaitDialog->getProgressBar(), mWaitDialog}); SpellCreationDialog* spellCreationDialog = new SpellCreationDialog(); mWindows.push_back(spellCreationDialog); @@ -426,7 +426,7 @@ namespace MWGui TrainingWindow* trainingWindow = new TrainingWindow(); mWindows.push_back(trainingWindow); - mGuiModeStates[GM_Training] = GuiModeState(trainingWindow); + mGuiModeStates[GM_Training] = GuiModeState({trainingWindow->getProgressBar(), trainingWindow}); MerchantRepair* merchantRepair = new MerchantRepair(); mWindows.push_back(merchantRepair); From 8ae7e4c958a0b59a0b555b9c60a227521f5da327 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:05:52 +0200 Subject: [PATCH 285/521] Make Enter on a name edit accept the dialog --- apps/openmw/mwgui/alchemywindow.cpp | 9 +++++++++ apps/openmw/mwgui/alchemywindow.hpp | 1 + apps/openmw/mwgui/enchantingdialog.cpp | 8 ++++++++ apps/openmw/mwgui/enchantingdialog.hpp | 3 ++- apps/openmw/mwgui/spellcreationdialog.cpp | 6 ++++++ apps/openmw/mwgui/spellcreationdialog.hpp | 1 + 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 5b1489821..0140653a1 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -54,9 +54,16 @@ namespace MWGui mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); + mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept); + center(); } + void AlchemyWindow::onAccept(MyGUI::EditBox* sender) + { + onCreateButtonClicked(sender); + } + void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); @@ -128,6 +135,8 @@ namespace MWGui } update(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit); } void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index a27d9c749..2d13a346a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -44,6 +44,7 @@ namespace MWGui void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); void onIngredientSelected(MyGUI::Widget* _sender); + void onAccept(MyGUI::EditBox*); void onSelectedItem(int index); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 88973bd46..74d80d292 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -53,6 +54,7 @@ namespace MWGui mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); + mName->eventEditSelectAccept += MyGUI::newDelegate(this, &EnchantingDialog::onAccept); } EnchantingDialog::~EnchantingDialog() @@ -63,6 +65,7 @@ namespace MWGui void EnchantingDialog::onOpen() { center(); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mName); } void EnchantingDialog::setSoulGem(const MWWorld::Ptr &gem) @@ -284,6 +287,11 @@ namespace MWGui updateEffectsView(); } + void EnchantingDialog::onAccept(MyGUI::EditBox *sender) + { + onBuyButtonClicked(sender); + } + void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) { if (mEffects.size() <= 0) diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 39614ebd1..4906de919 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -48,6 +48,7 @@ namespace MWGui void onBuyButtonClicked(MyGUI::Widget* sender); void updateLabels(); void onTypeButtonClicked(MyGUI::Widget* sender); + void onAccept(MyGUI::EditBox* sender); ItemSelectionDialog* mItemSelectionDialog; @@ -60,7 +61,7 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; - MyGUI::TextBox* mName; + MyGUI::EditBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index d5dee1139..4aa208d8f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -349,6 +349,7 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onCancelButtonClicked); mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onBuyButtonClicked); + mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SpellCreationDialog::onAccept); setWidgets(mAvailableEffectsList, mUsedEffectsView); } @@ -416,6 +417,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } + void SpellCreationDialog::onAccept(MyGUI::EditBox *sender) + { + onBuyButtonClicked(sender); + } + void SpellCreationDialog::onOpen() { center(); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 855016666..ec90fa3ce 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -162,6 +162,7 @@ namespace MWGui void onCancelButtonClicked (MyGUI::Widget* sender); void onBuyButtonClicked (MyGUI::Widget* sender); + void onAccept(MyGUI::EditBox* sender); virtual void notifyEffectsChanged (); From 67dc4e019acb554b6d36f02eb73f3ef7b190848d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:10:50 +0200 Subject: [PATCH 286/521] Make Enter on trade window price attempt the trade --- apps/openmw/mwgui/tradewindow.cpp | 8 ++++++++ apps/openmw/mwgui/tradewindow.hpp | 1 + 2 files changed, 9 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index feccfd942..c2e58b81f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -96,6 +96,7 @@ namespace MWGui mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged); + mTotalBalance->eventEditSelectAccept += MyGUI::newDelegate(this, &TradeWindow::onAccept); mTotalBalance->setMinValue(INT_MIN+1); // disallow INT_MIN since abs(INT_MIN) is undefined setCoord(400, 0, 400, 300); @@ -140,6 +141,8 @@ namespace MWGui setTitle(actor.getClass().getName(actor)); onFilterChanged(mFilterAll); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTotalBalance); } void TradeWindow::onFrame(float dt) @@ -364,6 +367,11 @@ namespace MWGui restock(); } + void TradeWindow::onAccept(MyGUI::EditBox *sender) + { + onOfferButtonClicked(sender); + } + void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { exit(); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 00f38024d..fc692a55a 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -84,6 +84,7 @@ namespace MWGui void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); + void onAccept(MyGUI::EditBox* sender); void onCancelButtonClicked(MyGUI::Widget* _sender); void onMaxSaleButtonClicked(MyGUI::Widget* _sender); void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); From 76ddf8d794dc9cc847297c7f994635028ffb1fcb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:17:08 +0200 Subject: [PATCH 287/521] Support Up/DownArrow keys to change NumericEditBox value --- components/widgets/numericeditbox.cpp | 16 ++++++++++++++++ components/widgets/numericeditbox.hpp | 1 + 2 files changed, 17 insertions(+) diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index 828a84589..6e884a091 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -75,4 +75,20 @@ namespace Gui setCaption(MyGUI::utility::toString(mValue)); } + void NumericEditBox::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + { + setValue(std::min(mValue+1, mMaxValue)); + eventValueChanged(mValue); + } + else if (key == MyGUI::KeyCode::ArrowDown) + { + setValue(std::max(mValue-1, mMinValue)); + eventValueChanged(mValue); + } + else + Base::onKeyButtonPressed(key, character); + } + } diff --git a/components/widgets/numericeditbox.hpp b/components/widgets/numericeditbox.hpp index 20000b3d3..ca7674f22 100644 --- a/components/widgets/numericeditbox.hpp +++ b/components/widgets/numericeditbox.hpp @@ -33,6 +33,7 @@ namespace Gui private: void onEditTextChange(MyGUI::EditBox* sender); void onKeyLostFocus(MyGUI::Widget* _new); + void onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char character); int mValue; From ca3b08b85202ed40845e93bed9800d02f0d86859 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:49:35 +0200 Subject: [PATCH 288/521] Make Activate key accept GUI buttons --- apps/openmw/mwinput/inputmanagerimp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c5b18ff17..79c689561 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -162,14 +162,13 @@ namespace MWInput void InputManager::setPlayerControlsEnabled(bool enabled) { - int nPlayerChannels = 18; - int playerChannels[] = {A_Activate, A_AutoMove, A_AlwaysRun, A_ToggleWeapon, + int playerChannels[] = {A_AutoMove, A_AlwaysRun, A_ToggleWeapon, A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10, A_Use, A_Journal}; - for(int i = 0; i < nPlayerChannels; i++) { + for(size_t i = 0; i < sizeof(playerChannels)/sizeof(playerChannels[0]); i++) { int pc = playerChannels[i]; mInputBinder->getChannel(pc)->setEnabled(enabled); } @@ -234,8 +233,7 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - activate(); + activate(); break; case A_Journal: toggleJournal (); @@ -1080,7 +1078,9 @@ namespace MWInput void InputManager::activate() { - if (mControlSwitch["playercontrols"]) + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From 94b538ac829553ba994054206b50aa90a6299785 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 13:57:09 +0200 Subject: [PATCH 289/521] Fix crash due to not calling WindowModal::onClose() --- apps/openmw/mwgui/race.cpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 2b407ac93..64609cbe6 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -187,6 +187,8 @@ namespace MWGui void RaceDialog::onClose() { + WindowModal::onClose(); + mPreviewImage->setRenderItemTexture(NULL); mPreviewTexture.reset(NULL); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c572bce54..d734d7540 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1738,9 +1738,12 @@ namespace MWGui // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, //so just popping the top would cause massive issues. if(!mCurrentModals.empty()) + { if(input == mCurrentModals.top()) mCurrentModals.pop(); - + else + std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; + } if (mCurrentModals.empty()) mKeyboardNavigation->restoreFocus(getMode()); } From ad8d0c53024d82464cf7a2861ce2908f3252efad Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 15:32:44 +0200 Subject: [PATCH 290/521] Use keypad to control the camera --- apps/openmw/mwinput/inputmanagerimp.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 79c689561..b1f80cae6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1215,6 +1215,17 @@ namespace MWInput control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } + + if (i == A_LookLeftRight && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_4) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_6)) + { + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_6, ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_4, ICS::Control::DECREASE); + } + if (i == A_LookUpDown && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_8) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_2)) + { + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_2, ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_8, ICS::Control::DECREASE); + } } } } From c035548f3737a24e1b699b770c4bba753d806641 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 19:00:51 +0200 Subject: [PATCH 291/521] Make Tab work if selected widget is marked as not needing keyfocus --- apps/openmw/mwgui/keyboardnavigation.cpp | 26 ++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index ddfd8f662..da99c72d0 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -63,12 +63,6 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) w.second = nullptr; } -bool isButtonFocus() -{ - MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - return focus->getTypeName().find("Button") != std::string::npos; -} - enum Direction { D_Left, @@ -106,7 +100,13 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - if (!focus && (direction == D_Next || direction == D_Prev)) + if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) + return false; + + if (focus && (direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + return false; + + if ((!focus || !focus->getNeedKeyFocus()) && (direction == D_Next || direction == D_Prev)) { // if nothing is selected, select the first widget MyGUI::VectorWidgetPtr keyFocusList; @@ -120,20 +120,12 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) return true; } } - if (!focus) return false; - if (!isButtonFocus() && direction != D_Prev && direction != D_Next) - return false; - - if ((direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") - return false; - - MyGUI::Widget* window = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - while (window->getParent()) + MyGUI::Widget* window = focus; + while (window && window->getParent()) window = window->getParent(); - MyGUI::VectorWidgetPtr keyFocusList; getKeyFocusWidgets(window, keyFocusList); From d78e8228331826976f17f8a37801c8eed7488232 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 24 Sep 2017 19:15:39 +0200 Subject: [PATCH 292/521] Add 'delay' argument for screen fading operations --- apps/openmw/mwbase/windowmanager.hpp | 6 +++--- apps/openmw/mwgui/screenfader.cpp | 29 ++++++++++++++++---------- apps/openmw/mwgui/screenfader.hpp | 11 +++++----- apps/openmw/mwgui/trainingwindow.cpp | 11 +--------- apps/openmw/mwgui/trainingwindow.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++--- 7 files changed, 37 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 43d99b6b3..2df3113b3 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -317,11 +317,11 @@ namespace MWBase virtual void pinWindow (MWGui::GuiWindow window) = 0; /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time, bool clearQueue=true) = 0; + virtual void fadeScreenIn(const float time, bool clearQueue=true, float delay=0.f) = 0; /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time, bool clearQueue=true) = 0; + virtual void fadeScreenOut(const float time, bool clearQueue=true, float delay=0.f) = 0; /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true) = 0; + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true, float delay=0.f) = 0; /// Darken the screen to a specified percentage virtual void setBlindness(const int percent) = 0; diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index 76e79a348..d1118848b 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -6,12 +6,13 @@ namespace MWGui { - FadeOp::FadeOp(ScreenFader * fader, float time, float targetAlpha) + FadeOp::FadeOp(ScreenFader * fader, float time, float targetAlpha, float delay) : mFader(fader), - mRemainingTime(time), + mRemainingTime(time+delay), mTargetTime(time), mTargetAlpha(targetAlpha), mStartAlpha(0.f), + mDelay(delay), mRunning(false) { } @@ -26,7 +27,7 @@ namespace MWGui if (mRunning) return; - mRemainingTime = mTargetTime; + mRemainingTime = mTargetTime + mDelay; mStartAlpha = mFader->getCurrentAlpha(); mRunning = true; } @@ -42,6 +43,12 @@ namespace MWGui return; } + if (mRemainingTime > mTargetTime) + { + mRemainingTime -= dt; + return; + } + float currentAlpha = mFader->getCurrentAlpha(); if (mStartAlpha > mTargetAlpha) { @@ -103,19 +110,19 @@ namespace MWGui mMainWidget->setAlpha(1.f-((1.f-mCurrentAlpha) * mFactor)); } - void ScreenFader::fadeIn(float time) + void ScreenFader::fadeIn(float time, float delay) { - queue(time, 1.f); + queue(time, 1.f, delay); } - void ScreenFader::fadeOut(const float time) + void ScreenFader::fadeOut(const float time, float delay) { - queue(time, 0.f); + queue(time, 0.f, delay); } - void ScreenFader::fadeTo(const int percent, const float time) + void ScreenFader::fadeTo(const int percent, const float time, float delay) { - queue(time, percent/100.f); + queue(time, percent/100.f, delay); } void ScreenFader::clear() @@ -135,7 +142,7 @@ namespace MWGui mRepeat = repeat; } - void ScreenFader::queue(float time, float targetAlpha) + void ScreenFader::queue(float time, float targetAlpha, float delay) { if (time < 0.f) return; @@ -147,7 +154,7 @@ namespace MWGui return; } - mQueue.push_back(FadeOp::Ptr(new FadeOp(this, time, targetAlpha))); + mQueue.push_back(FadeOp::Ptr(new FadeOp(this, time, targetAlpha, delay))); } bool ScreenFader::isEmpty() diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 19468de3c..88dd0c57b 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -14,7 +14,7 @@ namespace MWGui public: typedef std::shared_ptr Ptr; - FadeOp(ScreenFader * fader, float time, float targetAlpha); + FadeOp(ScreenFader * fader, float time, float targetAlpha, float delay); bool isRunning(); @@ -28,6 +28,7 @@ namespace MWGui float mTargetTime; float mTargetAlpha; float mStartAlpha; + float mDelay; bool mRunning; }; @@ -38,16 +39,16 @@ namespace MWGui void update(float dt); - void fadeIn(const float time); - void fadeOut(const float time); - void fadeTo(const int percent, const float time); + void fadeIn(const float time, float delay=0); + void fadeOut(const float time, float delay=0); + void fadeTo(const int percent, const float time, float delay=0); void clear(); void setFactor (float factor); void setRepeat(bool repeat); - void queue(float time, float targetAlpha); + void queue(float time, float targetAlpha, float delay); bool isEmpty(); void clearQueue(); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 13a0a6883..120ab5cba 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,6 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") - , mFadeTimeRemaining(0) , mTimeAdvancer(0.05f) { getWidget(mTrainingOptions, "TrainingOptions"); @@ -183,7 +182,7 @@ namespace MWGui mTimeAdvancer.run(2); MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); - mFadeTimeRemaining = 0.5; + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25, false, 0.25); } void TrainingWindow::onTrainingProgressChanged(int cur, int total) @@ -204,13 +203,5 @@ namespace MWGui { checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); - - if (mFadeTimeRemaining <= 0) - return; - - mFadeTimeRemaining -= dt; - - if (mFadeTimeRemaining <= 0) - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25); } } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index fb7b10deb..69a013059 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -39,8 +39,6 @@ namespace MWGui MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - float mFadeTimeRemaining; - WaitDialogProgressBar mProgressBar; TimeAdvancer mTimeAdvancer; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d734d7540..6be754109 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1788,25 +1788,25 @@ namespace MWGui updateVisible(); } - void WindowManager::fadeScreenIn(const float time, bool clearQueue) + void WindowManager::fadeScreenIn(const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeOut(time); + mScreenFader->fadeOut(time, delay); } - void WindowManager::fadeScreenOut(const float time, bool clearQueue) + void WindowManager::fadeScreenOut(const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeIn(time); + mScreenFader->fadeIn(time, delay); } - void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) + void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue, float delay) { if (clearQueue) mScreenFader->clearQueue(); - mScreenFader->fadeTo(percent, time); + mScreenFader->fadeTo(percent, time, delay); } void WindowManager::setBlindness(const int percent) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f315bb906..56e7d9b7b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -344,11 +344,11 @@ namespace MWGui virtual void pinWindow (MWGui::GuiWindow window); /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time, bool clearQueue); + virtual void fadeScreenIn(const float time, bool clearQueue, float delay); /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time, bool clearQueue); + virtual void fadeScreenOut(const float time, bool clearQueue, float delay); /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time, bool clearQueue); + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue, float delay); /// Darken the screen to a specified percentage virtual void setBlindness(const int percent); From e4c9d8466628061da92779695c0d0eb08746eff6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 01:03:16 +0200 Subject: [PATCH 293/521] Disable NeedKey for ScrollView skins The widget is set to accept key focus by default for no reason I can tell. Fix in MyGUI TBD --- files/mygui/openmw_map_window.skin.xml | 1 + files/mygui/openmw_scroll.skin.xml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/files/mygui/openmw_map_window.skin.xml b/files/mygui/openmw_map_window.skin.xml index 31a70191f..f6c099630 100644 --- a/files/mygui/openmw_map_window.skin.xml +++ b/files/mygui/openmw_map_window.skin.xml @@ -2,6 +2,7 @@ + diff --git a/files/mygui/openmw_scroll.skin.xml b/files/mygui/openmw_scroll.skin.xml index 415c2479a..cff0ad7eb 100644 --- a/files/mygui/openmw_scroll.skin.xml +++ b/files/mygui/openmw_scroll.skin.xml @@ -3,11 +3,13 @@ + + From 82a211ba030bce61618d6820b9db2787d0a6b936 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 17:47:30 +0200 Subject: [PATCH 294/521] Fix duplicate code --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 14 +------------- components/esm/loadnpc.hpp | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index fb4ba1016..bacbd7b2b 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -365,19 +365,7 @@ namespace MWDialogue } // check the available services of this actor - int services = 0; - if (mActor.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } - else if (mActor.getTypeName() == typeid(ESM::Creature).name()) - { - MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->mBase->mHasAI) - services = ref->mBase->mAiData.mServices; - } + int services = mActor.getClass().getServices(mActor); int windowServices = 0; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 5b89f4055..019baa297 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -46,7 +46,7 @@ struct NPC // Other services Spells = 0x00800, MagicItems = 0x01000, - Training = 0x04000, // What skills? + Training = 0x04000, Spellmaking = 0x08000, Enchanting = 0x10000, Repair = 0x20000 From b7752ec52de5489583fe174f2df2381c5777b06c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 18:07:49 +0200 Subject: [PATCH 295/521] Make TradeWindow not depend on DialogueWindow --- apps/openmw/mwgui/dialogue.cpp | 5 +++++ apps/openmw/mwgui/dialogue.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 4 +--- apps/openmw/mwgui/tradewindow.hpp | 3 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ec6dcb2cb..86aa64e8b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -270,6 +270,11 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + void DialogueWindow::onTradeComplete() + { + addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); + } + bool DialogueWindow::exit() { if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 224ecba66..dbb33969f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -99,6 +99,8 @@ namespace MWGui public: DialogueWindow(); + void onTradeComplete(); + virtual bool exit(); // Events diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c2e58b81f..341167ab7 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -27,7 +27,6 @@ #include "containeritemmodel.hpp" #include "tradeitemmodel.hpp" #include "countdialog.hpp" -#include "dialogue.hpp" #include "controllers.hpp" namespace @@ -358,8 +357,7 @@ namespace MWGui mPtr.getClass().getCreatureStats(mPtr).getGoldPool() - mCurrentBalance ); } - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( - MWBase::Environment::get().getWorld()->getStore().get().find("sBarterDialog5")->getString()); + eventTradeDone(); MWBase::Environment::get().getWindowManager()->playSound("Item Gold Up"); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index fc692a55a..514d24022 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -41,6 +41,9 @@ namespace MWGui virtual void resetReference(); + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_TradeDone; + EventHandle_TradeDone eventTradeDone; + private: ItemView* mItemView; SortFilterItemModel* mSortModel; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6be754109..76f0b029d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -337,7 +337,6 @@ namespace MWGui mTradeWindow = new TradeWindow(); mWindows.push_back(mTradeWindow); trackWindow(mTradeWindow, "barter"); - mGuiModeStates[GM_Barter] = GuiModeState({mInventoryWindow, mTradeWindow}); mConsole = new Console(w,h, mConsoleOnlyScripts); @@ -366,6 +365,7 @@ namespace MWGui mWindows.push_back(mDialogueWindow); trackWindow(mDialogueWindow, "dialogue"); mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); + mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete); ContainerWindow* containerWindow = new ContainerWindow(mDragAndDrop); mWindows.push_back(containerWindow); From f8ffd851461219cd5b7909b91dbf807f36b17a30 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 18:50:24 +0200 Subject: [PATCH 296/521] Topic passed to keywordSelected() no longer has to be lower case Remove redundant mDialogueMap --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 42 ++++++++----------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 3 +- apps/openmw/mwgui/dialogue.cpp | 23 ++-------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index bacbd7b2b..c29476c7f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -60,15 +60,6 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; mCompilerContext.setExtensions (&extensions); - - const MWWorld::Store &dialogs = - MWBase::Environment::get().getWorld()->getStore().get(); - - MWWorld::Store::iterator it = dialogs.begin(); - for (; it != dialogs.end(); ++it) - { - mDialogueMap[Misc::StringUtils::lowerCase(it->mId)] = *it; - } } void DialogueManager::clear() @@ -171,7 +162,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false); executeScript (info->mResultScript, mActor); - mLastTopic = Misc::StringUtils::lowerCase(it->mId); + mLastTopic = it->mId; // update topics again to accommodate changes resulting from executeScript updateTopics(); @@ -310,7 +301,7 @@ namespace MWDialogue { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor); + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(topic), info->mId, mActor); break; } } @@ -327,6 +318,11 @@ namespace MWDialogue } } + const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) + { + return MWBase::Environment::get().getWorld()->getStore().get().search(id); + } + void DialogueManager::updateGlobals() { MWBase::Environment::get().getWorld()->updateDialogueGlobals(); @@ -416,12 +412,10 @@ namespace MWDialogue { if(!mIsInChoice) { - if(mDialogueMap.find(keyword) != mDialogueMap.end()) + const ESM::Dialogue* dialogue = searchDialogue(keyword); + if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) - { - executeTopic (keyword); - } + executeTopic (keyword); } } @@ -456,14 +450,14 @@ namespace MWDialogue { mChoice = answer; - if (mDialogueMap.find(mLastTopic) != mDialogueMap.end()) + const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); + if (dialogue) { Filter filter (mActor, mChoice, mTalkedTo); - if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic - || mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting) + if (dialogue->mType == ESM::Dialogue::Topic || dialogue->mType == ESM::Dialogue::Greeting) { - if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) + if (const ESM::DialInfo *info = filter.search (*dialogue, true)) { std::string text = info->mResponse; parseText (text); @@ -477,12 +471,12 @@ namespace MWDialogue // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. - for (ESM::Dialogue::InfoContainer::const_iterator iter = mDialogueMap[mLastTopic].mInfo.begin(); - iter!=mDialogueMap[mLastTopic].mInfo.end(); ++iter) + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue->mInfo.begin(); + iter!=dialogue->mInfo.end(); ++iter) { if (iter->mId == info->mId) { - MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor); + MWBase::Environment::get().getJournal()->addTopic (Misc::StringUtils::lowerCase(mLastTopic), info->mId, mActor); break; } } @@ -737,7 +731,7 @@ namespace MWDialogue if (actor == mActor && !mLastTopic.empty()) { MWBase::Environment::get().getJournal()->removeLastAddedTopicResponse( - mLastTopic, actor.getClass().getName(actor)); + Misc::StringUtils::lowerCase(mLastTopic), actor.getClass().getName(actor)); } } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 40a24a1f8..81bd2f2b9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -22,7 +22,6 @@ namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - std::map mDialogueMap; std::set mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. > @@ -56,6 +55,8 @@ namespace MWDialogue void executeTopic (const std::string& topic); + const ESM::Dialogue* searchDialogue(const std::string& id); + public: DialogueManager (const Compiler::Extensions& extensions, Translation::Storage& translationDataStorage); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 86aa64e8b..95fa042cf 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -223,7 +223,7 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId); } void Goodbye::activated() @@ -328,7 +328,7 @@ namespace MWGui } if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(topic)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(topic); else { const MWWorld::Store &gmst = @@ -552,24 +552,7 @@ namespace MWGui void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) { - // This is called from the dialogue manager, so text is - // case-smashed - thus we have to retrieve the correct case - // of the title through the topic list. - std::string realTitle = title; - if (realTitle != "") - { - for (size_t i=0; igetItemCount(); ++i) - { - std::string item = mTopicsList->getItemNameAt(i); - if (Misc::StringUtils::ciEqual(item, title)) - { - realTitle = item; - break; - } - } - } - - mHistoryContents.push_back(new Response(text, realTitle, needMargin)); + mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); } From 19e07fad30bb43f0d474f9326fadbc44ab8b894a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:52:20 +0200 Subject: [PATCH 297/521] Remove redundant Services enum --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 39 ------------------- apps/openmw/mwgui/dialogue.cpp | 20 ++++++---- apps/openmw/mwgui/dialogue.hpp | 16 -------- components/esm/loadnpc.hpp | 2 + 4 files changed, 14 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c29476c7f..dea942349 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -360,47 +360,8 @@ namespace MWDialogue } } - // check the available services of this actor - int services = mActor.getClass().getServices(mActor); - - int windowServices = 0; - - if (services & ESM::NPC::Weapon - || services & ESM::NPC::Armor - || services & ESM::NPC::Clothing - || services & ESM::NPC::Books - || services & ESM::NPC::Ingredients - || services & ESM::NPC::Picks - || services & ESM::NPC::Probes - || services & ESM::NPC::Lights - || services & ESM::NPC::Apparatus - || services & ESM::NPC::RepairItem - || services & ESM::NPC::Misc) - windowServices |= MWGui::DialogueWindow::Service_Trade; - - if((mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->getTransport().empty()) - || (mActor.getTypeName() == typeid(ESM::Creature).name() && !mActor.get()->mBase->getTransport().empty())) - windowServices |= MWGui::DialogueWindow::Service_Travel; - - if (services & ESM::NPC::Spells) - windowServices |= MWGui::DialogueWindow::Service_BuySpells; - - if (services & ESM::NPC::Spellmaking) - windowServices |= MWGui::DialogueWindow::Service_CreateSpells; - - if (services & ESM::NPC::Training) - windowServices |= MWGui::DialogueWindow::Service_Training; - - if (services & ESM::NPC::Enchanting) - windowServices |= MWGui::DialogueWindow::Service_Enchant; - - if (services & ESM::NPC::Repair) - windowServices |= MWGui::DialogueWindow::Service_Repair; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->setServices (windowServices); - // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); win->setKeywords(keywordList); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 95fa042cf..e4d0af424 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -237,7 +237,6 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mServices(0) , mEnabled(false) , mGoodbye(false) , mPersuasionDialog() @@ -411,6 +410,11 @@ namespace MWGui mTopicLinks.clear(); mKeywordSearch.clear(); + int services = mPtr.getClass().getServices(mPtr); + + bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get()->mBase->getTransport().empty()) + || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get()->mBase->getTransport().empty()); + bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); @@ -420,25 +424,25 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addItem(gmst.find("sPersuasion")->getString()); - if (mServices & Service_Trade) + if (services & ESM::NPC::AllItems) mTopicsList->addItem(gmst.find("sBarter")->getString()); - if (mServices & Service_BuySpells) + if (services & ESM::NPC::Spells) mTopicsList->addItem(gmst.find("sSpells")->getString()); - if (mServices & Service_Travel) + if (services & travel) mTopicsList->addItem(gmst.find("sTravel")->getString()); - if (mServices & Service_CreateSpells) + if (services & ESM::NPC::Spellmaking) mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - if (mServices & Service_Enchant) + if (services & ESM::NPC::Enchanting) mTopicsList->addItem(gmst.find("sEnchanting")->getString()); - if (mServices & Service_Training) + if (services & ESM::NPC::Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - if (mServices & Service_Repair) + if (services & ESM::NPC::Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); if (isCompanion) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index dbb33969f..af5fe5efc 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -122,20 +122,6 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - // make sure to call these before setKeywords() - void setServices(int services) { mServices = services; } - - enum Services - { - Service_Trade = 0x01, - Service_BuySpells = 0x02, - Service_CreateSpells = 0x04, - Service_Enchant = 0x08, - Service_Training = 0x10, - Service_Travel = 0x20, - Service_Repair = 0x40 - }; - protected: void onSelectTopic(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); @@ -152,8 +138,6 @@ namespace MWGui void updateOptions(); void restock(); - int mServices; - bool mEnabled; bool mGoodbye; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 019baa297..d7f30e079 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -43,6 +43,8 @@ struct NPC Misc = 0x00400, Potions = 0x02000, + AllItems = Weapon|Armor|Clothing|Books|Ingredients|Picks|Probes|Lights|Apparatus|RepairItem|Misc|Potions, + // Other services Spells = 0x00800, MagicItems = 0x01000, From e14573fa8c05f6e41cbfa74cb6c3a31c4d0f990c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:53:42 +0200 Subject: [PATCH 298/521] Add missing null check --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e4d0af424..920183c61 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -625,7 +625,7 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); - if(mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(!mPtr.isEmpty() && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); mDispositionBar->setProgressRange(100); From 717e68fab21b4243118b06e61f74756cbdc1a130 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 19:58:34 +0200 Subject: [PATCH 299/521] Remove redundant resetHistory argument --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 5 +---- apps/openmw/mwgui/dialogue.cpp | 5 +++-- apps/openmw/mwgui/dialogue.hpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index dea942349..29bb49ca0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -127,9 +127,6 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - // If the dialogue window was already open, keep the existing history - bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue)); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -145,7 +142,7 @@ namespace MWDialogue { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - win->startDialogue(actor, actor.getClass().getName (actor), resetHistory); + win->startDialogue(actor, actor.getClass().getName (actor)); creatureStats.talkedToPlayer(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 920183c61..4ec3da50b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -283,6 +283,7 @@ namespace MWGui } else { + resetReference(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); mTopicsList->scrollToTop(); return true; @@ -357,7 +358,7 @@ namespace MWGui } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory) + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); @@ -372,7 +373,7 @@ namespace MWGui mTopicsList->clear(); - if (resetHistory || !sameActor) + if (!sameActor) { for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index af5fe5efc..b854e6c1a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -108,7 +108,7 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory); + void startDialogue(MWWorld::Ptr actor, std::string npcName); void setKeywords(std::list keyWord); void addResponse (const std::string& text, const std::string& title="", bool needMargin = true); From 36c192a1ddf98efb6ee4cf551353708316c91ae8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:03:52 +0200 Subject: [PATCH 300/521] Undo the console portion of 84657271c760 because it results in the console forgetting its object on opening --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/console.cpp | 6 +++--- apps/openmw/mwgui/console.hpp | 5 +---- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2df3113b3..51a17d380 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -151,6 +151,8 @@ namespace MWBase virtual void updateSpellWindow() = 0; + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; + /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 182b6ef97..6094111f8 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -417,7 +417,7 @@ namespace MWGui setCoord(10,10, width-10, height/2); } - void Console::setPtr(const MWWorld::Ptr& object) + void Console::setSelectedObject(const MWWorld::Ptr& object) { if (!object.isEmpty()) { @@ -443,12 +443,12 @@ namespace MWGui void Console::onReferenceUnavailable() { - setPtr(MWWorld::Ptr()); + setSelectedObject(MWWorld::Ptr()); } void Console::resetReference() { ReferenceInterface::resetReference(); - setPtr(MWWorld::Ptr()); + setSelectedObject(MWWorld::Ptr()); } } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index f243b8387..f5647e9ea 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -25,7 +25,7 @@ namespace MWGui { public: /// Set the implicit object for script execution - void setPtr(const MWWorld::Ptr& object); + void setSelectedObject(const MWWorld::Ptr& object); MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; @@ -42,12 +42,9 @@ namespace MWGui virtual void onOpen(); virtual void onClose(); - void onFrame(float dt) { checkReferenceAvailable(); } - void setFont(const std::string &fntName); void onResChange(int width, int height); - void clear() { resetReference(); } // Print a message to the console, in specified color. void print(const std::string &msg, const std::string& color = "#FFFFFF"); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 779e358d3..1db2691f4 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -260,7 +260,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Console, object); + MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 76f0b029d..85f57a75e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1884,6 +1884,11 @@ namespace MWGui mSpellWindow->updateSpells(); } + void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) + { + mConsole->setSelectedObject(object); + } + std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 56e7d9b7b..53b2dc33a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -190,6 +190,8 @@ namespace MWGui virtual void updateSpellWindow(); + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); + ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); From e8c6a3b225828fac735ba7b409ddccc9446e7640 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:21:51 +0200 Subject: [PATCH 301/521] Fix crash in dialogue filter if local variables are not configured This could happen e.g. by 'some_npc_in_remote_cell->forcegreeting' --- apps/openmw/mwdialogue/filter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 67bb53e71..e8757e4a3 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -193,7 +193,8 @@ bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& sele return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); - + if (locals.isEmpty()) + return select.selectCompare(0); switch (type) { case 's': return select.selectCompare (static_cast (locals.mShorts[index])); From c5613e384ea3dae8af6c6d8521e102a65424fb9c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:29:06 +0200 Subject: [PATCH 302/521] Remove duplicate disposition code --- apps/openmw/mwgui/dialogue.cpp | 17 ++++------------- apps/openmw/mwgui/dialogue.hpp | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4ec3da50b..869b83928 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -384,7 +384,7 @@ namespace MWGui delete (*it); mLinks.clear(); - updateOptions(); + updateDisposition(); restock(); } @@ -579,13 +579,10 @@ namespace MWGui updateHistory(); } - void DialogueWindow::updateOptions() + void DialogueWindow::updateDisposition() { - //Clear the list of topics - mTopicsList->clear(); - bool dispositionVisible = false; - if (mPtr.getClass().isNpc()) + if (!mPtr.isEmpty() && mPtr.getClass().isNpc()) { dispositionVisible = true; mDispositionBar->setProgressRange(100); @@ -626,12 +623,6 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); - if(!mPtr.isEmpty() && mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - int disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(disp); - mDispositionText->setCaption(MyGUI::utility::toString(disp)+std::string("/100")); - } + updateDisposition(); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index b854e6c1a..83f1eb1de 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -135,7 +135,7 @@ namespace MWGui virtual void onReferenceUnavailable(); private: - void updateOptions(); + void updateDisposition(); void restock(); bool mEnabled; From 476bec41c5c80c98981b491a6ca9593146c07901 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:47:35 +0200 Subject: [PATCH 303/521] Remove redundant code --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 29bb49ca0..ffa26e211 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -330,14 +330,12 @@ namespace MWDialogue updateGlobals(); std::list keywordList; - int choice = mChoice; - mChoice = -1; mActorKnownTopics.clear(); const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); - Filter filter (mActor, mChoice, mTalkedTo); + Filter filter (mActor, -1, mTalkedTo); for (MWWorld::Store::iterator iter = dialogs.begin(); iter != dialogs.end(); ++iter) { @@ -362,8 +360,6 @@ namespace MWDialogue // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); win->setKeywords(keywordList); - - mChoice = choice; } void DialogueManager::keywordSelected (const std::string& keyword) From 2ce79e07a461d4be141a4c5574474d7b9116467b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 25 Sep 2017 21:38:38 +0200 Subject: [PATCH 304/521] Refactor dialogue GUI to talk to the dialogue manager, not the other way around and not both ways. - Fix memory leaks in DialogueWindow - Fix Link objects being deleted from their own event handler --- apps/openmw/mwbase/dialoguemanager.hpp | 21 ++- apps/openmw/mwbase/windowmanager.hpp | 1 - apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 125 +++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 24 ++- apps/openmw/mwgui/dialogue.cpp | 152 ++++++++++++------ apps/openmw/mwgui/dialogue.hpp | 39 +++-- apps/openmw/mwgui/enchantingdialog.cpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 1 + apps/openmw/mwgui/trainingwindow.cpp | 1 + apps/openmw/mwgui/travelwindow.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.hpp | 1 - apps/openmw/mwscript/dialogueextensions.cpp | 5 +- apps/openmw/mwworld/actiontalk.cpp | 4 +- 14 files changed, 229 insertions(+), 148 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 18f249e56..c928fa940 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -2,6 +2,8 @@ #define GAME_MWBASE_DIALOGUEMANAGER_H #include +#include +#include #include @@ -42,24 +44,29 @@ namespace MWBase virtual bool isInChoice() const = 0; - virtual void startDialogue (const MWWorld::Ptr& actor) = 0; + typedef std::pair Response; // title, text + virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response) = 0; virtual void addTopic (const std::string& topic) = 0; - virtual void askQuestion (const std::string& question,int choice) = 0; + virtual void addChoice (const std::string& text,int choice) = 0; + virtual const std::vector >& getChoices() = 0; + + virtual bool isGoodbye() = 0; virtual void goodbye() = 0; virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0; - //calbacks for the GUI - virtual void keywordSelected (const std::string& keyword) = 0; + virtual Response keywordSelected (const std::string& keyword) = 0; virtual void goodbyeSelected() = 0; - virtual void questionAnswered (int answer) = 0; + virtual Response questionAnswered (int answer) = 0; + + virtual std::list getAvailableTopics() = 0; - virtual bool checkServiceRefused () = 0; + virtual bool checkServiceRefused (Response& response) = 0; - virtual void persuade (int type) = 0; + virtual Response persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 51a17d380..d8bce67e4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -140,7 +140,6 @@ namespace MWBase virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0; /// \todo investigate, if we really need to expose every single lousy UI element to the outside world - virtual MWGui::DialogueWindow* getDialogueWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index ffa26e211..4ed3b82a9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -33,8 +34,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwgui/dialogue.hpp" - #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/extensions.hpp" @@ -59,6 +58,7 @@ namespace MWDialogue { mChoice = -1; mIsInChoice = false; + mGoodbye = false; mCompilerContext.setExtensions (&extensions); } @@ -99,17 +99,15 @@ namespace MWDialogue if (mActorKnownTopics.count( topicId )) mKnownTopics.insert( topicId ); } - - updateTopics(); } - void DialogueManager::startDialogue (const MWWorld::Ptr& actor) + bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, Response& response) { updateGlobals(); // Dialogue with dead actor (e.g. through script) should not be allowed. if (actor.getClass().getCreatureStats(actor).isDead()) - return; + return false; mLastTopic = ""; mPermanentDispositionChange = 0; @@ -117,6 +115,8 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; + mGoodbye = false; + mChoices.clear(); mActor = actor; @@ -125,8 +125,6 @@ namespace MWDialogue mActorKnownTopics.clear(); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - //greeting const MWWorld::Store &dialogs = MWBase::Environment::get().getWorld()->getStore().get(); @@ -140,10 +138,6 @@ namespace MWDialogue // Search a response (we do not accept a fallback to "Info refusal" here) if (const ESM::DialInfo *info = filter.search (*it, false)) { - //initialise the GUI - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - win->startDialogue(actor, actor.getClass().getName (actor)); - creatureStats.talkedToPlayer(); if (!info->mSound.empty()) @@ -152,29 +146,23 @@ namespace MWDialogue } // first topics update so that parseText knows the keywords to highlight - updateTopics(); + updateActorKnownTopics(); parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false); + response = Response ("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; // update topics again to accommodate changes resulting from executeScript - updateTopics(); + updateActorKnownTopics(); - return; + return true; } } } - - // No greetings found. The dialogue window should not be shown. - // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). - bool isCompanion = !mActor.getClass().getScript(mActor).empty() - && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); - if (isCompanion) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor); + return false; } bool DialogueManager::compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor) @@ -252,8 +240,9 @@ namespace MWDialogue } } - void DialogueManager::executeTopic (const std::string& topic) + DialogueManager::Response DialogueManager::executeTopic (const std::string& topic) { + DialogueManager::Response response; Filter filter (mActor, mChoice, mTalkedTo); const MWWorld::Store &dialogues = @@ -261,8 +250,6 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - const ESM::DialInfo* info = filter.search(dialogue, true); if (info) { @@ -287,7 +274,7 @@ namespace MWDialogue title = topic; MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title); + response = Response(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); if (dialogue.mType == ESM::Dialogue::Topic) { @@ -308,11 +295,7 @@ namespace MWDialogue mLastTopic = topic; } - else - { - // no response found, print a fallback text - win->addResponse ("…", topic); - } + return response; } const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) @@ -325,11 +308,10 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->updateDialogueGlobals(); } - void DialogueManager::updateTopics() + void DialogueManager::updateActorKnownTopics() { updateGlobals(); - std::list keywordList; mActorKnownTopics.clear(); const MWWorld::Store &dialogs = @@ -345,35 +327,42 @@ namespace MWDialogue { std::string lower = Misc::StringUtils::lowerCase(iter->mId); mActorKnownTopics.insert (lower); - - //does the player know the topic? - if (mKnownTopics.count(lower)) - { - keywordList.push_back (iter->mId); - } } } } - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + } + + std::list DialogueManager::getAvailableTopics() + { + updateActorKnownTopics(); + + std::list keywordList; + + for (const std::string& topic : mActorKnownTopics) + { + //does the player know the topic? + if (mKnownTopics.count(Misc::StringUtils::lowerCase(topic))) + keywordList.push_back(topic); + } // sort again, because the previous sort was case-sensitive keywordList.sort(Misc::StringUtils::ciLess); - win->setKeywords(keywordList); + return keywordList; } - void DialogueManager::keywordSelected (const std::string& keyword) + DialogueManager::Response DialogueManager::keywordSelected (const std::string& keyword) { + Response response; if(!mIsInChoice) { const ESM::Dialogue* dialogue = searchDialogue(keyword); if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - executeTopic (keyword); + response = executeTopic (keyword); } } - - updateTopics(); + return response; } bool DialogueManager::isInChoice() const @@ -383,8 +372,6 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - // Apply disposition change to NPC's base disposition if (mActor.getClass().isNpc()) { @@ -400,9 +387,10 @@ namespace MWDialogue mTemporaryDispositionChange = 0; } - void DialogueManager::questionAnswered (int answer) + DialogueManager::Response DialogueManager::questionAnswered (int answer) { mChoice = answer; + DialogueManager::Response response; const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); if (dialogue) @@ -418,10 +406,10 @@ namespace MWDialogue mChoice = -1; mIsInChoice = false; - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + mChoices.clear(); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext)); + response = Response("", Interpreter::fixDefinesDialog(text, interpreterContext)); // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. @@ -441,32 +429,39 @@ namespace MWDialogue { mChoice = -1; mIsInChoice = false; - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices(); + mChoices.clear(); } } } - updateTopics(); + updateActorKnownTopics(); + return response; } - void DialogueManager::askQuestion (const std::string& question, int choice) + void DialogueManager::addChoice (const std::string& text, int choice) { mIsInChoice = true; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->addChoice(question, choice); + mChoices.push_back(std::make_pair(text, choice)); } - void DialogueManager::goodbye() + const std::vector >& DialogueManager::getChoices() { - mIsInChoice = true; + return mChoices; + } - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + bool DialogueManager::isGoodbye() + { + return mGoodbye; + } - win->goodbye(); + void DialogueManager::goodbye() + { + mIsInChoice = false; + mGoodbye = true; } - void DialogueManager::persuade(int type) + DialogueManager::Response DialogueManager::persuade(int type) { bool success; float temp, perm; @@ -515,7 +510,7 @@ namespace MWDialogue text = "Bribe"; } - executeTopic (text + (success ? " Success" : " Fail")); + return executeTopic (text + (success ? " Success" : " Fail")); } int DialogueManager::getTemporaryDispositionChange() const @@ -528,7 +523,7 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } - bool DialogueManager::checkServiceRefused() + bool DialogueManager::checkServiceRefused(Response& response) { Filter filter (mActor, mChoice, mTalkedTo); @@ -536,7 +531,6 @@ namespace MWDialogue MWBase::Environment::get().getWorld()->getStore().get(); const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); std::vector infos = filter.list (dialogue, false, false, true); if (!infos.empty()) @@ -550,8 +544,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), - gmsts.find ("sServiceRefusal")->getString()); + response = Response(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); return true; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 81bd2f2b9..d9c622120 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -41,19 +41,22 @@ namespace MWDialogue int mChoice; std::string mLastTopic; // last topic ID, lowercase bool mIsInChoice; + bool mGoodbye; + + std::vector > mChoices; float mTemporaryDispositionChange; float mPermanentDispositionChange; void parseText (const std::string& text); - void updateTopics(); + void updateActorKnownTopics(); void updateGlobals(); bool compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor); void executeScript (const std::string& script, const MWWorld::Ptr& actor); - void executeTopic (const std::string& topic); + Response executeTopic (const std::string& topic); const ESM::Dialogue* searchDialogue(const std::string& id); @@ -65,24 +68,29 @@ namespace MWDialogue virtual bool isInChoice() const; - virtual void startDialogue (const MWWorld::Ptr& actor); + virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response); + + std::list getAvailableTopics(); virtual void addTopic (const std::string& topic); - virtual void askQuestion (const std::string& question,int choice); + virtual void addChoice (const std::string& text,int choice); + const std::vector >& getChoices(); + + virtual bool isGoodbye(); virtual void goodbye(); - virtual bool checkServiceRefused (); + virtual bool checkServiceRefused (Response& response); virtual void say(const MWWorld::Ptr &actor, const std::string &topic); //calbacks for the GUI - virtual void keywordSelected (const std::string& keyword); + virtual Response keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); - virtual void questionAnswered (int answer); + virtual Response questionAnswered (int answer); - virtual void persuade (int type); + virtual Response persuade (int type); virtual int getTemporaryDispositionChange () const; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 869b83928..a7f18561e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -68,7 +68,9 @@ namespace MWGui else /*if (sender == mBribe1000Button)*/ type = MWBase::MechanicsManager::PT_Bribe1000; - MWBase::Environment::get().getDialogueManager()->persuade(type); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->persuade(type); + + eventPersuadeMsg(response.first, response.second); setVisible(false); } @@ -214,30 +216,26 @@ namespace MWGui void Choice::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId); + eventChoiceActivated(mChoiceId); } void Topic::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId); + eventTopicActivated(mTopicId); } void Goodbye::activated() { - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + eventActivated(); } // -------------------------------------------------------------------------------------------------- DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") - , mEnabled(false) , mGoodbye(false) , mPersuasionDialog() { @@ -245,13 +243,14 @@ namespace MWGui center(); mPersuasionDialog.setVisible(false); + mPersuasionDialog.eventPersuadeMsg += MyGUI::newDelegate(this, &DialogueWindow::onPersuadeResult); //History view getWidget(mHistory, "History"); //Topics list getWidget(mTopicsList, "TopicsList"); - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectListItem); getWidget(mGoodbyeButton, "ByeButton"); mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); @@ -269,15 +268,27 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } + DialogueWindow::~DialogueWindow() + { + mPersuasionDialog.eventPersuadeMsg.clear(); + + deleteLater(); + for (Link* link : mLinks) + delete link; + for (auto link : mTopicLinks) + delete link.second; + for (auto history : mHistoryContents) + delete history; + } + void DialogueWindow::onTradeComplete() { - addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); + addResponse("", MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}")); } bool DialogueWindow::exit() { - if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - && !mGoodbye) + if ((MWBase::Environment::get().getDialogueManager()->isInChoice())) { return false; } @@ -315,9 +326,9 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } - void DialogueWindow::onSelectTopic(const std::string& topic, int id) + void DialogueWindow::onSelectListItem(const std::string& topic, int id) { - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + if (mGoodbye || MWBase::Environment::get().getDialogueManager()->isInChoice()) return; int separatorPos = 0; @@ -328,17 +339,18 @@ namespace MWGui } if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(topic); + onTopicActivated(topic); else { const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWBase::DialogueManager::Response response; if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(response)) { if (topic == gmst.find("sBarter")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); @@ -355,21 +367,30 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + addResponse(response.first, response.second); } } - void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + void DialogueWindow::setPtr(const MWWorld::Ptr& actor) { + MWBase::DialogueManager::Response response; + if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, response)) + { + // No greetings found. The dialogue window should not be shown. + // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). + if (isCompanion()) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); + return; + } + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); mGoodbye = false; - mEnabled = true; bool sameActor = (mPtr == actor); mPtr = actor; mTopicsList->setEnabled(true); - setTitle(npcName); - - clearChoices(); + setTitle(mPtr.getClass().getName(mPtr)); mTopicsList->clear(); @@ -381,12 +402,13 @@ namespace MWGui } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) - delete (*it); + mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers mLinks.clear(); updateDisposition(); - restock(); + + addResponse(response.first, response.second, false); } void DialogueWindow::restock() @@ -403,11 +425,18 @@ namespace MWGui } } + void DialogueWindow::deleteLater() + { + for (Link* link : mDeleteLater) + delete link; + mDeleteLater.clear(); + } + void DialogueWindow::setKeywords(std::list keyWords) { mTopicsList->clear(); for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) - delete it->second; + mDeleteLater.push_back(it->second); mTopicLinks.clear(); mKeywordSearch.clear(); @@ -416,9 +445,6 @@ namespace MWGui bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get()->mBase->getTransport().empty()) || (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get()->mBase->getTransport().empty()); - bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -446,7 +472,7 @@ namespace MWGui if (services & ESM::NPC::Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); - if (isCompanion) + if (isCompanion()) mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); if (mTopicsList->getItemCount() > 0) @@ -458,6 +484,7 @@ namespace MWGui mTopicsList->addItem(*it); Topic* t = new Topic(*it); + t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated); mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t; mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t)); @@ -491,9 +518,11 @@ namespace MWGui typesetter->sectionBreak(9); // choices const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); - for (std::vector >::iterator it = mChoices.begin(); it != mChoices.end(); ++it) + mChoices = MWBase::Environment::get().getDialogueManager()->getChoices(); + for (std::vector >::const_iterator it = mChoices.begin(); it != mChoices.end(); ++it) { Choice* link = new Choice(it->second); + link->eventChoiceActivated += MyGUI::newDelegate(this, &DialogueWindow::onChoiceActivated); mLinks.push_back(link); typesetter->lineBreak(); @@ -503,9 +532,11 @@ namespace MWGui typesetter->write(questionStyle, to_utf8_span(it->first.c_str())); } + mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye(); if (mGoodbye) { Goodbye* link = new Goodbye(); + link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated); mLinks.push_back(link); std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString(); BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver, @@ -550,32 +581,40 @@ namespace MWGui reinterpret_cast(link)->activated(); } - void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) + void DialogueWindow::onTopicActivated(const std::string &topicId) { - mHistory->setPosition(0, static_cast(pos) * -1); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId); + addResponse(response.first, response.second); } - void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin) + void DialogueWindow::onChoiceActivated(int id) { - mHistoryContents.push_back(new Response(text, title, needMargin)); - updateHistory(); + MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id); + addResponse(response.first, response.second); } - void DialogueWindow::addMessageBox(const std::string& text) + void DialogueWindow::onGoodbyeActivated() { - mHistoryContents.push_back(new Message(text)); - updateHistory(); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + resetReference(); + } + + void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos) + { + mHistory->setPosition(0, static_cast(pos) * -1); } - void DialogueWindow::addChoice(const std::string& choice, int id) + void DialogueWindow::addResponse(const std::string &title, const std::string &text, bool needMargin) { - mChoices.push_back(std::make_pair(choice, id)); + mHistoryContents.push_back(new Response(text, title, needMargin)); updateHistory(); + updateTopics(); } - void DialogueWindow::clearChoices() + void DialogueWindow::addMessageBox(const std::string& text) { - mChoices.clear(); + mHistoryContents.push_back(new Message(text)); updateHistory(); } @@ -608,13 +647,6 @@ namespace MWGui } } - void DialogueWindow::goodbye() - { - mGoodbye = true; - mEnabled = false; - updateHistory(); - } - void DialogueWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); @@ -623,6 +655,30 @@ namespace MWGui void DialogueWindow::onFrame(float dt) { checkReferenceAvailable(); + if (mPtr.isEmpty()) + return; + updateDisposition(); + deleteLater(); + + if (mChoices != MWBase::Environment::get().getDialogueManager()->getChoices() + || mGoodbye != MWBase::Environment::get().getDialogueManager()->isGoodbye()) + updateHistory(); + } + + void DialogueWindow::updateTopics() + { + setKeywords(MWBase::Environment::get().getDialogueManager()->getAvailableTopics()); + } + + bool DialogueWindow::isCompanion() + { + return !mPtr.getClass().getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); + } + + void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) + { + addResponse(title, text); } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 83f1eb1de..c83906588 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -8,6 +8,8 @@ #include "../mwdialogue/keywordsearch.hpp" +#include + namespace Gui { class MWList; @@ -20,14 +22,14 @@ namespace MWGui namespace MWGui { - class DialogueHistoryViewModel; - class BookPage; - class PersuasionDialog : public WindowModal { public: PersuasionDialog(); + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_Result; + EventHandle_Result eventPersuadeMsg; + virtual void onOpen(); private: @@ -53,6 +55,8 @@ namespace MWGui struct Topic : Link { + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_TopicId; + EventHandle_TopicId eventTopicActivated; Topic(const std::string& id) : mTopicId(id) {} std::string mTopicId; virtual void activated (); @@ -60,6 +64,8 @@ namespace MWGui struct Choice : Link { + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_ChoiceId; + EventHandle_ChoiceId eventChoiceActivated; Choice(int id) : mChoiceId(id) {} int mChoiceId; virtual void activated (); @@ -67,6 +73,8 @@ namespace MWGui struct Goodbye : Link { + typedef MyGUI::delegates::CMultiDelegate0 Event_Activated; + Event_Activated eventActivated; virtual void activated (); }; @@ -98,6 +106,7 @@ namespace MWGui { public: DialogueWindow(); + ~DialogueWindow(); void onTradeComplete(); @@ -108,25 +117,29 @@ namespace MWGui void notifyLinkClicked (TypesetBook::InteractiveId link); - void startDialogue(MWWorld::Ptr actor, std::string npcName); + void setPtr(const MWWorld::Ptr& actor); + void setKeywords(std::list keyWord); - void addResponse (const std::string& text, const std::string& title="", bool needMargin = true); + void addResponse (const std::string& title, const std::string& text, bool needMargin = true); void addMessageBox(const std::string& text); - void addChoice(const std::string& choice, int id); - void clearChoices(); - - void goodbye(); void onFrame(float dt); void clear() { resetReference(); } protected: - void onSelectTopic(const std::string& topic, int id); + void updateTopics(); + bool isCompanion(); + + void onPersuadeResult(const std::string& title, const std::string& text); + void onSelectListItem(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onWindowResize(MyGUI::Window* _sender); + void onTopicActivated(const std::string& topicId); + void onChoiceActivated(int id); + void onGoodbyeActivated(); void onScrollbarMoved (MyGUI::ScrollBar* sender, size_t pos); @@ -137,17 +150,19 @@ namespace MWGui private: void updateDisposition(); void restock(); + void deleteLater(); bool mEnabled; - bool mGoodbye; - std::vector mHistoryContents; std::vector > mChoices; + bool mGoodbye; std::vector mLinks; std::map mTopicLinks; + std::vector mDeleteLater; + KeywordSearchT mKeywordSearch; BookPage* mHistory; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 74d80d292..6b0b33a0a 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -353,6 +353,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 341167ab7..939f70b59 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -323,6 +323,7 @@ namespace MWGui onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 120ab5cba..1081ee81e 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -197,6 +197,7 @@ namespace MWGui // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 02df6bd8e..c9f19ad92 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -178,6 +178,7 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 85f57a75e..f5825f08d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1288,7 +1288,6 @@ namespace MWGui mConsole->executeFile (path); } - MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 53b2dc33a..f6b2707ad 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -179,7 +179,6 @@ namespace MWGui virtual bool isAllowed(GuiWindow wnd) const; /// \todo investigate, if we really need to expose every single lousy UI element to the outside world - virtual MWGui::DialogueWindow* getDialogueWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index fcb7e8f3b..21d8d469b 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" @@ -116,7 +117,7 @@ namespace MWScript runtime.pop(); arg0 = arg0 -1; } - dialogue->askQuestion(question,choice); + dialogue->addChoice(question,choice); } } }; @@ -133,7 +134,7 @@ namespace MWScript if (!ptr.getRefData().isEnabled()) return; - MWBase::Environment::get().getDialogueManager()->startDialogue (ptr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, ptr); } }; diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 051380ff5..c7bb6a26e 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,7 +1,7 @@ #include "actiontalk.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWWorld { @@ -9,6 +9,6 @@ namespace MWWorld void ActionTalk::executeImp (const Ptr& actor) { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget()); } } From cde2c1390002ac631f1279b5950770fd87b025c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 26 Sep 2017 14:14:28 +0200 Subject: [PATCH 305/521] make water depth independent of view frustum --- apps/openmw/mwrender/renderingmanager.cpp | 8 +++++- apps/openmw/mwrender/renderingmanager.hpp | 3 +++ apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 32 ++++++++++++++--------- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5c22de12e..3a66c264b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -279,11 +279,14 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); - updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); + + mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); + mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); + updateProjectionMatrix(); } RenderingManager::~RenderingManager() @@ -889,6 +892,9 @@ namespace MWRender if (mFieldOfViewOverridden) fov = mFieldOfViewOverride; mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); + + mUniformNear->set(mNearClip); + mUniformFar->set(mViewDistance); } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e575456d9..f0087e43d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -83,6 +83,9 @@ namespace MWRender SceneUtil::UnrefQueue* getUnrefQueue(); Terrain::World* getTerrain(); + osg::Uniform* mUniformNear; + osg::Uniform* mUniformFar; + void preloadCommonAssets(); double getReferenceTime() const; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9679533be..68c07c1ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -6; + const float clipFudge = -5; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 1e3a1e17b..9c8e56191 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -6,7 +6,7 @@ // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -const float VISIBILITY = 1200.0; // how far you can look through water +const float VISIBILITY = 2.5; const float BIG_WAVES_X = 0.1; // strength of big waves const float BIG_WAVES_Y = 0.1; @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) +const float BUMP_SUPPRESS_DEPTH = 0.3; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -58,9 +58,9 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) return result; } -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; uniform sampler2D normalMap; @@ -76,15 +76,18 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float linearizeDepth(float depth) // helper for transforming water depth +float frustumDepth; + +float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value { float z_n = 2.0 * depth - 1.0; - depth = 2.0 * near * far / (far + near - z_n * (far - near)); - return depth - depthPassthrough; + depth = 2.0 * near * far / (far + near - z_n * frustumDepth); + return depth / frustumDepth; } void main(void) { + frustumDepth = abs(far - near); vec3 worldPos = position.xyz + nodePosition.xyz; vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; @@ -157,8 +160,13 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); #if REFRACTION - float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / (BUMP_SUPPRESS_DEPTH * (far - near)),0,1); + float normalization = frustumDepth / 1000; + float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; + float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; + float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum + + float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; #endif @@ -180,10 +188,8 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float waterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); - if (cameraPos.z > 0.0) - refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + refraction = mix(refraction, waterColor, clamp(depthSampleDistorted/VISIBILITY, 0.0, 1.0)); gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; #else From 6062cd4b9c7a3a3e7f05d6f12f27db4b85c14ee7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 Sep 2017 13:28:15 +0400 Subject: [PATCH 306/521] Make physics framerate configurable --- apps/openmw/mwphysics/physicssystem.cpp | 7 ++++++- docs/source/reference/modding/settings/physics.rst | 13 +++++++++++++ files/settings-default.cfg | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 docs/source/reference/modding/settings/physics.rst diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index ee368ad24..068ff3186 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include // FindRecIndexVisitor @@ -1357,7 +1358,11 @@ namespace MWPhysics mMovementResults.clear(); mTimeAccum += dt; - const float physicsDt = 1.f/60.0f; + + static const float physFramerate = Settings::Manager::getFloat("physics framerate", "Physics"); + + // Allow to use a physics framerate between 10 and 60 FPS + static const float physicsDt = 1.f / std::max(10.f, std::min(60.f, physFramerate)); const int maxAllowedSteps = 20; int numSteps = mTimeAccum / (physicsDt); diff --git a/docs/source/reference/modding/settings/physics.rst b/docs/source/reference/modding/settings/physics.rst new file mode 100644 index 000000000..e4f970a79 --- /dev/null +++ b/docs/source/reference/modding/settings/physics.rst @@ -0,0 +1,13 @@ +Physics Settings +################ + +physics framerate +--------------- + +:Type: floating point +:Range: 10.0 to 60.0 +:Default: 60.0 + +Allows to set how frequently an engine will do physics calculations. A default value is 60 times per second. +This setting allows developers with low-clocked CPUs to test an engine. +Changing from default value can lead to physics bugs. Change this setting on your own risk, and reset a value to default before filling a physics-related bugreport! diff --git a/files/settings-default.cfg b/files/settings-default.cfg index aec667a9c..f4c7f0a4a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -277,6 +277,10 @@ camera y multiplier = 1.0 # Invert the vertical axis while not in GUI mode. invert y axis = false +[Physics] +# Framerate of the physics system +physics framerate = 60.0 + [Saves] # Name of last character played, and default for loading save files. From 9b91ea5d34413c674a637692a984046c0886b728 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 16:51:19 +0200 Subject: [PATCH 307/521] Exit drag-and-drop if dragged item is deleted (Fixes #3097) --- apps/openmw/mwgui/draganddrop.cpp | 6 ++++++ apps/openmw/mwgui/draganddrop.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 6 +----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index fe0ad3374..d81b2ed00 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -121,6 +121,12 @@ void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) mSourceView->update(); } +void DragAndDrop::onFrame() +{ + if (mIsOnDragAndDrop && mItem.mBase.getRefData().getCount() == 0) + finish(); +} + void DragAndDrop::finish() { mIsOnDragAndDrop = false; diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index a356fe4e2..dff8cd73c 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -29,6 +29,7 @@ namespace MWGui void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); void drop (ItemModel* targetModel, ItemView* targetView); + void onFrame(); void finish(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f5825f08d..7e3741ae6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -876,11 +876,7 @@ namespace MWGui MWBase::StateManager::State_NoGame) return; - if (mDragAndDrop->mIsOnDragAndDrop) - { - assert(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - } + mDragAndDrop->onFrame(); updateMap(); From 62177ebb30a55a1cb8b62360ee0aa70056aa903c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 Sep 2017 21:19:53 +0400 Subject: [PATCH 308/521] Move physics framerate from setting to environment variable --- apps/openmw/mwphysics/physicssystem.cpp | 30 ++++++++++++------- apps/openmw/mwphysics/physicssystem.hpp | 2 ++ .../reference/modding/settings/physics.rst | 13 -------- files/settings-default.cfg | 4 --- 4 files changed, 22 insertions(+), 27 deletions(-) delete mode 100644 docs/source/reference/modding/settings/physics.rst diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 068ff3186..887189a85 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,5 +1,6 @@ #include "physicssystem.hpp" +#include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include // FindRecIndexVisitor @@ -684,6 +684,7 @@ namespace MWPhysics , mWaterHeight(0) , mWaterEnabled(false) , mParentNode(parentNode) + , mPhysicsDt(1.f / 60.f) { mResourceSystem->addResourceManager(mShapeManager.get()); @@ -696,6 +697,20 @@ namespace MWPhysics // Don't update AABBs of all objects every frame. Most objects in MW are static, so we don't need this. // Should a "static" object ever be moved, we have to update its AABB manually using DynamicsWorld::updateSingleAabb. mCollisionWorld->setForceUpdateAllAabbs(false); + + // Check if a user decided to override a physics system FPS + const char* env = getenv("OPENMW_PHYSICS_FPS"); + if (env) + { + std::string str(env); + + float physFramerate = std::atof(env); + if (physFramerate > 0) + { + mPhysicsDt = 1.f / physFramerate; + std::cerr << "Warning: physics framerate was overriden (a new value is " << physFramerate << ")." << std::endl; + } + } } PhysicsSystem::~PhysicsSystem() @@ -1359,16 +1374,11 @@ namespace MWPhysics mTimeAccum += dt; - static const float physFramerate = Settings::Manager::getFloat("physics framerate", "Physics"); - - // Allow to use a physics framerate between 10 and 60 FPS - static const float physicsDt = 1.f / std::max(10.f, std::min(60.f, physFramerate)); - const int maxAllowedSteps = 20; - int numSteps = mTimeAccum / (physicsDt); + int numSteps = mTimeAccum / (mPhysicsDt); numSteps = std::min(numSteps, maxAllowedSteps); - mTimeAccum -= numSteps * physicsDt; + mTimeAccum -= numSteps * mPhysicsDt; if (numSteps) { @@ -1417,7 +1427,7 @@ namespace MWPhysics bool positionChanged = false; for (int i=0; igetPtr(), physicActor, iter->second, physicsDt, + position = MovementSolver::move(position, physicActor->getPtr(), physicActor, iter->second, mPhysicsDt, flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions); if (position != physicActor->getPosition()) positionChanged = true; @@ -1426,7 +1436,7 @@ namespace MWPhysics if (positionChanged) mCollisionWorld->updateSingleAabb(physicActor->getCollisionObject()); - float interpolationFactor = mTimeAccum / physicsDt; + float interpolationFactor = mTimeAccum / mPhysicsDt; osg::Vec3f interpolated = position * interpolationFactor + physicActor->getPreviousPosition() * (1.f - interpolationFactor); float heightDiff = position.z() - oldHeight; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index aaf55e2b6..3ef9990f5 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -220,6 +220,8 @@ namespace MWPhysics osg::ref_ptr mParentNode; + float mPhysicsDt; + PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); }; diff --git a/docs/source/reference/modding/settings/physics.rst b/docs/source/reference/modding/settings/physics.rst deleted file mode 100644 index e4f970a79..000000000 --- a/docs/source/reference/modding/settings/physics.rst +++ /dev/null @@ -1,13 +0,0 @@ -Physics Settings -################ - -physics framerate ---------------- - -:Type: floating point -:Range: 10.0 to 60.0 -:Default: 60.0 - -Allows to set how frequently an engine will do physics calculations. A default value is 60 times per second. -This setting allows developers with low-clocked CPUs to test an engine. -Changing from default value can lead to physics bugs. Change this setting on your own risk, and reset a value to default before filling a physics-related bugreport! diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f4c7f0a4a..aec667a9c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -277,10 +277,6 @@ camera y multiplier = 1.0 # Invert the vertical axis while not in GUI mode. invert y axis = false -[Physics] -# Framerate of the physics system -physics framerate = 60.0 - [Saves] # Name of last character played, and default for loading save files. From 60604ef5e8cb3939a716877823d5fa3f98903a00 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:07:58 +0000 Subject: [PATCH 309/521] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index d9782ccf3..8c84fd1ed 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -40,6 +40,7 @@ Programmers Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) + crussell187 darkf devnexen Dieho From 09e93319f5620278bfb2bd5957948118fe36faed Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:20:07 +0200 Subject: [PATCH 310/521] Restrict the 'fake mouse movement' workaround to where it's actually required (Fixes #3978) --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b1f80cae6..cf52cbd18 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -366,8 +366,6 @@ namespace MWInput mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); mInputManager->capture(disableEvents); - // inject some fake mouse movement to force updating MyGUI's widget states - MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); if (mControlsDisabled) { @@ -764,6 +762,8 @@ namespace MWInput mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); + // FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel + MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); } if (mMouseLookEnabled && !mControlsDisabled) From fce9a14986e352af26270d814add9085c609c01c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:44:35 +0200 Subject: [PATCH 311/521] Hide the mouse cursor until it's used --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++++ apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d8bce67e4..d454067c8 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -180,6 +180,7 @@ namespace MWBase virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; virtual void setCursorVisible(bool visible) = 0; + virtual void setCursorActive(bool active) = 0; virtual void getMousePosition(int &x, int &y) = 0; virtual void getMousePosition(float &x, float &y) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7e3741ae6..8272568d3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -176,6 +176,7 @@ namespace MWGui , mWerewolfOverlayEnabled(Settings::Manager::getBool ("werewolf overlay", "GUI")) , mHudEnabled(true) , mCursorVisible(true) + , mCursorActive(false) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -1009,7 +1010,16 @@ namespace MWGui void WindowManager::setCursorVisible(bool visible) { + if (visible == mCursorVisible) + return; mCursorVisible = visible; + if (!visible) + mCursorActive = false; + } + + void WindowManager::setCursorActive(bool active) + { + mCursorActive = active; } void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) @@ -1518,7 +1528,7 @@ namespace MWGui bool WindowManager::getCursorVisible() { - return mCursorVisible; + return mCursorVisible && mCursorActive; } void WindowManager::trackWindow(Layout *layout, const std::string &name) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f6b2707ad..612470a7e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -320,6 +320,9 @@ namespace MWGui virtual bool getCursorVisible(); + /// Call when mouse cursor or buttons are used. + virtual void setCursorActive(bool active); + /// Clear all savegame-specific data virtual void clear(); @@ -447,6 +450,7 @@ namespace MWGui bool mWerewolfOverlayEnabled; bool mHudEnabled; bool mCursorVisible; + bool mCursorActive; void setCursorVisible(bool visible); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf52cbd18..6f0b3b1b4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -718,6 +718,7 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); } } + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } setPlayerControlsEnabled(!guiMode); @@ -764,6 +765,8 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); // FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel); + + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } if (mMouseLookEnabled && !mControlsDisabled) From c88c535e0ecf786384d7b209a2446d65a37b3aaf Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 17:59:45 +0200 Subject: [PATCH 312/521] Fix HBox/VBox not using Client widget with MyGUI <= 3.2.2 --- components/widgets/box.cpp | 16 ++++++++++++++++ components/widgets/box.hpp | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index eeddc22dd..a7bd573f4 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -238,6 +238,14 @@ namespace Gui align(); } + void HBox::initialiseOverride() + { + Base::initialiseOverride(); + MyGUI::Widget* client = 0; + assignWidget(client, "Client"); + setWidgetClient(client); + } + void HBox::onWidgetCreated(MyGUI::Widget* _widget) { align(); @@ -385,6 +393,14 @@ namespace Gui align(); } + void VBox::initialiseOverride() + { + Base::initialiseOverride(); + MyGUI::Widget* client = 0; + assignWidget(client, "Client"); + setWidgetClient(client); + } + MyGUI::IntSize VBox::getRequestedSize () { MyGUI::IntSize size(0,0); diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 70f73ce42..467d4b82d 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -99,6 +99,8 @@ namespace Gui virtual void setCoord (const MyGUI::IntCoord &_value); protected: + virtual void initialiseOverride(); + virtual void align(); virtual MyGUI::IntSize getRequestedSize(); @@ -116,6 +118,8 @@ namespace Gui virtual void setCoord (const MyGUI::IntCoord &_value); protected: + virtual void initialiseOverride(); + virtual void align(); virtual MyGUI::IntSize getRequestedSize(); From 2514cc5cc8162e24b299ea9690562475bda57f42 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:20:24 +0200 Subject: [PATCH 313/521] Workaround key focus being reset in BookWindow when next/prev are hidden --- apps/openmw/mwgui/bookwindow.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ae20b8e43..a86146f2f 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -1,6 +1,7 @@ #include "bookwindow.hpp" #include +#include #include @@ -153,20 +154,16 @@ namespace MWGui mLeftPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 1) ); mRightPageNumber->setCaption( MyGUI::utility::toString(mCurrentPage*2 + 2) ); - //If it is the last page, hide the button "Next Page" - if ( (mCurrentPage+1)*2 == mPages.size() - || (mCurrentPage+1)*2 == mPages.size() + 1) - { - mNextPageButton->setVisible(false); - } else { - mNextPageButton->setVisible(true); - } - //If it is the fist page, hide the button "Prev Page" - if (mCurrentPage == 0) { - mPrevPageButton->setVisible(false); - } else { - mPrevPageButton->setVisible(true); - } + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool nextPageVisible = (mCurrentPage+1)*2 < mPages.size(); + mNextPageButton->setVisible(nextPageVisible); + bool prevPageVisible = mCurrentPage != 0; + mPrevPageButton->setVisible(prevPageVisible); + + if (focus == mNextPageButton && !nextPageVisible && prevPageVisible) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton); + else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible) + MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton); if (mPages.empty()) return; From a0ee1c563049216350ae8ed5c5678806de0567b7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:24:43 +0200 Subject: [PATCH 314/521] Fix order of buttons in book window layout for key cycling --- files/mygui/openmw_book.layout | 77 +++++++++++++++++----------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 7c158af8d..a7bea5eb5 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -5,49 +5,50 @@ - - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + - - - - - - - - - - + + + + + + + + + + - - - + + + From 010a7ea5b36ea6e412375fe94106ded92850fbf7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:33:32 +0200 Subject: [PATCH 315/521] Fix tooltip widgets being set to accept key focus --- apps/openmw/mwgui/tooltips.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9b89c3957..a611b1f06 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -422,18 +422,20 @@ namespace MWGui std::string realImage = MWBase::Environment::get().getWindowManager()->correctIconPath(image); MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); - captionWidget->setProperty("Static", "true"); + captionWidget->setEditStatic(true); + captionWidget->setNeedKeyFocus(false); captionWidget->setCaptionWithReplacing(caption); MyGUI::IntSize captionSize = captionWidget->getTextSize(); int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); - textWidget->setProperty("Static", "true"); - textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); + textWidget->setEditStatic(true); + textWidget->setEditMultiLine(true); + textWidget->setEditWordWrap(info.wordWrap); textWidget->setCaptionWithReplacing(text); textWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top); + textWidget->setNeedKeyFocus(false); MyGUI::IntSize textSize = textWidget->getTextSize(); captionSize += MyGUI::IntSize(imageSize, 0); // adjust for image From b9341925f2947b31562d7eca9a3c95d6edc20fb6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 18:33:41 +0200 Subject: [PATCH 316/521] Set AutoSizedEditBox as Static by default Would look very odd anyway to use it for editable text, with the widget resizing as you type. --- components/widgets/box.cpp | 7 +++++++ components/widgets/box.hpp | 3 +++ 2 files changed, 10 insertions(+) diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index a7bd573f4..bf18cef5b 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -66,6 +66,13 @@ namespace Gui notifySizeChange (this); } + void AutoSizedEditBox::initialiseOverride() + { + Base::initialiseOverride(); + setNeedKeyFocus(false); + setEditStatic(true); + } + void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) { if (_key == "ExpandDirection") diff --git a/components/widgets/box.hpp b/components/widgets/box.hpp index 467d4b82d..66be00719 100644 --- a/components/widgets/box.hpp +++ b/components/widgets/box.hpp @@ -39,9 +39,12 @@ namespace Gui MYGUI_RTTI_DERIVED( AutoSizedEditBox ) public: + virtual MyGUI::IntSize getRequestedSize(); virtual void setCaption(const MyGUI::UString& _value); + virtual void initialiseOverride(); + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); }; From 475ac46f3eb10bcb977387ccb1e084407229bdd3 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 19:22:23 +0200 Subject: [PATCH 317/521] Workaround keyfocus issues in current versions of MyGUI --- apps/openmw/mwgui/keyboardnavigation.cpp | 58 +++++++++++++++++++++++- apps/openmw/mwgui/keyboardnavigation.hpp | 4 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index da99c72d0..c9ad5a587 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -30,7 +31,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu } } +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); +} + KeyboardNavigation::KeyboardNavigation() + : mCurrentFocus(nullptr) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -42,7 +49,11 @@ KeyboardNavigation::~KeyboardNavigation() void KeyboardNavigation::saveFocus(int mode) { - mKeyFocus[mode] = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (shouldAcceptKeyFocus(focus)) + mKeyFocus[mode] = focus; + else + mKeyFocus[mode] = mCurrentFocus; } void KeyboardNavigation::restoreFocus(int mode) @@ -61,6 +72,51 @@ void KeyboardNavigation::_unlinkWidget(MyGUI::Widget *widget) for (std::pair& w : mKeyFocus) if (w.second == widget) w.second = nullptr; + if (widget == mCurrentFocus) + mCurrentFocus = nullptr; +} + +void styleFocusedButton(MyGUI::Widget* w) +{ + if (w) + { + if (MyGUI::Button* b = w->castType(false)) + { + b->_setWidgetState("highlighted"); + } + } +} + +void KeyboardNavigation::onFrame() +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + + if (focus == mCurrentFocus) + { + styleFocusedButton(mCurrentFocus); + return; + } + + // workaround incorrect key focus resets (fix in MyGUI TBD) + if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) + { + MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); + focus = mCurrentFocus; + } + + // style highlighted button (won't be needed for MyGUI 3.2.3) + if (focus != mCurrentFocus) + { + if (mCurrentFocus) + { + if (MyGUI::Button* b = mCurrentFocus->castType(false)) + b->_setWidgetState("normal"); + } + + mCurrentFocus = focus; + } + + styleFocusedButton(mCurrentFocus); } enum Direction diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index fff36d862..15aa0d6a8 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -21,6 +21,8 @@ namespace MWGui void _unlinkWidget(MyGUI::Widget* widget); + void onFrame(); + private: bool switchFocus(int direction, bool wrap); @@ -28,6 +30,8 @@ namespace MWGui bool accept(); std::map mKeyFocus; + + MyGUI::Widget* mCurrentFocus; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8272568d3..950b1edc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -866,6 +866,8 @@ namespace MWGui if (!mCurrentModals.empty()) mCurrentModals.top()->onFrame(frameDuration); + mKeyboardNavigation->onFrame(); + mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); From 41fe16013b5f7908964d7837f306bb333446b461 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 19:37:33 +0200 Subject: [PATCH 318/521] Select first widget if we can't find the current widget --- apps/openmw/mwgui/keyboardnavigation.cpp | 38 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index c9ad5a587..d4d0a8c43 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -152,6 +152,21 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) } } +bool selectFirstWidget() +{ + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + return false; +} + bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); @@ -159,22 +174,14 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) return false; - if (focus && (direction == D_Prev || direction == D_Next) && focus->getUserString("AcceptTab") == "true") + bool isCycle = (direction == D_Prev || direction == D_Next); + if (focus && isCycle && focus->getUserString("AcceptTab") == "true") return false; - if ((!focus || !focus->getNeedKeyFocus()) && (direction == D_Next || direction == D_Prev)) + if ((!focus || !focus->getNeedKeyFocus()) && isCycle) { // if nothing is selected, select the first widget - MyGUI::VectorWidgetPtr keyFocusList; - MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); - while (enumerator.next()) - getKeyFocusWidgets(enumerator.current(), keyFocusList); - - if (!keyFocusList.empty()) - { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); - return true; - } + return selectFirstWidget(); } if (!focus) return false; @@ -190,7 +197,12 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) MyGUI::VectorWidgetPtr::iterator found = std::find(keyFocusList.begin(), keyFocusList.end(), focus); if (found == keyFocusList.end()) - return false; + { + if (isCycle) + return selectFirstWidget(); + else + return false; + } bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); From 1714271a7692e884fa0337cc56ef9d5d5bf74236 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 22:21:30 +0200 Subject: [PATCH 319/521] Improve KeyboardNavigation to better handle modal windows It's no longer possible to cycle to widgets that aren't part of the current modal window. The window manager will remember the focused widget of a modal window on a limited basis (it'll be discarded when a different modal window opens). --- apps/openmw/mwgui/dialogue.cpp | 7 ++- apps/openmw/mwgui/dialogue.hpp | 2 + apps/openmw/mwgui/keyboardnavigation.cpp | 70 ++++++++++++++++++------ apps/openmw/mwgui/keyboardnavigation.hpp | 8 +++ apps/openmw/mwgui/windowbase.cpp | 5 +- apps/openmw/mwgui/windowbase.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 ++++ files/mygui/openmw_text.skin.xml | 1 + 8 files changed, 87 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index a7f18561e..b7da86f4e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -77,7 +77,6 @@ namespace MWGui void PersuasionDialog::onOpen() { - WindowModal::onOpen(); center(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -88,6 +87,12 @@ namespace MWGui mBribe1000Button->setEnabled (playerGold >= 1000); mGoldLabel->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold)); + WindowModal::onOpen(); + } + + MyGUI::Widget* PersuasionDialog::getDefaultKeyFocus() + { + return mAdmireButton; } // -------------------------------------------------------------------------------------------------- diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index c83906588..6535ad4b2 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -32,6 +32,8 @@ namespace MWGui virtual void onOpen(); + virtual MyGUI::Widget* getDefaultKeyFocus(); + private: MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index d4d0a8c43..6e1113a4f 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -38,6 +38,7 @@ bool shouldAcceptKeyFocus(MyGUI::Widget* w) KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) + , mModalWindow(nullptr) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -51,9 +52,13 @@ void KeyboardNavigation::saveFocus(int mode) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (shouldAcceptKeyFocus(focus)) + { mKeyFocus[mode] = focus; + } else + { mKeyFocus[mode] = mCurrentFocus; + } } void KeyboardNavigation::restoreFocus(int mode) @@ -87,6 +92,13 @@ void styleFocusedButton(MyGUI::Widget* w) } } +bool isRootParent(MyGUI::Widget* widget, MyGUI::Widget* root) +{ + while (widget && widget->getParent()) + widget = widget->getParent(); + return widget == root; +} + void KeyboardNavigation::onFrame() { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); @@ -98,7 +110,7 @@ void KeyboardNavigation::onFrame() } // workaround incorrect key focus resets (fix in MyGUI TBD) - if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus)) + if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow))) { MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); focus = mCurrentFocus; @@ -119,6 +131,25 @@ void KeyboardNavigation::onFrame() styleFocusedButton(mCurrentFocus); } +void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *defaultFocus) +{ + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + if (!focus || !shouldAcceptKeyFocus(focus)) + { + MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + } + else + { + if (!isRootParent(focus, window)) + MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + } +} + +void KeyboardNavigation::setModalWindow(MyGUI::Widget *window) +{ + mModalWindow = window; +} + enum Direction { D_Left, @@ -152,29 +183,15 @@ bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) } } -bool selectFirstWidget() -{ - MyGUI::VectorWidgetPtr keyFocusList; - MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); - while (enumerator.next()) - getKeyFocusWidgets(enumerator.current(), keyFocusList); - - if (!keyFocusList.empty()) - { - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); - return true; - } - return false; -} - bool KeyboardNavigation::switchFocus(int direction, bool wrap) { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); - if ((focus && focus->getTypeName().find("Button") == std::string::npos) && direction != D_Prev && direction != D_Next) + bool isCycle = (direction == D_Prev || direction == D_Next); + + if ((focus && focus->getTypeName().find("Button") == std::string::npos) && !isCycle) return false; - bool isCycle = (direction == D_Prev || direction == D_Next); if (focus && isCycle && focus->getUserString("AcceptTab") == "true") return false; @@ -230,6 +247,23 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap) return true; } +bool KeyboardNavigation::selectFirstWidget() +{ + MyGUI::VectorWidgetPtr keyFocusList; + MyGUI::EnumeratorWidgetPtr enumerator = MyGUI::Gui::getInstance().getEnumerator(); + if (mModalWindow) + enumerator = mModalWindow->getEnumerator(); + while (enumerator.next()) + getKeyFocusWidgets(enumerator.current(), keyFocusList); + + if (!keyFocusList.empty()) + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]); + return true; + } + return false; +} + bool KeyboardNavigation::accept() { MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 15aa0d6a8..728f16a3d 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -23,15 +23,23 @@ namespace MWGui void onFrame(); + /// Set a key focus widget for this window, if one isn't already set. + void setDefaultFocus(MyGUI::Widget* window, MyGUI::Widget* defaultFocus); + + void setModalWindow(MyGUI::Widget* window); + private: bool switchFocus(int direction, bool wrap); + bool selectFirstWidget(); + /// Send button press event to focused button bool accept(); std::map mKeyFocus; MyGUI::Widget* mCurrentFocus; + MyGUI::Widget* mModalWindow; }; } diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index e563d9aa9..a0e7eedde 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -67,14 +67,17 @@ WindowModal::WindowModal(const std::string& parLayout) void WindowModal::onOpen() { - // Order important. We need to save the key focus widget before its unset MWBase::Environment::get().getWindowManager()->addCurrentModal(this); //Set so we can escape it if needed + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); + MyGUI::InputManager::getInstance().setKeyFocusWidget(focus); } void WindowModal::onClose() { MWBase::Environment::get().getWindowManager()->removeCurrentModal(this); + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index f183c97fe..56901c95a 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -23,6 +23,8 @@ namespace MWGui public: WindowBase(const std::string& parLayout); + virtual MyGUI::Widget* getDefaultKeyFocus() { return NULL; } + // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 950b1edc3..0b51b2b3f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1738,6 +1738,10 @@ namespace MWGui mKeyboardNavigation->saveFocus(getMode()); mCurrentModals.push(input); + mKeyboardNavigation->restoreFocus(-1); + + mKeyboardNavigation->setModalWindow(input->mMainWidget); + mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus()); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1747,12 +1751,20 @@ namespace MWGui if(!mCurrentModals.empty()) { if(input == mCurrentModals.top()) + { mCurrentModals.pop(); + mKeyboardNavigation->saveFocus(-1); + } else std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; } if (mCurrentModals.empty()) + { + mKeyboardNavigation->setModalWindow(NULL); mKeyboardNavigation->restoreFocus(getMode()); + } + else + mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 163b9d134..edc103443 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -81,6 +81,7 @@ color_misc=0,205,205 # ???? + From 22929e53fad10f2be52b67ccf77ab8e5d90c00b9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 22:25:10 +0200 Subject: [PATCH 320/521] Don't ignore my own advice Can't wait until MyGUI 3.2.2 is a build dependency, then we can use key focus events to handle the SDL text input. --- apps/openmw/mwgui/bookwindow.cpp | 4 ++-- apps/openmw/mwgui/keyboardnavigation.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index a86146f2f..c18548dad 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -161,9 +161,9 @@ namespace MWGui mPrevPageButton->setVisible(prevPageVisible); if (focus == mNextPageButton && !nextPageVisible && prevPageVisible) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mPrevPageButton); else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible) - MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNextPageButton); if (mPages.empty()) return; diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 6e1113a4f..2b06de295 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -112,7 +112,7 @@ void KeyboardNavigation::onFrame() // workaround incorrect key focus resets (fix in MyGUI TBD) if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow))) { - MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCurrentFocus); focus = mCurrentFocus; } @@ -136,12 +136,12 @@ void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *d MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (!focus || !shouldAcceptKeyFocus(focus)) { - MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus); } else { if (!isRootParent(focus, window)) - MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus); } } From 44720bf41a1cae7a920dec6537abe7dfc15664dc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:26:40 +0200 Subject: [PATCH 321/521] Allow MWList items to retain key focus --- components/widgets/list.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index c5a459f22..9318e32ed 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -72,6 +72,7 @@ namespace Gui button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheelMoved); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + button->setNeedKeyFocus(true); int height = button->getTextSize().height; button->setSize(MyGUI::IntSize(button->getSize().width, height)); From 7a64098da399e4853fe824f477b878eab01050c4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:27:00 +0200 Subject: [PATCH 322/521] Avoid rebuilding the dialogue topics pane unnecessarily Also retaining key focus. --- apps/openmw/mwgui/dialogue.cpp | 16 +++++++++++++++- apps/openmw/mwgui/dialogue.hpp | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b7da86f4e..b726bf0d9 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -241,6 +241,7 @@ namespace MWGui DialogueWindow::DialogueWindow() : WindowBase("openmw_dialogue_window.layout") + , mIsCompanion(false) , mGoodbye(false) , mPersuasionDialog() { @@ -404,6 +405,9 @@ namespace MWGui for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) delete (*it); mHistoryContents.clear(); + + mKeywords.clear(); + updateTopicsPane(); } for (std::vector::iterator it = mLinks.begin(); it != mLinks.end(); ++it) @@ -438,6 +442,16 @@ namespace MWGui } void DialogueWindow::setKeywords(std::list keyWords) + { + if (mKeywords == keyWords && isCompanion() == mIsCompanion) + return; + mIsCompanion = isCompanion(); + mKeywords = keyWords; + + updateTopicsPane(); + } + + void DialogueWindow::updateTopicsPane() { mTopicsList->clear(); for (std::map::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it) @@ -484,7 +498,7 @@ namespace MWGui mTopicsList->addSeparator(); - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + for(std::list::iterator it = mKeywords.begin(); it != mKeywords.end(); ++it) { mTopicsList->addItem(*it); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 6535ad4b2..97a0e8b37 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -132,6 +132,7 @@ namespace MWGui protected: void updateTopics(); + void updateTopicsPane(); bool isCompanion(); void onPersuadeResult(const std::string& title, const std::string& text); @@ -156,6 +157,9 @@ namespace MWGui bool mEnabled; + bool mIsCompanion; + std::list mKeywords; + std::vector mHistoryContents; std::vector > mChoices; bool mGoodbye; From 8964fc93d60341deb22cdbf702ba3c114b4034a2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 26 Sep 2017 23:27:53 +0200 Subject: [PATCH 323/521] Fix dialogue window not being exited properly --- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 5 +---- apps/openmw/mwgui/spellbuyingwindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 5 ++--- apps/openmw/mwgui/trainingwindow.cpp | 4 +--- apps/openmw/mwgui/travelwindow.cpp | 6 ++---- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 90ef32ced..739acee48 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -164,7 +164,7 @@ void CompanionWindow::onMessageBoxButtonClicked(int button) { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); // Important for Calvus' contract script to work properly - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 6b0b33a0a..3616b8b62 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -9,7 +9,6 @@ #include #include -#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -176,7 +175,6 @@ namespace MWGui void EnchantingDialog::onReferenceUnavailable () { - MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); resetReference(); } @@ -352,8 +350,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, item, mPtr, 1); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return; } } diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index aeb5cfbe5..d9c3a5f16 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -187,7 +187,7 @@ namespace MWGui { // remove both Spells and Dialogue (since you always trade with the NPC/creature that you have previously talked to) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void SpellBuyingWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 939f70b59..2eeeafe0d 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -322,8 +322,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->confiscateStolenItemToOwner(player, it->mBase, mPtr, it->mCount); onCancelButtonClicked(mCancelButton); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); return; } } @@ -503,7 +502,7 @@ namespace MWGui { // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } int TradeWindow::getMerchantGold() diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 1081ee81e..b6504d223 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -6,7 +6,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -196,8 +195,7 @@ namespace MWGui // go back to game mode MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void TrainingWindow::onFrame(float dt) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index c9f19ad92..7c7cdb63e 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -8,7 +8,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" @@ -177,8 +176,7 @@ namespace MWGui } MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); @@ -208,7 +206,7 @@ namespace MWGui void TravelWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); } void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) From 05814c092959ab9481c9453e7364216f2e278133 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:04:01 +0200 Subject: [PATCH 324/521] Add key focus handling for WaitDialog Default is 'until healed'. Up/Down arrows change the hour slider and implicitely change the button to 'Wait'. --- apps/openmw/mwgui/waitdialog.cpp | 22 ++++++++++++++++++++++ apps/openmw/mwgui/waitdialog.hpp | 1 + 2 files changed, 23 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 8a360435c..43c6f135a 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,6 +1,7 @@ #include "waitdialog.hpp" #include +#include #include @@ -72,6 +73,10 @@ namespace MWGui mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + mCancelButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mWaitButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mUntilHealedButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &WaitDialog::onKeyButtonPressed); + mTimeAdvancer.eventProgressChanged += MyGUI::newDelegate(this, &WaitDialog::onWaitingProgressChanged); mTimeAdvancer.eventInterrupted += MyGUI::newDelegate(this, &WaitDialog::onWaitingInterrupted); mTimeAdvancer.eventFinished += MyGUI::newDelegate(this, &WaitDialog::onWaitingFinished); @@ -80,6 +85,11 @@ namespace MWGui void WaitDialog::setPtr(const MWWorld::Ptr &ptr) { setCanRest(!ptr.isEmpty() || MWBase::Environment::get().getWorld ()->canRest () == 0); + + if (mUntilHealedButton->getVisible()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mUntilHealedButton); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton); } bool WaitDialog::exit() @@ -195,6 +205,18 @@ namespace MWGui { mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}"); mManualHours = position+1; + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton); + } + + void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowDown) + mHourSlider->setScrollPosition(std::min(mHourSlider->getScrollPosition()+1, mHourSlider->getScrollRange()-1)); + else if (key == MyGUI::KeyCode::ArrowUp) + mHourSlider->setScrollPosition(std::max(static_cast(mHourSlider->getScrollPosition())-1, 0)); + else + return; + onHourSliderChangedPosition(mHourSlider, mHourSlider->getScrollPosition()); } void WaitDialog::onWaitingProgressChanged(int cur, int total) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index c7ccee025..eb6a55640 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -65,6 +65,7 @@ namespace MWGui void onWaitButtonClicked(MyGUI::Widget* sender); void onCancelButtonClicked(MyGUI::Widget* sender); void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + void onKeyButtonPressed(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character); void onWaitingProgressChanged(int cur, int total); void onWaitingInterrupted(); From 7a3fbfb34ae918cf00badd32c3b0b45ac875c4ab Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:21:20 +0200 Subject: [PATCH 325/521] Slightly improve journal window keyboard navigation --- apps/openmw/mwgui/journalwindow.cpp | 40 ++++++++++++++++++++++++++--- files/mygui/openmw_journal.layout | 32 +++++++++++------------ 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3a67e857d..30a440b58 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -84,10 +85,16 @@ namespace void adviseButtonClick (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender)) { - getWidget (name) -> + getWidget (name) -> eventMouseButtonClick += newDelegate(this, Handler); } + void adviseKeyPress (char const * name, void (JournalWindowImpl::*Handler) (MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)) + { + getWidget (name) -> + eventKeyButtonPressed += newDelegate(this, Handler); + } + MWGui::BookPage* getPage (char const * name) { return getWidget (name); @@ -111,6 +118,12 @@ namespace adviseButtonClick (ShowAllBTN, &JournalWindowImpl::notifyShowAll ); adviseButtonClick (ShowActiveBTN, &JournalWindowImpl::notifyShowActive); + adviseKeyPress (OptionsBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (PrevPageBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (NextPageBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (CloseBTN, &JournalWindowImpl::notifyKeyPress); + adviseKeyPress (JournalBTN, &JournalWindowImpl::notifyKeyPress); + Gui::MWList* list = getWidget(QuestsList); list->eventItemSelected += MyGUI::newDelegate(this, &JournalWindowImpl::notifyQuestClicked); @@ -237,6 +250,8 @@ namespace --page; } updateShowingPages(); + + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget(CloseBTN)); } void onClose() @@ -348,8 +363,19 @@ namespace relPages = 0; } - setVisible (PrevPageBTN, page > 0); - setVisible (NextPageBTN, relPages > 2); + MyGUI::Widget* nextPageBtn = getWidget(NextPageBTN); + MyGUI::Widget* prevPageBtn = getWidget(PrevPageBTN); + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); + bool nextPageVisible = relPages > 2; + nextPageBtn->setVisible(nextPageVisible); + bool prevPageVisible = page > 0; + prevPageBtn->setVisible(prevPageVisible); + + if (focus == nextPageBtn && !nextPageVisible && prevPageVisible) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(prevPageBtn); + else if (focus == prevPageBtn && !prevPageVisible && nextPageVisible) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nextPageBtn); setVisible (PageOneNum, relPages > 0); setVisible (PageTwoNum, relPages > 1); @@ -361,6 +387,14 @@ namespace setText (PageTwoNum, page + 2); } + void notifyKeyPress(MyGUI::Widget* sender, MyGUI::KeyCode key, MyGUI::Char character) + { + if (key == MyGUI::KeyCode::ArrowUp) + notifyPrevPage(sender); + else if (key == MyGUI::KeyCode::ArrowDown) + notifyNextPage(sender); + } + void notifyTopicClicked (intptr_t linkId) { Book topicBook = createTopicBook (linkId); diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index 1131b1bbc..964b5ea95 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -3,32 +3,27 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + @@ -36,11 +31,14 @@ + + + From 879da9c69a6e7828a3e0d0bf1913e69e97629cbc Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 00:28:15 +0200 Subject: [PATCH 326/521] Add key focus for some more button skins --- files/mygui/openmw_text.skin.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index edc103443..5f96d0a57 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -66,6 +66,7 @@ color_misc=0,205,205 # ???? + @@ -97,6 +98,7 @@ color_misc=0,205,205 # ???? + @@ -104,6 +106,7 @@ color_misc=0,205,205 # ???? + From 87311d86b58193cc15018777585d45e1bf99a29c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 12:12:16 +0200 Subject: [PATCH 327/521] Fix what looks like a copy/paste error --- apps/openmw/mwgui/widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 744ef236f..45767bf01 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -105,7 +105,7 @@ namespace MWGui assignWidget(button, "StatValueButton"); if (button) { - mSkillNameWidget = button; + mSkillValueWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); } } From 3d2ad2d3391aaf887010742afa45ce092a2157c6 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 12:40:47 +0200 Subject: [PATCH 328/521] Include cleanup --- apps/openmw/mwgui/alchemywindow.cpp | 3 +++ apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/companionwindow.cpp | 1 + apps/openmw/mwgui/companionwindow.hpp | 6 +++++- apps/openmw/mwgui/dialogue.cpp | 3 ++- apps/openmw/mwgui/recharge.cpp | 1 - apps/openmw/mwgui/repair.cpp | 2 -- apps/openmw/mwgui/savegamedialog.cpp | 1 - apps/openmw/mwgui/waitdialog.cpp | 3 +-- 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 0140653a1..80284e9b2 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -1,6 +1,8 @@ #include "alchemywindow.hpp" #include +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -19,6 +21,7 @@ #include "sortfilteritemmodel.hpp" #include "itemview.hpp" #include "itemwidget.hpp" +#include "widgets.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 2d13a346a..d1e54241a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,7 +5,6 @@ #include "../mwmechanics/alchemy.hpp" -#include "widgets.hpp" #include "windowbase.hpp" namespace MWMechanics diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 739acee48..ad71be7df 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,6 +13,7 @@ #include "companionitemmodel.hpp" #include "draganddrop.hpp" #include "countdialog.hpp" +#include "widgets.hpp" namespace { diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 891106853..8ca350617 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -1,12 +1,16 @@ #ifndef OPENMW_MWGUI_COMPANIONWINDOW_H #define OPENMW_MWGUI_COMPANIONWINDOW_H -#include "widgets.hpp" #include "windowbase.hpp" #include "referenceinterface.hpp" namespace MWGui { + namespace Widgets + { + class MWDynamicStat; + } + class MessageBoxManager; class ItemView; class DragAndDrop; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b726bf0d9..4e36fe117 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -20,7 +22,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "widgets.hpp" #include "bookpage.hpp" #include "textcolours.hpp" diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 32da7876c..26a364f72 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -21,7 +21,6 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" -#include "widgets.hpp" #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index a461f7b3d..11a8aece2 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -17,8 +17,6 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" -#include "widgets.hpp" - #include "itemwidget.hpp" #include "itemchargeview.hpp" #include "sortfilteritemmodel.hpp" diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index e7c27b268..0e4ff1cf4 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -29,7 +29,6 @@ #include "../mwstate/character.hpp" #include "confirmationdialog.hpp" -#include "widgets.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 43c6f135a..a7ad687cb 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -24,8 +25,6 @@ #include "../mwstate/charactermanager.hpp" -#include "widgets.hpp" - namespace MWGui { From 74e806d9745e6f14be6cc4f04320586b3df3cace Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:14:26 +0200 Subject: [PATCH 329/521] Additionally use movement keys (default WASD) to navigate GUI buttons --- apps/openmw/mwinput/inputmanagerimp.cpp | 29 +++++++++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 1 + 2 files changed, 30 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6f0b3b1b4..0637b6d83 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -174,6 +174,29 @@ namespace MWInput } } + void InputManager::handleGuiArrowKey(int action) + { + MyGUI::KeyCode key; + switch (action) + { + case A_MoveLeft: + key = MyGUI::KeyCode::ArrowLeft; + break; + case A_MoveRight: + key = MyGUI::KeyCode::ArrowRight; + break; + case A_MoveForward: + key = MyGUI::KeyCode::ArrowUp; + break; + case A_MoveBackward: + default: + key = MyGUI::KeyCode::ArrowDown; + break; + } + + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0); + } + void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { resetIdleTime (); @@ -235,6 +258,12 @@ namespace MWInput resetIdleTime(); activate(); break; + case A_MoveLeft: + case A_MoveRight: + case A_MoveForward: + case A_MoveBackward: + handleGuiArrowKey(action); + break; case A_Journal: toggleJournal (); break; diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 8809f44cd..cba7fc743 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -214,6 +214,7 @@ namespace MWInput void updateIdleTime(float dt); void setPlayerControlsEnabled(bool enabled); + void handleGuiArrowKey(int action); void updateCursorMode(); From c7a82704c6344ee62fd4a4848144b5f250fbf804 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:32:46 +0200 Subject: [PATCH 330/521] Fix key focus resets in SaveGameDialog --- apps/openmw/mwgui/savegamedialog.cpp | 12 ++++++++++++ apps/openmw/mwgui/savegamedialog.hpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 0e4ff1cf4..eb7f158d7 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -105,6 +105,11 @@ namespace MWGui } } + void SaveGameDialog::onDeleteSlotCancel() + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender) { // This might have previously been a save slot from the list. If so, that is no longer the case @@ -225,6 +230,11 @@ namespace MWGui accept(true); } + void SaveGameDialog::onConfirmationCancel() + { + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::accept(bool reallySure) { // Remove for MyGUI 3.2.2 @@ -240,6 +250,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel); return; } if (mSaveNameEdit->getCaption().empty()) @@ -260,6 +271,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel); return; } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 39e3d310a..a51124705 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -37,10 +37,12 @@ namespace MWGui void onSlotMouseClick(MyGUI::ListBox* sender, size_t pos); void onDeleteSlotConfirmed(); + void onDeleteSlotCancel(); void onEditSelectAccept (MyGUI::EditBox* sender); void onSaveNameChanged (MyGUI::EditBox* sender); void onConfirmationGiven(); + void onConfirmationCancel(); void accept(bool reallySure=false); From 0ee57effcceaf6050a3b85c6b91cc63615c7400e Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:43:33 +0200 Subject: [PATCH 331/521] Make 'Delete game' button not accept keyfocus, to prevent accidents --- apps/openmw/mwgui/savegamedialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index eb7f158d7..423dbb036 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -57,6 +57,9 @@ namespace MWGui mSaveList->eventKeyButtonPressed += MyGUI::newDelegate(this, &SaveGameDialog::onKeyButtonPressed); mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept); mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged); + + // To avoid accidental deletions + mDeleteButton->setNeedKeyFocus(false); } void SaveGameDialog::onSlotActivated(MyGUI::ListBox *sender, size_t pos) From f2146a2dc0164adfd078e20e5aee1cf6901cfab9 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 13:15:22 +0000 Subject: [PATCH 332/521] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 8c84fd1ed..02eb30da0 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -106,6 +106,7 @@ Programmers Michael Papageorgiou (werdanith) Michał Bień (Glorf) Michał Moroz (dragonee) + Miloslav Číž (drummyfish) Miroslav Puda (pakanek) MiroslavR Mitchell Schwitzer (schwitzerm) From 5c50506c83262bf82681a580e89a81ed7eb99eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 27 Sep 2017 17:13:21 +0200 Subject: [PATCH 333/521] water shader refactor plus basic rain ripples --- files/shaders/water_fragment.glsl | 113 +++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 19 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 9c8e56191..f7f87ce77 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -38,10 +38,85 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); + + + + + + + + + + + + +const float RAIN_RIPPLE_GAPS = 5.0; +const float RAIN_RIPPLE_RADIUS = 0.1; + +int modulo(int v1, int v2) +{ + return v1 - v2 * int(floor(float(v1) / float(v2))); +} + +vec2 randOffset(vec2 c) +{ + return fract(vec2( + c.x * c.y / 8.0 + c.y * 0.3 + c.x * 0.2, + c.x * c.y / 14.0 + c.y * 0.5 + c.x * 0.7)); +} + +float randPhase(vec2 c) +{ + return fract((c.x * c.y) / (c.x + c.y + 0.1)); +} + +float circle(vec2 coords, vec2 i_part, float phase) +{ + float d = distance(vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0),coords); + float r = RAIN_RIPPLE_RADIUS * phase; + + if (d > r) + return 0.0; + + float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + + return (1.0 - abs(phase)) * pow(sinValue,3.0); +} + +float rain(vec2 uv, float time) +{ + vec2 i_part = floor(uv * RAIN_RIPPLE_GAPS); + vec2 f_part = fract(uv * RAIN_RIPPLE_GAPS); + return circle(f_part,i_part,fract(time * 1.2 + randPhase(i_part))); +} + +float rainCombined(vec2 uv, float time) +{ + return + rain(uv,time) + + rain(uv + vec2(10.5,5.7),time) + + rain(uv * 0.75 + vec2(3.7,18.9),time) + + rain(uv * 0.9 + vec2(5.7,30.1),time) + + rain(uv * 0.8 + vec2(1.2,3.0),time); +} + + + + + + + + + + + + + + // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) -{ + { float c = abs(dot(Incoming, Normal)); float g = eta * eta - 1.0 + c * c; float result; @@ -56,7 +131,12 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) result = 1.0; /* TIR (no refracted component) */ return result; -} + } + +vec2 normalCoords(vec2 uv, float scale, float speed, float time, float timer1, float timer2, vec3 previousNormal) + { + return uv * (WAVE_SCALE * scale) + WIND_DIR * time * (WIND_SPEED * speed) -(previousNormal.xy/previousNormal.zz) * WAVE_CHOPPYNESS + vec2(time * timer1,time * timer2); + } varying vec3 screenCoordsPassthrough; varying vec4 position; @@ -101,22 +181,12 @@ void main(void) #define waterTimer osg_SimulationTime - nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); - vec3 normal0 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; - vec3 normal1 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; - vec3 normal2 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; - vec3 normal3 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; - - nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; - vec3 normal4 = 2.0 * texture2D(normalMap, nCoord + vec2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; - nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; - vec3 normal5 = 2.0 * texture2D(normalMap, nCoord + vec2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; - - + vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; + vec3 normal1 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.1, 0.08, waterTimer, 0.02, 0.015, normal0)).rgb - 1.0; + vec3 normal2 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.25, 0.07, waterTimer, -0.04, -0.03, normal1)).rgb - 1.0; + vec3 normal3 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.5, 0.09, waterTimer, 0.03, 0.04, normal2)).rgb - 1.0; + vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; + vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + @@ -126,6 +196,10 @@ void main(void) normal = vec3(-normal.x, -normal.y, normal.z); + float rainRipple = rainCombined(position.xy / 1000.0,osg_SimulationTime); + +//normal.y += 2 * rainRipple; + // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + @@ -133,7 +207,6 @@ void main(void) lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); - vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; @@ -200,6 +273,8 @@ void main(void) float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); +gl_FragData[0].xyz += vec3(rainRipple) * 0.2; + #if REFRACTION gl_FragData[0].w = 1.0; #else From 668a947210afe2d7cadd26a3ba9312aad0115f2b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 27 Sep 2017 20:00:41 +0400 Subject: [PATCH 334/521] Inherit owner, if an item is in container (regression #4128) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5d9ef726a..574444a8f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1012,14 +1012,17 @@ namespace MWMechanics MWWorld::Ptr victim; + bool isAllowed = true; const MWWorld::CellRef* ownerCellRef = &item.getCellRef(); if (!container.isEmpty()) { // Inherit the owner of the container ownerCellRef = &container.getCellRef(); + isAllowed = isAllowedToUse(ptr, container, victim); } else { + isAllowed = isAllowedToUse(ptr, item, victim); if (!item.getCellRef().hasContentFile()) { // this is a manually placed item, which means it was already stolen @@ -1027,7 +1030,7 @@ namespace MWMechanics } } - if (isAllowedToUse(ptr, item, victim)) + if (isAllowed) return; Owner owner; From 4a332a180764af345d939c93b0ebda696b81c9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 27 Sep 2017 21:25:14 +0200 Subject: [PATCH 335/521] improve rain ripples --- files/shaders/water_fragment.glsl | 69 ++++++++++++------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index f7f87ce77..23bd688ab 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -38,17 +38,7 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); - - - - - - - - - - - +// ---------------- rain ripples related stuff --------------------- const float RAIN_RIPPLE_GAPS = 5.0; const float RAIN_RIPPLE_RADIUS = 0.1; @@ -70,27 +60,32 @@ float randPhase(vec2 c) return fract((c.x * c.y) / (c.x + c.y + 0.1)); } -float circle(vec2 coords, vec2 i_part, float phase) +vec4 circle(vec2 coords, vec2 i_part, float phase) { - float d = distance(vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0),coords); + vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0); + vec2 toCenter = coords - center; + float d = length(toCenter); float r = RAIN_RIPPLE_RADIUS * phase; if (d > r) - return 0.0; + return vec4(0.0,0.0,1.0,0.0); float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + float height = (1.0 - abs(phase)) * pow(sinValue,3.0); + + vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); - return (1.0 - abs(phase)) * pow(sinValue,3.0); + return vec4(normal,height); } -float rain(vec2 uv, float time) +vec4 rain(vec2 uv, float time) { vec2 i_part = floor(uv * RAIN_RIPPLE_GAPS); vec2 f_part = fract(uv * RAIN_RIPPLE_GAPS); return circle(f_part,i_part,fract(time * 1.2 + randPhase(i_part))); } -float rainCombined(vec2 uv, float time) +vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and ripple height in w { return rain(uv,time) + @@ -100,19 +95,6 @@ float rainCombined(vec2 uv, float time) rain(uv * 0.8 + vec2(1.2,3.0),time); } - - - - - - - - - - - - - // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) @@ -188,22 +170,24 @@ void main(void) vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; + vec4 rainRipple = rainCombined(position.xy / 1000.0,waterTimer); + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; + vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y + + rippleAdd); normal = normalize(vec3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = vec3(-normal.x, -normal.y, normal.z); - float rainRipple = rainCombined(position.xy / 1000.0,osg_SimulationTime); - -//normal.y += 2 * rainRipple; - // normal for sunlight scattering vec3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1 + + rippleAdd).xyz; + lNormal = normalize(vec3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); lNormal = vec3(-lNormal.x, -lNormal.y, lNormal.z); @@ -224,10 +208,10 @@ void main(void) float s = clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0); float lightScatter = shadow * clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * s * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); - vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); + vec3 scatterColour = mix(vec3(SCATTER_COLOUR)*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); // fresnel - float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air float fresnel = fresnel_dielectric(vVec, normal, ior); fresnel = clamp(fresnel, 0.0, 1.0); @@ -243,12 +227,14 @@ void main(void) #else float shore = 1.0; #endif + vec2 screenCoordsOffset = ( (normal.xy + rainRipple.w * vec2(0.0,2.0)) * REFL_BUMP * shore); + // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; + vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; // refraction #if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP*shore)).rgb; + vec3 refraction = texture2D(refractionMap, screenCoords - screenCoordsOffset).rgb; // brighten up the refraction underwater refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; @@ -268,12 +254,11 @@ void main(void) #else gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz; #endif - // fog float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); -gl_FragData[0].xyz += vec3(rainRipple) * 0.2; + gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; #if REFRACTION gl_FragData[0].w = 1.0; From 0240a6c38b3b62ea35ed84ce0b2903a89b8b1115 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:30:12 +0200 Subject: [PATCH 336/521] Fix controls window regression --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0637b6d83..e6acbbd52 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -697,7 +697,7 @@ namespace MWInput SDL_StopTextInput(); bool consumed = false; - if (kc != OIS::KC_UNASSIGNED) + if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState()) { consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); if (SDL_IsTextInputActive() && // Little trick to check if key is printable @@ -726,7 +726,8 @@ namespace MWInput mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + if (!mInputBinder->detectingBindingState()) + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); mInputBinder->keyReleased (arg); } From fb8306b61f66650bc5ce5421a17fa496c70822fe Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:30:31 +0200 Subject: [PATCH 337/521] Disable keyfocus for world map button Fixes 'Tab' no longer working as a keybinding for closing the inventory window. --- files/mygui/openmw_map_window.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index b38097dce..8d45022f8 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -31,6 +31,7 @@ + From a0f5e32113352217a372b040774a9a3292c79208 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:38:15 +0200 Subject: [PATCH 338/521] Fix 'new game' from the main menu not removing menu afterwards --- apps/openmw/mwgui/mainmenu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 4e629403a..00e4e30a5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -80,6 +80,7 @@ namespace MWGui void MainMenu::onNewGameConfirmed() { + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getStateManager()->newGame(); } From db650df416991bd9485634cedb0b03eb12a67790 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 21:40:59 +0200 Subject: [PATCH 339/521] Fix 'blocking' messageboxes not handling key focus properly --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + files/mygui/openmw_interactive_messagebox_notransp.layout | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0b51b2b3f..fbee52c82 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -773,6 +773,7 @@ namespace MWGui double dt = frameTimer.time_s(); frameTimer.setStartTick(); + mKeyboardNavigation->onFrame(); mMessageBoxManager->onFrame(dt); MWBase::Environment::get().getInputManager()->update(dt, true, false); diff --git a/files/mygui/openmw_interactive_messagebox_notransp.layout b/files/mygui/openmw_interactive_messagebox_notransp.layout index 6b79b9417..f5a462977 100644 --- a/files/mygui/openmw_interactive_messagebox_notransp.layout +++ b/files/mygui/openmw_interactive_messagebox_notransp.layout @@ -9,6 +9,7 @@ + From e9d81fdf5aa7bfa4f5f4c668473fb722e7f8050f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:00:20 +0200 Subject: [PATCH 340/521] Fix being able to escape interactive messageboxes --- apps/openmw/mwgui/messagebox.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 38e6590b7..53b277416 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -77,6 +77,8 @@ namespace MWGui void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); + virtual bool exit() { return false; } + bool mMarkedToDelete; private: From 0deda69a272813423518c406ee0fb6ceac563f79 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:04:36 +0200 Subject: [PATCH 341/521] Fix wrong skin for levelup attribute values --- apps/openmw/mwgui/levelupdialog.cpp | 4 +--- files/mygui/openmw_levelup_dialog.layout | 16 ++++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index a068d71f3..286405f79 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -41,6 +41,7 @@ namespace MWGui { MyGUI::TextBox* t; getWidget(t, "AttribVal" + MyGUI::utility::toString(i)); + mAttributeValues.push_back(t); MyGUI::Button* b; getWidget(b, "Attrib" + MyGUI::utility::toString(i)); @@ -48,10 +49,7 @@ namespace MWGui b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked); mAttributes.push_back(b); - mAttributeValues.push_back(t); - getWidget(t, "AttribMultiplier" + MyGUI::utility::toString(i)); - mAttributeMultipliers.push_back(t); } diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index fc11ddfd7..66855373a 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -50,7 +50,7 @@ - + @@ -64,7 +64,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -149,7 +149,7 @@ - + From d53e7f8a3c836344176d8f7f5500dd3128d52b06 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:07:49 +0200 Subject: [PATCH 342/521] Remove redundant code Already worked around in WindowBase::setVisible --- apps/openmw/mwgui/console.cpp | 7 ------- apps/openmw/mwgui/console.hpp | 1 - 2 files changed, 8 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 6094111f8..2d016ddf1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -152,13 +152,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine); } - void Console::onClose() - { - // Apparently, hidden widgets can retain key focus - // Remove for MyGUI 3.2.2 - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL); - } - void Console::setFont(const std::string &fntName) { mHistory->setFontName(fntName); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index f5647e9ea..7ee39770d 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -40,7 +40,6 @@ namespace MWGui Console(int w, int h, bool consoleOnlyScripts); virtual void onOpen(); - virtual void onClose(); void setFont(const std::string &fntName); From 0ae009eb21eb2f079379320edb34fd2deb0d3a2a Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 27 Sep 2017 22:18:47 +0200 Subject: [PATCH 343/521] Hide message box before deleting it Fixes a crash when closing the game window during the 'plugin mismatch' dialog. Modal windows have to be hidden before they are deleted to prevent a dangling pointer in WindowManager. --- apps/openmw/mwgui/messagebox.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index dd0495051..6c421de5e 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -36,8 +36,13 @@ namespace MWGui void MessageBoxManager::clear() { - delete mInterMessageBoxe; - mInterMessageBoxe = NULL; + if (mInterMessageBoxe) + { + mInterMessageBoxe->setVisible(false); + + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + } std::vector::iterator it(mMessageBoxes.begin()); for (; it != mMessageBoxes.end(); ++it) From 6ec66fa95fb64be4510c1c80777d0d7dfb1d614b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 16:57:55 +0000 Subject: [PATCH 344/521] Restore keyfocus to goodbye when selecting a topic --- apps/openmw/mwgui/dialogue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 4e36fe117..27a5003db 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -346,7 +346,10 @@ namespace MWGui } if (id >= separatorPos) + { onTopicActivated(topic); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + } else { const MWWorld::Store &gmst = From 14c9e858c819adf667f7ef022a246c72fa6d9e60 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 17:00:07 +0000 Subject: [PATCH 345/521] Check to make sure button is enabled --- apps/openmw/mwgui/dialogue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 27a5003db..95fa00469 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -348,7 +348,8 @@ namespace MWGui if (id >= separatorPos) { onTopicActivated(topic); - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); + if (mGoodbyeButton->getEnabled()) + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); } else { From 8416feaf5b302c3222df110a4e9a50bbaba6c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 19:04:31 +0200 Subject: [PATCH 346/521] link rain water ripple effect to actual rain --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/sky.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/sky.hpp | 1 + files/shaders/water_fragment.glsl | 12 +++++++++++- 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3a66c264b..23fc4ec28 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -251,6 +251,10 @@ namespace MWRender sceneRoot->setNodeMask(Mask_Scene); sceneRoot->setName("Scene Root"); + mUniformRainIntensity = new osg::Uniform("rainIntensity",(float) 0.0); + + mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); @@ -799,6 +803,7 @@ namespace MWRender { mEffectManager->clear(); mWater->clearRipples(); + mUniformRainIntensity->set((float) 0.0); // for interiors } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0087e43d..1673003c4 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,6 +85,7 @@ namespace MWRender osg::Uniform* mUniformNear; osg::Uniform* mUniformFar; + osg::Uniform* mUniformRainIntensity; void preloadCommonAssets(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index e6aa013ec..5bf5dbcb3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1305,13 +1305,19 @@ public: std::vector > mAlphaFaders; }; -private: +protected: float mAlpha; }; class RainFader : public AlphaFader { public: + + RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() + { + mRainIntensityUniform = rainIntensityUniform; + } + virtual void setDefaults(osg::StateSet* stateset) { osg::ref_ptr mat (new osg::Material); @@ -1320,6 +1326,15 @@ public: mat->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(mat, osg::StateAttribute::ON); } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + AlphaFader::apply(stateset,nv); + mRainIntensityUniform->set((float) (mAlpha * 2.0)); // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity + } + +protected: + osg::Uniform* mRainIntensityUniform; }; void SkyManager::createRain() @@ -1375,7 +1390,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader; + mRainFader = new RainFader(mRootNode->getParent(0)->getParent(0)->getStateSet()->getUniform("rainIntensity")); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 863ecc77d..8278c7101 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 23bd688ab..9da7abc01 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -65,12 +65,14 @@ vec4 circle(vec2 coords, vec2 i_part, float phase) vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(i_part) - 1.0); vec2 toCenter = coords - center; float d = length(toCenter); + float r = RAIN_RIPPLE_RADIUS * phase; if (d > r) return vec4(0.0,0.0,1.0,0.0); float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; + float height = (1.0 - abs(phase)) * pow(sinValue,3.0); vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); @@ -138,6 +140,8 @@ uniform float near; uniform float far; uniform vec3 nodePosition; +uniform float rainIntensity; + float frustumDepth; float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value @@ -170,7 +174,13 @@ void main(void) vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; - vec4 rainRipple = rainCombined(position.xy / 1000.0,waterTimer); + vec4 rainRipple; + + if (rainIntensity > 0.01) + rainRipple = rainCombined(position.xy / 1000.0,waterTimer) * clamp(rainIntensity,0.0,1.0); + else + rainRipple = vec4(0.0,0.0,0.0,0.0); + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + From c9c6326d8726a6c11cd5bff04732a142fbd9c119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 19:23:37 +0200 Subject: [PATCH 347/521] fix non-refraction water rain ripples --- files/shaders/water_fragment.glsl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 9da7abc01..ee7ac6255 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -231,8 +231,7 @@ void main(void) float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; - float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum - + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; @@ -268,11 +267,15 @@ void main(void) float fogValue = clamp((depthPassthrough - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); +#if REFRACTION gl_FragData[0].xyz += vec3(rainRipple.w) * 0.2; +#else + gl_FragData[0].xyz += vec3(rainRipple.w) * 0.7; +#endif #if REFRACTION gl_FragData[0].w = 1.0; #else - gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); + gl_FragData[0].w = clamp(fresnel*6.0 + specular, 0.0, 1.0); //clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif } From 7bb0a76df2a2a2f1db5d92d0bf1f108d54b88745 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 28 Sep 2017 19:42:16 +0200 Subject: [PATCH 348/521] Fix tooltips showing when cursor isn't visible --- apps/openmw/mwgui/tooltips.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a611b1f06..e6de9c42c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -97,6 +97,8 @@ namespace MWGui if (guiMode) { + if (!MWBase::Environment::get().getWindowManager()->getCursorVisible()) + return; const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) From 64793a55dc1ef9fc6faa2ad5bb62505a321d7595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 28 Sep 2017 20:44:43 +0200 Subject: [PATCH 349/521] get rid of buggy shader trick --- files/shaders/water_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ee7ac6255..931422d5e 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -236,7 +236,7 @@ void main(void) #else float shore = 1.0; #endif - vec2 screenCoordsOffset = ( (normal.xy + rainRipple.w * vec2(0.0,2.0)) * REFL_BUMP * shore); + vec2 screenCoordsOffset = normal.xy * REFL_BUMP * shore; // reflection vec3 reflection = texture2D(reflectionMap, screenCoords + screenCoordsOffset).rgb; From 5b10e3128eda8a2d914d2e46efd9f333caebfbf4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 29 Sep 2017 14:58:25 +0000 Subject: [PATCH 350/521] Use first resolution in fullscreen if current is not supported (Fixes #4113) --- apps/openmw/mwgui/settingswindow.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c239fc12f..9bf6e4385 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -353,24 +353,31 @@ namespace MWGui } bool supported = false; + int fallbackX = 0, fallbackY = 0; for (unsigned int i=0; igetItemCount(); ++i) { std::string resStr = mResolutionList->getItemNameAt(i); int resX, resY; parseResolution (resX, resY, resStr); + if (i == 0) + { + fallbackX = resX; + fallbackY = resY; + } + if (resX == Settings::Manager::getInt("resolution x", "Video") && resY == Settings::Manager::getInt("resolution y", "Video")) supported = true; } - if (!supported) + if (!supported && mResolutionList->getItemCount()) { - std::string msg = "This resolution is not supported in Fullscreen mode. Please select a resolution from the list."; - MWBase::Environment::get().getWindowManager()-> - messageBox(msg); - _sender->castType()->setCaption(off); - return; + if (fallbackX != 0 && fallbackY != 0) + { + Settings::Manager::setInt("resolution x", "Video", fallbackX); + Settings::Manager::setInt("resolution y", "Video", fallbackY); + } } mWindowBorderButton->setEnabled(!newState); From 4999c667b62654ba580bcd9cdb9ebeb784f5797d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 29 Sep 2017 19:56:16 +0200 Subject: [PATCH 351/521] fix rain ripple bug --- apps/openmw/mwrender/renderingmanager.cpp | 9 ++++++++- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwrender/sky.cpp | 10 ++++++++++ apps/openmw/mwrender/sky.hpp | 4 ++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 23fc4ec28..3826fd5f6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -504,6 +504,9 @@ namespace MWRender mWater->update(dt); } + if (!mSky->isEnabled() || !mSky->hasRain()) + clearRainRipples(); + mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -803,7 +806,11 @@ namespace MWRender { mEffectManager->clear(); mWater->clearRipples(); - mUniformRainIntensity->set((float) 0.0); // for interiors + } + + void RenderingManager::clearRainRipples() + { + mUniformRainIntensity->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1673003c4..43059ab6d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -160,6 +160,8 @@ namespace MWRender /// Clear all worldspace-specific data void notifyWorldSpaceChanged(); + void clearRainRipples(); + void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 5bf5dbcb3..178c753c6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1431,6 +1431,16 @@ int SkyManager::getSecundaPhase() const return mSecunda->getPhaseInt(); } +bool SkyManager::isEnabled() +{ + return mEnabled; +} + +bool SkyManager::hasRain() +{ + return mRainNode != NULL; +} + void SkyManager::update(float duration) { if (!mEnabled) return; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 8278c7101..59a8ddc4e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -138,6 +138,10 @@ namespace MWRender void sunDisable(); + bool isEnabled(); + + bool hasRain(); + void setRainSpeed(float speed); void setStormDirection(const osg::Vec3f& direction); From 03daf2b9e3bf08737dd84614874ce2e43a09b982 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 29 Sep 2017 22:28:09 +0400 Subject: [PATCH 352/521] Fix a failed assert in the getCell() check during a new game start --- apps/openmw/mwworld/worldimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2a25d5bbc..9c7fba9fa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2118,7 +2118,9 @@ namespace MWWorld pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); - return isUnderwater(object.getCell(), pos); + const CellStore *currCell = object.isInCell() ? object.getCell() : NULL; // currCell == NULL should only happen for player, during initial startup + + return isUnderwater(currCell, pos); } bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const From dfcbee3ab162e5c7ff8809bb753dafc083848548 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 30 Sep 2017 00:04:52 -0400 Subject: [PATCH 353/521] Ignore case when comparing textures, also add new textures to lookup map. --- apps/opencs/model/world/idtable.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 54d65ac3f..bde5af3d9 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -1,5 +1,7 @@ #include "idtable.hpp" +#include +#include #include #include #include @@ -346,8 +348,10 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import for (int i = 0; i < idCollection()->getSize(); ++i) { auto& record = static_cast&>(idCollection()->getRecord(i)); + std::string texture = record.get().mTexture; + std::transform(texture.begin(), texture.end(), texture.begin(), tolower); if (record.isModified()) - reverseLookupMap.emplace(record.get().mTexture, idCollection()->getId(i)); + reverseLookupMap.emplace(texture, idCollection()->getId(i)); } for (const std::string& id : ids) @@ -366,7 +370,9 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import // Look for a pre-existing record auto& record = static_cast&>(idCollection()->getRecord(oldRow)); - auto searchIt = reverseLookupMap.find(record.get().mTexture); + std::string texture = record.get().mTexture; + std::transform(texture.begin(), texture.end(), texture.begin(), tolower); + auto searchIt = reverseLookupMap.find(texture); if (searchIt != reverseLookupMap.end()) { results.recordMapping.push_back(std::make_pair(id, searchIt->second)); @@ -385,6 +391,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import cloneRecord(id, newId, UniversalId::Type_LandTexture); results.createdRecords.push_back(newId); results.recordMapping.push_back(std::make_pair(id, newId)); + reverseLookupMap.emplace(texture, newId); break; } From 097b9d90bc101a0a55eced4baed9acf423e611f1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 30 Sep 2017 16:53:39 +0200 Subject: [PATCH 354/521] Fix travel service not showing --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 95fa00469..8dd027c4a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -481,7 +481,7 @@ namespace MWGui if (services & ESM::NPC::Spells) mTopicsList->addItem(gmst.find("sSpells")->getString()); - if (services & travel) + if (travel) mTopicsList->addItem(gmst.find("sTravel")->getString()); if (services & ESM::NPC::Spellmaking) From 3c62a8c5c29fe5b1d0ed0531bee39a52f517735f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 30 Sep 2017 16:57:07 +0200 Subject: [PATCH 355/521] Fix console selected object persisting on a new game --- apps/openmw/mwgui/console.cpp | 5 +++++ apps/openmw/mwgui/console.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 2d016ddf1..e8ac33f6d 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -215,6 +215,11 @@ namespace MWGui } } + void Console::clear() + { + resetReference(); + } + void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 7ee39770d..bbff34c8d 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -60,6 +60,8 @@ namespace MWGui void executeFile (const std::string& path); + void clear(); + virtual void resetReference (); protected: From 04452b094963d8cbe1e453d9344d8407c4cf11f8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:11:53 +0400 Subject: [PATCH 356/521] Use a pickpocket crime instead of theft when pickpocketing was failed --- apps/openmw/mwgui/container.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 57c756762..a70d833c7 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -136,7 +136,7 @@ namespace MWGui bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); - if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) + if (mPtr.getClass().isNpc() && !loot) { // we are stealing stuff MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -271,9 +271,8 @@ namespace MWGui MWMechanics::Pickpocket pickpocket(player, mPtr); if (pickpocket.pick(item.mBase, count)) { - int value = item.mBase.getClass().getValue(item.mBase) * count; MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Theft, value, true); + player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); mPickpocketDetected = true; return false; From 34895157f91e25f2990afa59e2d4572ff837db37 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:22:26 +0400 Subject: [PATCH 357/521] Consider taking items from unconscious NPC as a theft --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 23 +++++++++++++++---- .../mwmechanics/mechanicsmanagerimp.hpp | 4 ++-- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index d9068b285..398439ad8 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -238,7 +238,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) = 0; + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf) = 0; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e6de9c42c..a9930db4f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -325,7 +325,7 @@ namespace MWGui } } - void ToolTips::setFocusObject(const MWWorld::ConstPtr& focus) + void ToolTips::setFocusObject(const MWWorld::Ptr& focus) { mFocusObject = focus; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index bb2affc63..2793e6544 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -59,7 +59,7 @@ namespace MWGui void setDelay(float delay); - void setFocusObject(const MWWorld::ConstPtr& focus); + void setFocusObject(const MWWorld::Ptr& focus); void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); ///< set the screen-space position of the tooltip for focused object @@ -96,7 +96,7 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWWorld::ConstPtr mFocusObject; + MWWorld::Ptr mFocusObject; MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); ///< @return requested tooltip size diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fbee52c82..e96743b91 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1573,7 +1573,7 @@ namespace MWGui mMessageBoxManager->clear(); - mToolTips->setFocusObject(MWWorld::ConstPtr()); + mToolTips->setFocusObject(MWWorld::Ptr()); mSelectedSpell.clear(); mCustomMarkers.clear(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 574444a8f..950cf8a01 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -840,17 +840,30 @@ namespace MWMechanics mAI = true; } - bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim) + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { - const MWWorld::CellRef& cellref = item.getCellRef(); + const MWWorld::CellRef& cellref = target.getCellRef(); // there is no harm to use unlocked doors - if (item.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) + if (target.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) return true; - // TODO: implement a better check to check if item is owned bed - if (item.getClass().isActivator() && item.getClass().getScript(item).compare(0, 3, "Bed") != 0) + // TODO: implement a better check to check if target is owned bed + if (target.getClass().isActivator() && target.getClass().getScript(target).compare(0, 3, "Bed") != 0) return true; + if (target.getClass().isNpc()) + { + if (target.getClass().getCreatureStats(target).isDead()) + return true; + + // check if a player tries to pickpocket a target NPC + if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak) + || target.getClass().getCreatureStats(target).getKnockedDown()) + return false; + + return true; + } + const std::string& owner = cellref.getOwner(); bool isOwned = !owner.empty() && owner != "player"; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 1bf3a8d22..ee4cf28af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -204,8 +204,8 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); - /// @return is \a ptr allowed to take/use \a cellref or is it a crime? - virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::ConstPtr& item, MWWorld::Ptr& victim); + /// @return is \a ptr allowed to take/use \a target or is it a crime? + virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim); virtual void setWerewolf(const MWWorld::Ptr& actor, bool werewolf); virtual void applyWerewolfAcrobatics(const MWWorld::Ptr& actor); From 3ebb18ce18b89407464f388c00fb36455500be36 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:31:06 +0400 Subject: [PATCH 358/521] Make unconscious actors do not report about crimes --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 950cf8a01..525749c38 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1097,6 +1097,10 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).isDead()) continue; + // Unconsious actor can not report about crime + if (it->getClass().getCreatureStats(*it).getKnockedDown()) + continue; + if ((*it == victim && victimAware) || (MWBase::Environment::get().getWorld()->getLOS(player, *it) && awarenessCheck(player, *it) ) // Murder crime can be reported even if no one saw it (hearing is enough, I guess). @@ -1208,12 +1212,16 @@ namespace MWMechanics // Tell everyone (including the original reporter) in alarm range for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if ( *it == player + if (*it == player || !it->getClass().isNpc() || it->getClass().getCreatureStats(*it).isDead()) continue; if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; + // Unconsious actor can not report about crime and should not become hostile + if (it->getClass().getCreatureStats(*it).getKnockedDown()) + continue; + // Player's followers should not attack player, or try to arrest him if (it->getClass().getCreatureStats(*it).getAiSequence().hasPackage(AiPackage::TypeIdFollow)) { From f26206b63026253e91993003a69bc29dbb9acb19 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 20:55:42 +0400 Subject: [PATCH 359/521] Make unconscious actors do not speak and do not track targets --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 ++++++ apps/openmw/mwmechanics/actors.cpp | 14 +++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 4ed3b82a9..6fac03e92 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -567,6 +567,12 @@ namespace MWDialogue return; } + if (actor.getClass().getCreatureStats(actor).getKnockedDown()) + { + // Unconscious actors can not speak + return; + } + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Dialogue *dial = store.get().find(topic); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef429504..d0fe5a755 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1232,13 +1232,17 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + // Unconsious actor can not track target + if (!iter->first.getClass().getCreatureStats(iter->first).getKnockedDown()) { - if (it->first == iter->first) - continue; - updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); + for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + { + if (it->first == iter->first) + continue; + updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); + } + iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } - iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) From b8fd530ee1111372f34f6e084fd0b966eb7c9dd0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 21:20:38 +0400 Subject: [PATCH 360/521] Do not speak with unconscious creatures --- apps/openmw/mwclass/creature.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d6926f11d..2e16b13aa 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -470,6 +470,9 @@ namespace MWClass if(stats.getAiSequence().isInCombat()) return std::shared_ptr(new MWWorld::FailedAction("")); + if(stats.getKnockedDown()) + return std::shared_ptr(new MWWorld::FailedAction("")); + return std::shared_ptr(new MWWorld::ActionTalk(ptr)); } From c5fcb9684efe3c0b41a0d7901af4887d7b9ca003 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 30 Sep 2017 21:29:02 +0400 Subject: [PATCH 361/521] Improve owned crosshair feature behaviour --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 525749c38..da98e7f5f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -856,6 +856,9 @@ namespace MWMechanics if (target.getClass().getCreatureStats(target).isDead()) return true; + if (target.getClass().getCreatureStats(target).getAiSequence().isInCombat()) + return true; + // check if a player tries to pickpocket a target NPC if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak) || target.getClass().getCreatureStats(target).getKnockedDown()) From 21b6bd176f2c40f1e953fd599030d5f64e8abae5 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 1 Oct 2017 17:11:30 +0400 Subject: [PATCH 362/521] AI: Autoequip armor when bound armor spell expires --- apps/openmw/mwmechanics/actors.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index cef429504..69ccdf9e4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,9 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } else { - actor.getClass().getContainerStore(actor).remove(item, 1, actor); + MWWorld::Ptr itemPtr = actor.getClass().getInventoryStore(actor).search(item); + if (!itemPtr.isEmpty()) + actor.getClass().getInventoryStore(actor).remove(itemPtr, 1, actor, true); } } From 137ea872d34683c8e2631b7b96b4fe9d716a2ec3 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 2 Oct 2017 15:56:22 -0400 Subject: [PATCH 363/521] Hide base land textures. --- apps/opencs/CMakeLists.txt | 2 +- .../world/landtexturetableproxymodel.cpp | 21 ++++++++++++++++++ .../world/landtexturetableproxymodel.hpp | 22 +++++++++++++++++++ apps/opencs/view/world/table.cpp | 6 +++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/world/landtexturetableproxymodel.cpp create mode 100644 apps/opencs/model/world/landtexturetableproxymodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 36ff8cf67..f10525e08 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel ) diff --git a/apps/opencs/model/world/landtexturetableproxymodel.cpp b/apps/opencs/model/world/landtexturetableproxymodel.cpp new file mode 100644 index 000000000..cf33fab9e --- /dev/null +++ b/apps/opencs/model/world/landtexturetableproxymodel.cpp @@ -0,0 +1,21 @@ +#include "landtexturetableproxymodel.hpp" + +#include "idtable.hpp" + +namespace CSMWorld +{ + LandTextureTableProxyModel::LandTextureTableProxyModel(QObject* parent) + : IdTableProxyModel(parent) + { + } + + bool LandTextureTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const + { + int columnIndex = mSourceModel->findColumnIndex(Columns::ColumnId_Modification); + QModelIndex index = mSourceModel->index(sourceRow, columnIndex); + if (mSourceModel->data(index).toInt() != RecordBase::State_ModifiedOnly) + return false; + + return IdTableProxyModel::filterAcceptsRow(sourceRow, sourceParent); + } +} diff --git a/apps/opencs/model/world/landtexturetableproxymodel.hpp b/apps/opencs/model/world/landtexturetableproxymodel.hpp new file mode 100644 index 000000000..bbedecb53 --- /dev/null +++ b/apps/opencs/model/world/landtexturetableproxymodel.hpp @@ -0,0 +1,22 @@ +#ifndef CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H +#define CSM_WORLD_LANDTEXTURETABLEPROXYMODEL_H + +#include "idtableproxymodel.hpp" + +namespace CSMWorld +{ + /// \brief Removes base records from filtered results. + class LandTextureTableProxyModel : public IdTableProxyModel + { + Q_OBJECT + public: + + LandTextureTableProxyModel(QObject* parent = nullptr); + + protected: + + bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const override; + }; +} + +#endif diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 3cccaaa22..34ecd57d0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -16,6 +16,7 @@ #include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtablebase.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/landtexturetableproxymodel.hpp" #include "../../model/world/record.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/commanddispatcher.hpp" @@ -236,10 +237,15 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || id.getType() == CSMWorld::UniversalId::Type_JournalInfos; + bool isLtexTable = (id.getType() == CSMWorld::UniversalId::Type_LandTextures); if (isInfoTable) { mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this); } + else if (isLtexTable) + { + mProxyModel = new CSMWorld::LandTextureTableProxyModel (this); + } else { mProxyModel = new CSMWorld::IdTableProxyModel (this); From 2f5449a68c6ff2b0c3f7345e0d9746dd59eba490 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 2 Oct 2017 16:13:40 -0400 Subject: [PATCH 364/521] Remove now unnecessary overrides. --- apps/opencs/model/world/idtable.cpp | 26 -------------------------- apps/opencs/model/world/idtable.hpp | 6 ------ 2 files changed, 32 deletions(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index bde5af3d9..fcfc8577e 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -313,32 +313,6 @@ CSMWorld::LandTextureIdTable::LandTextureIdTable(CollectionBase* idCollection, u { } -QVariant CSMWorld::LandTextureIdTable::data(const QModelIndex& index, int role) const -{ - if (role==Qt::EditRole && !idCollection()->getRecord(index.row()).isModified()) - return QVariant(); - - return IdTable::data(index, role); -} - -bool CSMWorld::LandTextureIdTable::setData(const QModelIndex& index, const QVariant& value, int role) -{ - if (!idCollection()->getRecord(index.row()).isModified()) - return false; - else - return IdTable::setData(index, value, role); -} - -Qt::ItemFlags CSMWorld::LandTextureIdTable::flags(const QModelIndex& index) const -{ - Qt::ItemFlags flags = IdTable::flags(index); - - if (!idCollection()->getRecord(index.row()).isModified()) - flags &= ~Qt::ItemIsEnabled; - - return flags; -} - CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::importTextures(const std::vector& ids) { ImportResults results; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index ccc5ac404..4136061e4 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -118,12 +118,6 @@ namespace CSMWorld LandTextureIdTable(CollectionBase* idCollection, unsigned int features=0); - QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const override; - - bool setData(const QModelIndex& index, const QVariant& value, int role) override; - - Qt::ItemFlags flags (const QModelIndex & index) const override; - /// Finds and maps/recreates the specified ids. ImportResults importTextures(const std::vector& ids); }; From d7a5622485a03ef6324470fcb84976882f444af7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 3 Oct 2017 09:16:46 +0000 Subject: [PATCH 365/521] Fix book window buttons overlap --- files/mygui/openmw_book.layout | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index a7bea5eb5..c83c4982b 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -14,19 +14,15 @@ - - - - - - + + + + - - - - - - + + + + From c598f1313c4233af2aec6dcb92e4924408120961 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 3 Oct 2017 17:34:45 +0200 Subject: [PATCH 366/521] [macOS, CI] Update dependencies The following changes are included: - https://github.com/OpenMW/openmw-deps-mac/pull/37 - https://github.com/OpenMW/openmw-deps-mac/pull/38 --- CI/before_install.osx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index 25e1c9517..86e8fb81b 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -6,5 +6,5 @@ brew outdated cmake || brew upgrade cmake brew outdated pkgconfig || brew upgrade pkgconfig brew install $macos_qt_formula -curl https://downloads.openmw.org/osx/dependencies/openmw-deps-5e144e2.zip -o ~/openmw-deps.zip +curl https://downloads.openmw.org/osx/dependencies/openmw-deps-c40905f.zip -o ~/openmw-deps.zip unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null From 433028e8d7395db109920e0b74309388ddec8984 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 3 Oct 2017 22:07:56 +0000 Subject: [PATCH 367/521] Fix GUI regressions --- apps/openmw/mwgui/dialogue.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8dd027c4a..e13e626ae 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -390,6 +390,7 @@ namespace MWGui { // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); if (isCompanion()) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); return; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e96743b91..fdf4da8a7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -606,7 +606,7 @@ namespace MWGui mMap->setVisible(false); mStatsWindow->setVisible(false); mSpellWindow->setVisible(false); - mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter); + mInventoryWindow->setVisible(getMode() == GM_Container || getMode() == GM_Barter || getMode() == GM_Companion); } GuiMode mode = mGuiModes.back(); From 1cb7ed5db102117b595b8d026d49a51a6244d068 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 3 Oct 2017 09:59:31 +0400 Subject: [PATCH 368/521] Use owned tooltips for items in containers correctly --- apps/openmw/mwgui/container.cpp | 20 ++++++--- apps/openmw/mwgui/containeritemmodel.cpp | 16 +++++++ apps/openmw/mwgui/containeritemmodel.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 10 +++++ apps/openmw/mwgui/itemmodel.hpp | 6 +++ apps/openmw/mwgui/pickpocketitemmodel.cpp | 5 +++ apps/openmw/mwgui/pickpocketitemmodel.hpp | 2 + apps/openmw/mwgui/sortfilteritemmodel.cpp | 5 +++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 1 + apps/openmw/mwgui/tooltips.cpp | 44 +++++++++---------- apps/openmw/mwgui/tooltips.hpp | 4 +- apps/openmw/mwgui/tradeitemmodel.cpp | 5 +++ apps/openmw/mwgui/tradeitemmodel.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 3 ++ 14 files changed, 92 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index a70d833c7..74ed4fff9 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -22,6 +22,7 @@ #include "itemview.hpp" #include "itemwidget.hpp" #include "inventoryitemmodel.hpp" +#include "containeritemmodel.hpp" #include "sortfilteritemmodel.hpp" #include "pickpocketitemmodel.hpp" #include "draganddrop.hpp" @@ -136,15 +137,22 @@ namespace MWGui bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); - if (mPtr.getClass().isNpc() && !loot) + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // we are stealing stuff - MWWorld::Ptr player = MWMechanics::getPlayer(); - mModel = new PickpocketItemModel(player, new InventoryItemModel(container), - !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); + if (mPtr.getClass().isNpc() && !loot) + { + // we are stealing stuff + MWWorld::Ptr player = MWMechanics::getPlayer(); + mModel = new PickpocketItemModel(player, new InventoryItemModel(container), + !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); + } + else + mModel = new InventoryItemModel(container); } else - mModel = new InventoryItemModel(container); + { + mModel = new ContainerItemModel(container); + } mDisposeCorpseButton->setVisible(loot); diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index d62cd16b0..479638672 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -6,8 +6,11 @@ #include "../mwworld/class.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace { @@ -47,6 +50,19 @@ ContainerItemModel::ContainerItemModel (const MWWorld::Ptr& source) mItemSources.push_back(source); } +bool ContainerItemModel::allowedToUseItems() const +{ + if (mItemSources.size() == 0) + return true; + + MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::Ptr victim; + + // Check if the player is allowed to use items from opened container + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + return mm->isAllowedToUse(ptr, mItemSources[0], victim); +} + ItemStack ContainerItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 7ced6ae34..c6ecafd46 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -17,6 +17,7 @@ namespace MWGui ContainerItemModel (const MWWorld::Ptr& source); + virtual bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 390bb0586..ffcf9075e 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -119,6 +119,11 @@ namespace MWGui return ret; } + bool ItemModel::allowedToUseItems() const + { + return true; + } + bool ItemModel::allowedToInsertItems() const { return true; @@ -135,6 +140,11 @@ namespace MWGui delete mSourceModel; } + bool ProxyItemModel::allowedToUseItems() const + { + return mSourceModel->allowedToUseItems(); + } + MWWorld::Ptr ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner) { return mSourceModel->copyItem (item, count, setNewOwner); diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 20955b206..bc6be8023 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -70,6 +70,9 @@ namespace MWGui virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0; virtual void removeItem (const ItemStack& item, size_t count) = 0; + /// Is the player allowed to use items from this item model? (default true) + virtual bool allowedToUseItems() const; + /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; @@ -85,6 +88,9 @@ namespace MWGui public: ProxyItemModel(); virtual ~ProxyItemModel(); + + bool allowedToUseItems() const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 238fb5913..ec4b378a0 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -26,6 +26,11 @@ namespace MWGui } } + bool PickpocketItemModel::allowedToUseItems() const + { + return false; + } + ItemStack PickpocketItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 61f0569b5..1b08ec485 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -11,6 +11,8 @@ namespace MWGui { public: PickpocketItemModel (const MWWorld::Ptr& thief, ItemModel* sourceModel, bool hideItems=true); + + virtual bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); virtual void update(); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 45aa261df..e294ebe07 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -159,6 +159,11 @@ namespace MWGui mSourceModel = sourceModel; } + bool SortFilterItemModel::allowedToUseItems() const + { + return mSourceModel->allowedToUseItems(); + } + void SortFilterItemModel::addDragItem (const MWWorld::Ptr& dragItem, size_t count) { mDragItems.push_back(std::make_pair(dragItem, count)); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 4731cbb8a..6ddb019b0 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -15,6 +15,7 @@ namespace MWGui bool filterAccepts (const ItemStack& item); + bool allowedToUseItems() const; virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a9930db4f..af6bf4726 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -120,7 +120,7 @@ namespace MWGui if (info.caption.empty()) info.caption=mFocusObject.getCellRef().getRefId(); info.icon=""; - tooltipSize = createToolTip(info, true); + tooltipSize = createToolTip(info, checkOwned()); } else tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true); @@ -186,22 +186,24 @@ namespace MWGui ToolTipInfo info; info.text = data.caption; info.notes = data.notes; - tooltipSize = createToolTip(info, false); + tooltipSize = createToolTip(info); } else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false); + bool isAllowedToUse = checkOwned(); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, !isAllowedToUse); } else if (type == "ItemModelIndex") { std::pair pair = *focus->getUserData >(); mFocusObject = pair.second->getItem(pair.first).mBase; - tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false); + bool isAllowedToUse = pair.second->allowedToUseItems(); + tooltipSize = getToolTipViaPtr(pair.second->getItem(pair.first).mCount, false, !isAllowedToUse); } else if (type == "ToolTipInfo") { - tooltipSize = createToolTip(*focus->getUserData(), false); + tooltipSize = createToolTip(*focus->getUserData()); } else if (type == "AvatarItemSelection") { @@ -244,7 +246,7 @@ namespace MWGui info.text = "#{sSchool}: " + sSchoolNames[school]; } info.effects = effects; - tooltipSize = createToolTip(info, false); + tooltipSize = createToolTip(info); } else if (type == "Layout") { @@ -298,7 +300,7 @@ namespace MWGui { if (!mFocusObject.isEmpty()) { - MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount()); + MyGUI::IntSize tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), true, checkOwned()); setCoord(viewSize.width/2 - tooltipSize.width/2, std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), @@ -332,7 +334,7 @@ namespace MWGui update(mFrameDuration); } - MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image) + MyGUI::IntSize ToolTips::getToolTipViaPtr (int count, bool image, bool isOwned) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -351,7 +353,7 @@ namespace MWGui ToolTipInfo info = object.getToolTipInfo(mFocusObject, count); if (!image) info.icon = ""; - tooltipSize = createToolTip(info, true); + tooltipSize = createToolTip(info, isOwned); } return tooltipSize; @@ -359,27 +361,21 @@ namespace MWGui bool ToolTips::checkOwned() { - if(!mFocusObject.isEmpty()) - { - MWWorld::Ptr ptr = MWMechanics::getPlayer(); - MWWorld::Ptr victim; - - MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); - bool allowed = mm->isAllowedToUse(ptr, mFocusObject, victim); - - return !allowed; - } - else - { + if(mFocusObject.isEmpty()) return false; - } + + MWWorld::Ptr ptr = MWMechanics::getPlayer(); + MWWorld::Ptr victim; + + MWBase::MechanicsManager* mm = MWBase::Environment::get().getMechanicsManager(); + return !mm->isAllowedToUse(ptr, mFocusObject, victim); } - MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isFocusObject) + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info, bool isOwned) { mDynamicToolTipBox->setVisible(true); - if((mShowOwned == 1 || mShowOwned == 3) && isFocusObject && checkOwned()) + if((mShowOwned == 1 || mShowOwned == 3) && isOwned) mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp_Owned" : "HUD_Box_Owned"); else mDynamicToolTipBox->changeWidgetSkin(MWBase::Environment::get().getWindowManager()->isGuiMode() ? "HUD_Box_NoTransp" : "HUD_Box"); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 2793e6544..1ef473b5a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -98,10 +98,10 @@ namespace MWGui MWWorld::Ptr mFocusObject; - MyGUI::IntSize getToolTipViaPtr (int count, bool image=true); + MyGUI::IntSize getToolTipViaPtr (int count, bool image = true, bool isOwned = false); ///< @return requested tooltip size - MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isFocusObject); + MyGUI::IntSize createToolTip(const ToolTipInfo& info, bool isOwned = false); ///< @return requested tooltip size /// @param isFocusObject Is the object this tooltips originates from mFocusObject? diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index ae3feb61c..a26294a0e 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -15,6 +15,11 @@ namespace MWGui mSourceModel = sourceModel; } + bool TradeItemModel::allowedToUseItems() const + { + return true; + } + ItemStack TradeItemModel::getItem (ModelIndex index) { if (index < 0) diff --git a/apps/openmw/mwgui/tradeitemmodel.hpp b/apps/openmw/mwgui/tradeitemmodel.hpp index 1bfee9b2a..cdb949c49 100644 --- a/apps/openmw/mwgui/tradeitemmodel.hpp +++ b/apps/openmw/mwgui/tradeitemmodel.hpp @@ -15,6 +15,8 @@ namespace MWGui public: TradeItemModel (ItemModel* sourceModel, const MWWorld::Ptr& merchant); + bool allowedToUseItems() const; + virtual ItemStack getItem (ModelIndex index); virtual size_t getItemCount(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index da98e7f5f..2c7b6a500 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -842,6 +842,9 @@ namespace MWMechanics bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { + if (target.isEmpty()) + return true; + const MWWorld::CellRef& cellref = target.getCellRef(); // there is no harm to use unlocked doors if (target.getClass().isDoor() && cellref.getLockLevel() <= 0 && ptr.getCellRef().getTrap().empty()) From 7c68ed04b2bb458d02fd6b57dd1f1b9a3187ab48 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:03:23 +0200 Subject: [PATCH 369/521] Don't require modal windows to be removed in the same order they were added --- apps/openmw/mwgui/windowmanagerimp.cpp | 24 ++++++++++++++---------- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fdf4da8a7..a9ca9bd19 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -865,7 +865,7 @@ namespace MWGui window->onFrame(frameDuration); } if (!mCurrentModals.empty()) - mCurrentModals.top()->onFrame(frameDuration); + mCurrentModals.back()->onFrame(frameDuration); mKeyboardNavigation->onFrame(); @@ -1727,9 +1727,9 @@ namespace MWGui { if (!mCurrentModals.empty()) { - if (!mCurrentModals.top()->exit()) + if (!mCurrentModals.back()->exit()) return; - mCurrentModals.top()->setVisible(false); + mCurrentModals.back()->setVisible(false); } } @@ -1738,7 +1738,7 @@ namespace MWGui if (mCurrentModals.empty()) mKeyboardNavigation->saveFocus(getMode()); - mCurrentModals.push(input); + mCurrentModals.push_back(input); mKeyboardNavigation->restoreFocus(-1); mKeyboardNavigation->setModalWindow(input->mMainWidget); @@ -1747,17 +1747,21 @@ namespace MWGui void WindowManager::removeCurrentModal(WindowModal* input) { - // Only remove the top if it matches the current pointer. A lot of things hide their visibility before showing it, - //so just popping the top would cause massive issues. if(!mCurrentModals.empty()) { - if(input == mCurrentModals.top()) + if(input == mCurrentModals.back()) { - mCurrentModals.pop(); + mCurrentModals.pop_back(); mKeyboardNavigation->saveFocus(-1); } else - std::cout << " warning: modal widget " << input << " " << typeid(input).name() << " not found " << std::endl; + { + auto found = std::find(mCurrentModals.begin(), mCurrentModals.end(), input); + if (found != mCurrentModals.end()) + mCurrentModals.erase(found); + else + std::cerr << " warning: can't find modal window " << input << std::endl; + } } if (mCurrentModals.empty()) { @@ -1765,7 +1769,7 @@ namespace MWGui mKeyboardNavigation->restoreFocus(getMode()); } else - mKeyboardNavigation->setModalWindow(mCurrentModals.top()->mMainWidget); + mKeyboardNavigation->setModalWindow(mCurrentModals.back()->mMainWidget); } void WindowManager::onVideoKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 612470a7e..bdd2aa094 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -401,7 +401,7 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - std::stack mCurrentModals; + std::vector mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). CustomMarkerCollection mCustomMarkers; From 49a0922f1b4b26c5dd421ab326fb6529b55d79eb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:08:09 +0200 Subject: [PATCH 370/521] Remove 'visibility mask' gui feature which did not end up being useful --- apps/openmw/mwgui/windowmanagerimp.cpp | 29 +++++++++++--------------- apps/openmw/mwgui/windowmanagerimp.hpp | 1 - 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a9ca9bd19..9a7a7437a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -613,18 +613,18 @@ namespace MWGui mInventoryWindow->setTrading(mode == GM_Barter); - // For the inventory mode, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed & ~mForceHidden; - mGuiModeStates[GM_Inventory].mVisibilityMask.resize(4); - mGuiModeStates[GM_Inventory].mVisibilityMask[0] = eff & GW_Map; - mGuiModeStates[GM_Inventory].mVisibilityMask[1] = eff & GW_Inventory; - mGuiModeStates[GM_Inventory].mVisibilityMask[2] = eff & GW_Magic; - mGuiModeStates[GM_Inventory].mVisibilityMask[3] = eff & GW_Stats; if (getMode() == GM_Inventory) - mGuiModeStates[GM_Inventory].update(true); + { + // For the inventory mode, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed & ~mForceHidden; + mMap->setVisible(eff & GW_Map); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow->setVisible(eff & GW_Magic); + mStatsWindow->setVisible(eff & GW_Stats); + } switch (mode) { @@ -2063,12 +2063,7 @@ namespace MWGui void WindowManager::GuiModeState::update(bool visible) { for (unsigned int i=0; isetVisible(visible && visibilityMask); - } + mWindows[i]->setVisible(visible); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bdd2aa094..c8bc8d21e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -477,7 +477,6 @@ namespace MWGui void update(bool visible); std::vector mWindows; - std::vector mVisibilityMask; // optional, may be used to temporarily exclude windows from this mode. std::string mCloseSound; std::string mOpenSound; From e4f0f7157a796ccf647b6e841b06604ce8f0bf69 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:08:52 +0200 Subject: [PATCH 371/521] Fix pinned windows not being updated --- apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 9a7a7437a..eae706ec3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -864,6 +864,14 @@ namespace MWGui for (WindowBase* window : state.mWindows) window->onFrame(frameDuration); } + else + { + // update pinned windows if visible + for (WindowBase* window : mGuiModeStates[GM_Inventory].mWindows) + if (window->isVisible()) + window->onFrame(frameDuration); + } + if (!mCurrentModals.empty()) mCurrentModals.back()->onFrame(frameDuration); From a4737d84178e0f7ae58ed9364d648d1e9c4c687f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:26:23 +0200 Subject: [PATCH 372/521] Use MyGUI frame events for ScreenFader --- apps/openmw/mwgui/screenfader.cpp | 10 +++++++++- apps/openmw/mwgui/screenfader.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp index d1118848b..9a9a1ae01 100644 --- a/apps/openmw/mwgui/screenfader.cpp +++ b/apps/openmw/mwgui/screenfader.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace MWGui { @@ -80,6 +81,8 @@ namespace MWGui , mFactor(1.f) , mRepeat(false) { + MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); MyGUI::ImageBox* imageBox = mMainWidget->castType(false); @@ -94,7 +97,12 @@ namespace MWGui } } - void ScreenFader::update(float dt) + ScreenFader::~ScreenFader() + { + MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &ScreenFader::onFrameStart); + } + + void ScreenFader::onFrameStart(float dt) { if (!mQueue.empty()) { diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp index 88dd0c57b..79bea30e5 100644 --- a/apps/openmw/mwgui/screenfader.hpp +++ b/apps/openmw/mwgui/screenfader.hpp @@ -36,8 +36,9 @@ namespace MWGui { public: ScreenFader(const std::string & texturePath, const std::string& layout = "openmw_screen_fader.layout", const MyGUI::FloatCoord& texCoordOverride = MyGUI::FloatCoord(0,0,1,1)); + ~ScreenFader(); - void update(float dt); + void onFrameStart(float dt); void fadeIn(const float time, float delay=0); void fadeOut(const float time, float delay=0); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eae706ec3..504bef964 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -894,12 +894,6 @@ namespace MWGui mHud->onFrame(frameDuration); - if (mWerewolfFader) - mWerewolfFader->update(frameDuration); - mBlindnessFader->update(frameDuration); - mHitFader->update(frameDuration); - mScreenFader->update(frameDuration); - mDebugWindow->onFrame(frameDuration); if (mCharGen) From 12510efab7bd2e29f23e5054356718a8847bf763 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:39:19 +0200 Subject: [PATCH 373/521] Fade screen out during loading screen (when travelling) --- apps/openmw/mwgui/loadingscreen.cpp | 12 ++++++++++-- apps/openmw/mwgui/loadingscreen.hpp | 1 + apps/openmw/mwgui/travelwindow.cpp | 2 ++ files/mygui/openmw_layers.xml | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f22d825dd..4753c39f2 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -50,6 +50,8 @@ namespace MWGui mBackgroundImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Stretch, "Menu"); + mSceneImage = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Stretch, "Scene"); findSplashScreens(); } @@ -110,6 +112,7 @@ namespace MWGui { WindowBase::setVisible(visible); mBackgroundImage->setVisible(visible); + mSceneImage->setVisible(visible); } double LoadingScreen::getTargetFrameRate() const @@ -214,8 +217,11 @@ namespace MWGui // TODO: add option (filename pattern?) to use image aspect ratio instead of 4:3 // we can't do this by default, because the Morrowind splash screens are 1024x1024, but should be displayed as 4:3 bool stretch = Settings::Manager::getBool("stretch menu background", "GUI"); + mBackgroundImage->setVisible(true); mBackgroundImage->setBackgroundImage(randomSplash, true, stretch); } + mSceneImage->setBackgroundImage(""); + mSceneImage->setVisible(false); } void LoadingScreen::setProgressRange (size_t range) @@ -292,9 +298,11 @@ namespace MWGui mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture)); mBackgroundImage->setBackgroundImage(""); + mBackgroundImage->setVisible(false); - mBackgroundImage->setRenderItemTexture(mGuiTexture.get()); - mBackgroundImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mSceneImage->setRenderItemTexture(mGuiTexture.get()); + mSceneImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + mSceneImage->setVisible(true); } void LoadingScreen::draw() diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 2f8831fdc..8536972a3 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -72,6 +72,7 @@ namespace MWGui MyGUI::TextBox* mLoadingText; MyGUI::ScrollBar* mProgressBar; BackgroundImage* mBackgroundImage; + BackgroundImage* mSceneImage; std::vector mSplashScreens; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7c7cdb63e..7586bb66a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -178,6 +178,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); + // Teleports any followers, too. MWWorld::ActionTeleport action(interior ? cellname : "", pos, true); action.execute(player); diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index cd8a9f760..5e4a74978 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,6 +1,7 @@ + From d94235e3a727bcec1d800cd4184bd70da142d306 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 4 Oct 2017 17:47:42 +0200 Subject: [PATCH 374/521] Update the saves list/preview image when character selection changes to make it more convenient to flip through characters with the keyboard --- apps/openmw/mwgui/savegamedialog.cpp | 13 ++++++++++--- apps/openmw/mwgui/savegamedialog.hpp | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 423dbb036..6a290bef1 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -50,7 +50,8 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked); mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked); - mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); + mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected); + mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterAccept); mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected); mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick); mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated); @@ -132,6 +133,8 @@ namespace MWGui mSaveNameEdit->setCaption (""); if (mSaving) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit); + else + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); center(); @@ -322,6 +325,12 @@ namespace MWGui fillSaveList(); } + void SaveGameDialog::onCharacterAccept(MyGUI::ComboBox* sender, size_t pos) + { + // Give key focus to save list so we can confirm the selection with Enter + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); + } + void SaveGameDialog::fillSaveList() { mSaveList->removeAllItems(); @@ -336,8 +345,6 @@ namespace MWGui { mSaveList->setIndexSelected(0); onSlotSelected(mSaveList, 0); - // Give key focus to save list so we can confirm the selection with Enter - MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList); } else onSlotSelected(mSaveList, MyGUI::ITEM_NONE); diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index a51124705..0a87b6600 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -29,6 +29,7 @@ namespace MWGui void onOkButtonClicked (MyGUI::Widget* sender); void onDeleteButtonClicked (MyGUI::Widget* sender); void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos); + void onCharacterAccept(MyGUI::ComboBox* sender, size_t pos); // Slot selected (mouse click or arrow keys) void onSlotSelected (MyGUI::ListBox* sender, size_t pos); // Slot activated (double click or enter key) From cd437f094d9fbeb77850dbaa0d84fb25ca749151 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:35:09 +0200 Subject: [PATCH 375/521] Fix exiting savegamedialog with 'esc' when no game is running --- apps/openmw/mwgui/mainmenu.cpp | 5 +++++ apps/openmw/mwgui/mainmenu.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 00e4e30a5..5017b8893 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -210,6 +210,11 @@ namespace MWGui } } + bool MainMenu::exit() + { + return MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running; + } + void MainMenu::updateMenu() { setCoord(0,0, mWidth, mHeight); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 1beb9ee16..82553d22e 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -38,6 +38,8 @@ namespace MWGui void onFrame(float dt); + bool exit(); + private: const VFS::Manager* mVFS; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 504bef964..a81c3a614 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -750,8 +750,8 @@ namespace MWGui if (!window->exit()) { // unable to exit window, but give access to main menu - if (!MyGUI::InputManager::getInstance().isModalAny()) - pushGuiMode (MWGui::GM_MainMenu); + if (!MyGUI::InputManager::getInstance().isModalAny() && getMode() != GM_MainMenu) + pushGuiMode (GM_MainMenu); return; } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e6acbbd52..06ebeb0b8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -241,9 +241,7 @@ namespace MWInput switch (action) { case A_GameMenu: - if(!(MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_MainMenu)) - toggleMainMenu (); + toggleMainMenu (); break; case A_Screenshot: screenshot(); From 8c0790580a80431d9f31d7beed07f8e61beae121 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:39:28 +0200 Subject: [PATCH 376/521] Add screen fading for exterior cell transitions --- apps/openmw/mwworld/scene.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c83165239..0a27cf257 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -580,10 +580,16 @@ namespace MWWorld MWBase::Environment::get().getWorld()->positionToIndex (position.pos[0], position.pos[1], x, y); + if (changeEvent) + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + changeCellGrid(x, y, changeEvent); CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); changePlayerCell(current, position, adjustPlayerPos); + + if (changeEvent) + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); } CellStore* Scene::getCurrentCell () From 842a42ee664b30dee6e9bd74c4a70de1bfca19ea Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 5 Oct 2017 18:39:58 +0200 Subject: [PATCH 377/521] Fix non-top level Windows accepting key focus --- apps/openmw/mwgui/keyboardnavigation.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index 2b06de295..d27185204 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -12,6 +12,11 @@ namespace MWGui { +bool shouldAcceptKeyFocus(MyGUI::Widget* w) +{ + return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); +} + /// Recursively get all child widgets that accept keyboard input void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& results) { @@ -24,18 +29,13 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu MyGUI::Widget* w = enumerator.current(); if (!w->getVisible() || !w->getEnabled()) continue; - if (w->getNeedKeyFocus()) + if (w->getNeedKeyFocus() && shouldAcceptKeyFocus(w)) results.push_back(w); else getKeyFocusWidgets(w, results); } } -bool shouldAcceptKeyFocus(MyGUI::Widget* w) -{ - return w && !w->castType(false) && w->getInheritedEnabled() && w->getInheritedVisible() && w->getVisible() && w->getEnabled(); -} - KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) , mModalWindow(nullptr) From e2afd3690c0f2495a1efd12576e5ed91c3dab932 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 6 Oct 2017 10:54:25 +0400 Subject: [PATCH 378/521] Remove item by id from InventoryStore --- apps/openmw/mwmechanics/actors.cpp | 6 +----- apps/openmw/mwworld/inventorystore.cpp | 19 +++++++++++++++++++ apps/openmw/mwworld/inventorystore.hpp | 3 +++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0715eb177..a144911c5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -70,11 +70,7 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } } else - { - MWWorld::Ptr itemPtr = actor.getClass().getInventoryStore(actor).search(item); - if (!itemPtr.isEmpty()) - actor.getClass().getInventoryStore(actor).remove(itemPtr, 1, actor, true); - } + actor.getClass().getInventoryStore(actor).remove(item, 1, actor, true); } class CheckActorCommanded : public MWMechanics::EffectSourceVisitor diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index b599b3583..77141f269 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -654,11 +654,30 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( return mSelectedEnchantItem; } +int MWWorld::InventoryStore::remove(const std::string& itemId, int count, const Ptr& actor) +{ + return remove(itemId, count, actor, false); +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) { return remove(item, count, actor, false); } +int MWWorld::InventoryStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement) +{ + int toRemove = count; + + for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) + toRemove -= remove(*iter, toRemove, actor, equipReplacement); + + flagAsModified(); + + // number of removed items + return count - toRemove; +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { int retCount = ContainerStore::remove(item, count, actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 851abf408..49991c164 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -177,6 +177,9 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other + virtual int remove(const std::string& itemId, int count, const Ptr& actor); + virtual int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement); + virtual int remove(const Ptr& item, int count, const Ptr& actor); virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement); ///< Remove \a count item(s) designated by \a item from this inventory. From ad27e0f945ed2bafca11b4fdeff5cefd01e52863 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 6 Oct 2017 11:38:27 +0400 Subject: [PATCH 379/521] Fix owned tooltip in the spellwindow --- apps/openmw/mwgui/tooltips.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index af6bf4726..b2991a034 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -191,8 +191,7 @@ namespace MWGui else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); - bool isAllowedToUse = checkOwned(); - tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, !isAllowedToUse); + tooltipSize = getToolTipViaPtr(mFocusObject.getRefData().getCount(), false, checkOwned()); } else if (type == "ItemModelIndex") { From 280578154222556506c3c293c63e7ea5b7a0b4b7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 6 Oct 2017 16:18:57 +0000 Subject: [PATCH 380/521] Fix a crash when exit() already hides the window (Fixes #4148) --- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a81c3a614..ccdd6916c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1729,9 +1729,10 @@ namespace MWGui { if (!mCurrentModals.empty()) { - if (!mCurrentModals.back()->exit()) + WindowModal* window = mCurrentModals.back(); + if (!window->exit()) return; - mCurrentModals.back()->setVisible(false); + window->setVisible(false); } } From b14404e9cccbb3c8a91d7f5e6476b15d30be1850 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Fri, 6 Oct 2017 20:05:06 -0400 Subject: [PATCH 381/521] Fix region colors --- apps/opencs/model/world/columnimp.hpp | 17 ++++------------- apps/opencs/view/world/colordelegate.cpp | 15 +++++++++------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index e36e386c9..f1025acb9 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -692,32 +692,23 @@ namespace CSMWorld } }; - /// \todo QColor is a GUI class and should not be in model. Need to think of an alternative - /// solution. template struct MapColourColumn : public Column { - /// \todo Replace Display_Integer with something that displays the colour value more directly. MapColourColumn() : Column (Columns::ColumnId_MapColour, ColumnBase::Display_Colour) {} virtual QVariant get (const Record& record) const { - int colour = record.get().mMapColor; - - return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff); + return record.get().mMapColor; } virtual void set (Record& record, const QVariant& data) { - ESXRecordT record2 = record.get(); - - QColor colour = data.value(); - - record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red(); - - record.setModified (record2); + ESXRecordT copy = record.get(); + copy.mMapColor = data.toInt(); + record.setModified (copy); } virtual bool isEditable() const diff --git a/apps/opencs/view/world/colordelegate.cpp b/apps/opencs/view/world/colordelegate.cpp index 1a89fc675..15a07b42c 100644 --- a/apps/opencs/view/world/colordelegate.cpp +++ b/apps/opencs/view/world/colordelegate.cpp @@ -5,29 +5,32 @@ #include "../widget/coloreditor.hpp" -CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document& document, +CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, QObject *parent) : CommandDelegate(dispatcher, document, parent) {} -void CSVWorld::ColorDelegate::paint(QPainter *painter, +void CSVWorld::ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + int colorInt = index.data().toInt(); + QColor color(colorInt & 0xff, (colorInt >> 8) & 0xff, (colorInt >> 16) & 0xff); + QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0), option.rect.y() + qRound(option.rect.height() / 4.0), option.rect.width() / 2, option.rect.height() / 2); painter->save(); - painter->fillRect(coloredRect, index.data().value()); + painter->fillRect(coloredRect, color); painter->setPen(Qt::black); painter->drawRect(coloredRect); painter->restore(); } -CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, - CSMDoc::Document &document, +CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document &document, QObject *parent) const { return new ColorDelegate(dispatcher, document, parent); From ea3729790f113120d98fae5940e62f6d852a4e5c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 8 Oct 2017 09:20:07 +0400 Subject: [PATCH 382/521] Add showsInInventory() check to the ContainerItemModel --- apps/openmw/mwgui/containeritemmodel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 479638672..9f7a9965c 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -142,6 +142,9 @@ void ContainerItemModel::update() 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) { From dc127fbb93316865f8023977ccb29b91b8f3ad5b Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Oct 2017 11:58:38 +0200 Subject: [PATCH 383/521] Add a launch checkbox to the OpenMW installer --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0050104cf..50c0d5455 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,6 +497,7 @@ if(WIN32) SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe") + SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") From 479f9535b43fdc528539a632413e35e415007924 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 8 Oct 2017 20:38:20 +0000 Subject: [PATCH 384/521] Allow training window exit() --- apps/openmw/mwgui/trainingwindow.cpp | 6 ++++++ apps/openmw/mwgui/trainingwindow.hpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index b6504d223..04b051e16 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -203,4 +203,10 @@ namespace MWGui checkReferenceAvailable(); mTimeAdvancer.onFrame(dt); } + + bool TrainingWindow::exit() + { + return !mTimeAdvancer.isRunning(); + } + } diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index 69a013059..2edad1f27 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -16,7 +16,7 @@ namespace MWGui virtual void onOpen(); - bool exit() { return false; } + bool exit(); void setPtr(const MWWorld::Ptr& actor); From f8fe992dc0bdc393f847812bd321daf0eed32451 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 21:58:55 +0100 Subject: [PATCH 385/521] Adjust CMake's run-time resource handling such that the Windows CI script does not have to copy these files --- CI/before_script.msvc.sh | 15 --------------- CMakeLists.txt | 24 ++++++++++++------------ cmake/GitVersion.cmake | 18 +++++++++++++++++- cmake/OpenMWMacros.cmake | 29 +++++++++++++++++++++++++++++ components/CMakeLists.txt | 9 ++++++--- files/mygui/CMakeLists.txt | 4 ++-- files/shaders/CMakeLists.txt | 4 ++-- 7 files changed, 68 insertions(+), 35 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 14998a3c6..a7f30d7ed 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -750,19 +750,4 @@ if [ -z $VERBOSE ]; then fi fi -if [ -z $CI ]; then - echo "- Copying Runtime Resources/Config Files" - echo " gamecontrollerdb.txt" - cp gamecontrollerdb.txt $BUILD_CONFIG/gamecontrollerdb.txt - echo " openmw.cfg" - cp openmw.cfg.install $BUILD_CONFIG/openmw.cfg - echo " openmw-cs.cfg" - cp openmw-cs.cfg $BUILD_CONFIG/openmw-cs.cfg - echo " settings-default.cfg" - cp settings-default.cfg $BUILD_CONFIG/settings-default.cfg - echo " resources/" - cp -r resources $BUILD_CONFIG/resources - echo -fi - exit $RET diff --git a/CMakeLists.txt b/CMakeLists.txt index 50c0d5455..2bf2896da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,27 +313,27 @@ endif (APPLE) # Other files -configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg - "${OpenMW_BINARY_DIR}/settings-default.cfg") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg + "${OpenMW_BINARY_DIR}" "settings-default.cfg") if (NOT APPLE) - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local - "${OpenMW_BINARY_DIR}/openmw.cfg") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg - "${OpenMW_BINARY_DIR}/openmw.cfg.install") + configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local + "${OpenMW_BINARY_DIR}" "openmw.cfg") + configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg + "${OpenMW_BINARY_DIR}" "openmw.cfg.install") else () configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg") endif () -configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg - "${OpenMW_BINARY_DIR}/openmw-cs.cfg") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg + "${OpenMW_BINARY_DIR}" "openmw-cs.cfg") -configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters - "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) +configure_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters + "${OpenMW_BINARY_DIR}" "resources/defaultfilters" COPYONLY) -configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt - "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt + "${OpenMW_BINARY_DIR}" "gamecontrollerdb.txt") if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 32abbbfbf..0eefe01e6 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -26,4 +26,20 @@ else () message(WARNING "Failed to get valid version information from Git") endif () -configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) +# duplicated from OpenMWMacros.cmake +macro (configure_resource_file source_path destination_dir_base dest_path_relative) + if (MSVC) + configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") + else (MSVC) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") + endif (MSVC) +endmacro (configure_resource_file) + +message(STATUS ${VERSION_IN_FILE}) +message(STATUS ${VERSION_FILE_PATH_BASE}) +message(STATUS ${VERSION_FILE_PATH_RELATIVE}) + +configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 6573265bd..08b36017b 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -171,3 +171,32 @@ macro (openmw_add_executable target) endif (CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) endif (MSVC) endmacro (openmw_add_executable) + +macro (copy_resource_file source_path destination_dir_base dest_path_relative) + if (MSVC) + configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}" COPYONLY) + configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}" COPYONLY) + configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}" COPYONLY) + configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}" COPYONLY) + else (MSVC) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}" COPYONLY) + endif (MSVC) +endmacro (copy_resource_file) + +macro (configure_resource_file source_path destination_dir_base dest_path_relative) + if (MSVC) + configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") + configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") + else (MSVC) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") + endif (MSVC) +endmacro (configure_resource_file) + +macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) + foreach (f ${files}) + get_filename_component(filename ${f} NAME) + copy_resource_file("${source_dir}/${f}" "${destination_dir_base}" "${destination_dir_relative}/${filename}") + endforeach (f) +endmacro (copy_all_files) \ No newline at end of file diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 88de17903..bb22e047c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -2,22 +2,25 @@ project (Components) # Version file set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") -set (VERSION_FILE "${OpenMW_BINARY_DIR}/resources/version") +set (VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") +set (VERSION_FILE_PATH_RELATIVE resources/version) if (GIT_CHECKOUT) add_custom_target (git-version COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} -DVERSION_IN_FILE=${VERSION_IN_FILE} - -DVERSION_FILE=${VERSION_FILE} + -DVERSION_FILE_PATH_BASE=${VERSION_FILE_PATH_BASE} + -DVERSION_FILE_PATH_RELATIVE=${VERSION_FILE_PATH_RELATIVE} -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} + -DMSVC=${MSVC} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) - configure_file(${VERSION_IN_FILE} ${VERSION_FILE}) + configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) endif (GIT_CHECKOUT) if (OPENGL_ES) diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ed673c5d6..49b833e38 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -4,7 +4,7 @@ endif() # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(DDIR ${OPENMW_MYGUI_FILES_ROOT}/resources/mygui) +set(DDIRRELATIVE resources/mygui) set(MYGUI_FILES core.skin @@ -97,4 +97,4 @@ set(MYGUI_FILES ) -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${MYGUI_FILES}") +copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_MYGUI_FILES_ROOT} ${DDIRRELATIVE} "${MYGUI_FILES}") diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 5ca0d1e83..5833a592f 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -4,7 +4,7 @@ endif() # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(DDIR ${OPENMW_SHADERS_ROOT}/resources/shaders) +set(DDIRRELATIVE resources/shaders) set(SHADER_FILES water_vertex.glsl @@ -18,4 +18,4 @@ set(SHADER_FILES parallax.glsl ) -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${SHADER_FILES}") +copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") From 5ceaaabeb2c8a448cd220e06c6f39c121fbc381e Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 22:08:49 +0100 Subject: [PATCH 386/521] Remove MESSAGE calls I accidentally left in --- cmake/GitVersion.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 0eefe01e6..786ac23ed 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -38,8 +38,4 @@ macro (configure_resource_file source_path destination_dir_base dest_path_relati endif (MSVC) endmacro (configure_resource_file) -message(STATUS ${VERSION_IN_FILE}) -message(STATUS ${VERSION_FILE_PATH_BASE}) -message(STATUS ${VERSION_FILE_PATH_RELATIVE}) - configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) From 2652a89df4425017b7d1a62a4bf9ce493a8d7282 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 11 Oct 2017 22:10:52 +0100 Subject: [PATCH 387/521] Fix mismatched indentation that apparently the .editorconfig file doesn't handle automatically --- components/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index bb22e047c..a8b7f1fd2 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -16,7 +16,7 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} - -DMSVC=${MSVC} + -DMSVC=${MSVC} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From f9a3562ccdec731e560d59e4a9f8844b0ed7584a Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 02:45:50 +0100 Subject: [PATCH 388/521] Remove duplicate macro definition and fix warning --- cmake/GitVersion.cmake | 12 +----------- cmake/OpenMWMacros.cmake | 2 +- components/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 786ac23ed..ff719d72a 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -26,16 +26,6 @@ else () message(WARNING "Failed to get valid version information from Git") endif () -# duplicated from OpenMWMacros.cmake -macro (configure_resource_file source_path destination_dir_base dest_path_relative) - if (MSVC) - configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") - else (MSVC) - configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") - endif (MSVC) -endmacro (configure_resource_file) +include(${MACROSFILE}) configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 08b36017b..aac38a7f6 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -199,4 +199,4 @@ macro (copy_all_resource_files source_dir destination_dir_base destination_dir_r get_filename_component(filename ${f} NAME) copy_resource_file("${source_dir}/${f}" "${destination_dir_base}" "${destination_dir_relative}/${filename}") endforeach (f) -endmacro (copy_all_files) \ No newline at end of file +endmacro (copy_all_resource_files) \ No newline at end of file diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a8b7f1fd2..b8ade0a67 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -17,6 +17,7 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} -DMSVC=${MSVC} + -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From b00b94f0dbefa99d42f861bf691125c4255f62fd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 15:40:37 +0100 Subject: [PATCH 389/521] Use CMAKE_CONFIGURATION_TYPES instead of manually listing the possible configuration types. --- cmake/OpenMWMacros.cmake | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index aac38a7f6..ed1023c5d 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -173,25 +173,15 @@ macro (openmw_add_executable target) endmacro (openmw_add_executable) macro (copy_resource_file source_path destination_dir_base dest_path_relative) - if (MSVC) - configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}" COPYONLY) - configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}" COPYONLY) - configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}" COPYONLY) - configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}" COPYONLY) - else (MSVC) - configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}" COPYONLY) - endif (MSVC) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}" COPYONLY) + endforeach(cfgtype) endmacro (copy_resource_file) macro (configure_resource_file source_path destination_dir_base dest_path_relative) - if (MSVC) - configure_file(${source_path} "${destination_dir_base}/Debug/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/Release/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/RelWithDebInfo/${dest_path_relative}") - configure_file(${source_path} "${destination_dir_base}/MinSizeRel/${dest_path_relative}") - else (MSVC) - configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") - endif (MSVC) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}") + endforeach(cfgtype) endmacro (configure_resource_file) macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) From 1f86fa3c3183255833cb81bcd95f7e7a3e3e4967 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 17:09:01 +0100 Subject: [PATCH 390/521] Fix resource copying on non-MSVC targets --- cmake/OpenMWMacros.cmake | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index ed1023c5d..5e6efaa0f 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -172,16 +172,34 @@ macro (openmw_add_executable target) endif (MSVC) endmacro (openmw_add_executable) +macro (get_generator_is_multi_config VALUE) + if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + set(${VALUE} ${GENERATOR_IS_MULTI_CONFIG}) + else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + list(LENGTH ${CMAKE_CONFIGURATION_TYPES} ${VALUE}) + endif ((CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9)) +endmacro (get_generator_is_multi_config) + macro (copy_resource_file source_path destination_dir_base dest_path_relative) - foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) - configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}" COPYONLY) - endforeach(cfgtype) + get_generator_is_multi_config(multi_config) + if (multi_config) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}" COPYONLY) + endforeach(cfgtype) + else (multi_config) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}" COPYONLY) + endif (multi_config) endmacro (copy_resource_file) macro (configure_resource_file source_path destination_dir_base dest_path_relative) - foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) - configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}") - endforeach(cfgtype) + get_generator_is_multi_config(multi_config) + if (multi_config) + foreach(cfgtype ${CMAKE_CONFIGURATION_TYPES}) + configure_file(${source_path} "${destination_dir_base}/${cfgtype}/${dest_path_relative}") + endforeach(cfgtype) + else (multi_config) + configure_file(${source_path} "${destination_dir_base}/${dest_path_relative}") + endif (multi_config) endmacro (configure_resource_file) macro (copy_all_resource_files source_dir destination_dir_base destination_dir_relative files) From 76c4ff983af0d043845719f5d333c92584d295cf Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 17:17:25 +0100 Subject: [PATCH 391/521] Fix getting cmake property as variable --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 5e6efaa0f..18b410d3e 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -174,10 +174,10 @@ endmacro (openmw_add_executable) macro (get_generator_is_multi_config VALUE) if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - set(${VALUE} ${GENERATOR_IS_MULTI_CONFIG}) + get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) list(LENGTH ${CMAKE_CONFIGURATION_TYPES} ${VALUE}) - endif ((CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9)) + endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) endmacro (get_generator_is_multi_config) macro (copy_resource_file source_path destination_dir_base dest_path_relative) From 6af8ad70a53629c88ce7046cb6dc5e124091b3a0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 17:50:20 +0100 Subject: [PATCH 392/521] Remove superfluous copy_all_files macro --- cmake/OpenMWMacros.cmake | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 18b410d3e..c3ba197e4 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -88,13 +88,6 @@ endforeach (u) source_group ("components\\${dir}" FILES ${files}) endmacro (add_component_qt_dir) -macro (copy_all_files source_dir destination_dir files) -foreach (f ${files}) -get_filename_component(filename ${f} NAME) -configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY) -endforeach (f) -endmacro (copy_all_files) - macro (add_file project type file) list (APPEND ${project}${type} ${file}) endmacro (add_file) From a52c485090998af0f669f717ffe7b470d5ba9f6c Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 18:16:10 +0100 Subject: [PATCH 393/521] Fix list length error --- cmake/OpenMWMacros.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index c3ba197e4..5f66705e7 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -169,7 +169,7 @@ macro (get_generator_is_multi_config VALUE) if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - list(LENGTH ${CMAKE_CONFIGURATION_TYPES} ${VALUE}) + list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) endmacro (get_generator_is_multi_config) From c9e86a8ebc5bed5492ec0df46e1940c4821a28c9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 12 Oct 2017 18:16:44 +0100 Subject: [PATCH 394/521] Remove superfluous argument --- components/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b8ade0a67..e9b992e02 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -16,7 +16,6 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} - -DMSVC=${MSVC} -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) From a25903b075a567b9c6eef47874b42433a5312150 Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 14:39:44 +0200 Subject: [PATCH 395/521] fixed autoequiping rings by npc - now checks if right hand is free --- .gitignore | 1 + apps/openmw/mwworld/inventorystore.cpp | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 9fbb82dba..e9e518c7d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ Makefile makefile build* prebuilt +cmake-build-debug/ ##windows build process /deps diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 77141f269..7c3271cc2 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -315,6 +315,14 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } else if (iter.getType() == ContainerStore::Type_Clothing) { + if (*iter2 == MWWorld::InventoryStore::Slot_LeftRing) + { + if (slots_.at(MWWorld::InventoryStore::Slot_RightRing) == end()) + { + continue; + } + } + if (old.getTypeName() == typeid(ESM::Clothing).name()) { // check value From e6e482ea9890ef8d4b5a2d89d6b00f9d80f99670 Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 14:47:26 +0200 Subject: [PATCH 396/521] added some comments for autoEquip --- apps/openmw/mwworld/inventorystore.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7c3271cc2..c28e6a109 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -266,6 +266,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Autoequip clothing, armor and weapons. // Equipping lights is handled in Actors::updateEquippedLight based on environment light. + // the main loop iterating through all items in inventory for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; @@ -290,9 +291,13 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); + // nested loop for iterating through avialable NPC slots for equipped items + // and checking if current item poited by iter can be placed there for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { + // if true then it means slot is equipped already + // check if slot may require swapping if current item is more valueable if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); @@ -315,8 +320,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } else if (iter.getType() == ContainerStore::Type_Clothing) { + // if left ring is equipped if (*iter2 == MWWorld::InventoryStore::Slot_LeftRing) { + // if there is a place for right ring dont swap left leaving right hand empty if (slots_.at(MWWorld::InventoryStore::Slot_RightRing) == end()) { continue; @@ -345,6 +352,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } } + // if we are here it means item can be equipped or swapped slots_[*iter2] = iter; break; } From ff9cb22a58fc9dbb233b223a15e93b3914ed428e Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 15:16:07 +0200 Subject: [PATCH 397/521] npc swap cheaper ring during auto equip --- apps/openmw/mwworld/inventorystore.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index c28e6a109..40f9c741a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -321,13 +321,23 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) else if (iter.getType() == ContainerStore::Type_Clothing) { // if left ring is equipped - if (*iter2 == MWWorld::InventoryStore::Slot_LeftRing) + if (*iter2 == Slot_LeftRing) { // if there is a place for right ring dont swap left leaving right hand empty - if (slots_.at(MWWorld::InventoryStore::Slot_RightRing) == end()) + if (slots_.at(Slot_RightRing) == end()) { continue; } + else // if right ring is equipped too + { + Ptr rightRing = *slots_.at(Slot_RightRing); + + // we want to swap cheaper ring only if both are equipped + if (rightRing.getClass().getValue(rightRing) < old.getClass().getValue(old)) + { + continue; + } + } } if (old.getTypeName() == typeid(ESM::Clothing).name()) From 548e90a7bc493fe032a1858550a0a648e58976bb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 13 Oct 2017 16:22:44 +0000 Subject: [PATCH 398/521] Set cursor active when moving by controller --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 06ebeb0b8..a5bb93b6c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -430,6 +430,7 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mGuiCursorX), static_cast(mGuiCursorY), mMouseWheel); mInputManager->warpMouse(static_cast(mGuiCursorX/mInvUiScalingFactor), static_cast(mGuiCursorY/mInvUiScalingFactor)); + MWBase::Environment::get().getWindowManager()->setCursorActive(true); } } if (mMouseLookEnabled) From 83a5c7c3d87f4e5740b67f271c6007ad16f73d8f Mon Sep 17 00:00:00 2001 From: glbwsk Date: Fri, 13 Oct 2017 20:32:52 +0200 Subject: [PATCH 399/521] removed unnecessary comments, added gitignore for clion cmake --- .gitignore | 2 +- apps/openmw/mwworld/inventorystore.cpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e9e518c7d..672c3ec18 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ Makefile makefile build* prebuilt -cmake-build-debug/ ##windows build process /deps @@ -27,6 +26,7 @@ Doxygen .settings .directory .idea +cmake-build-* files/windows/*.aps ## qt-creator CMakeLists.txt.user* diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 40f9c741a..50ee97d1c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -265,8 +265,6 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Autoequip clothing, armor and weapons. // Equipping lights is handled in Actors::updateEquippedLight based on environment light. - - // the main loop iterating through all items in inventory for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; @@ -291,8 +289,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); - // nested loop for iterating through avialable NPC slots for equipped items - // and checking if current item poited by iter can be placed there + // checking if current item poited by iter can be equipped for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { @@ -323,7 +320,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // if left ring is equipped if (*iter2 == Slot_LeftRing) { - // if there is a place for right ring dont swap left leaving right hand empty + // if there is a place for right ring dont swap it if (slots_.at(Slot_RightRing) == end()) { continue; From a5b39e0842305372ac4cbb100cb1cb0cd4d955cb Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 13 Oct 2017 19:35:49 +0000 Subject: [PATCH 400/521] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 02eb30da0..839a04e42 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -88,6 +88,7 @@ Programmers lazydev Leon Krieg (lkrieg) Leon Saunders (emoose) + Łukasz Gołębiewski (lukago) logzero lohikaarme Lukasz Gromanowski (lgro) From 30b05b557bc70cf6d20b989507499b96018a01be Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 14 Oct 2017 10:23:59 +0400 Subject: [PATCH 401/521] ExtraSpell magic effect: a basic implementation --- apps/openmw/mwmechanics/spellcasting.cpp | 7 +++++++ components/esm/loadmgef.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a808b8285..a09436d14 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -536,6 +536,13 @@ namespace MWMechanics appliedLastingEffects.push_back(effect); + // Unequip all items, if a spell with the ExtraSpell effect was casted + if (effectIt->mEffectID == ESM::MagicEffect::ExtraSpell && target.getClass().hasInventoryStore(target)) + { + MWWorld::InventoryStore& store = target.getClass().getInventoryStore(target); + store.unequipAll(target); + } + // Command spells should have their effect, including taking the target out of combat, each time the spell successfully affects the target if (((effectIt->mEffectID == ESM::MagicEffect::CommandHumanoid && target.getClass().isNpc()) || (effectIt->mEffectID == ESM::MagicEffect::CommandCreature && target.getTypeName() == typeid(ESM::Creature).name())) diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 3a918cf19..9f8ad94e1 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -380,6 +380,7 @@ static std::map genNameMap() names[131] ="sEffectBoundGloves"; names[128] ="sEffectBoundHelm"; names[125] ="sEffectBoundLongbow"; + names[126] ="sEffectExtraSpell"; names[121] ="sEffectBoundLongsword"; names[122] ="sEffectBoundMace"; names[130] ="sEffectBoundShield"; From 548af6dbfbdd265c94796fa79f6c87cedabc5135 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 14 Oct 2017 14:02:20 +0000 Subject: [PATCH 402/521] Fix jail screen fading --- apps/openmw/mwgui/jailscreen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 11d7466a8..9fa5927ac 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -58,6 +58,7 @@ namespace MWGui { MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.f); // override fade-in caused by cell transition setVisible(true); mTimeAdvancer.run(100); From 6d9d98c02cc663d67372a65c1aaea58b35dacc23 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 11:32:42 -0400 Subject: [PATCH 403/521] Merge Land/LandTextures --- apps/opencs/model/tools/mergeoperation.cpp | 4 +- apps/opencs/model/tools/mergestages.cpp | 147 ++++++--------------- apps/opencs/model/tools/mergestages.hpp | 15 ++- 3 files changed, 47 insertions(+), 119 deletions(-) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index 9b595046a..cbd2abe0d 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -38,9 +38,9 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new MergeRefIdsStage (mState)); appendStage (new MergeReferencesStage (mState)); appendStage (new MergeReferencesStage (mState)); - appendStage (new ListLandTexturesMergeStage (mState)); - appendStage (new MergeLandTexturesStage (mState)); + appendStage (new PopulateLandTexturesMergeStage (mState)); appendStage (new MergeLandStage (mState)); + appendStage (new FixLandsAndLandTexturesMergeStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 176d35914..eea0656b7 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -8,7 +8,9 @@ #include "mergestate.hpp" #include "../doc/document.hpp" +#include "../world/commands.hpp" #include "../world/data.hpp" +#include "../world/idtable.hpp" CSMTools::StartMergeStage::StartMergeStage (MergeState& state) @@ -109,102 +111,32 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa } -CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state) -: mState (state) -{} - -int CSMTools::ListLandTexturesMergeStage::setup() +CSMTools::PopulateLandTexturesMergeStage::PopulateLandTexturesMergeStage (MergeState& state) + : mState (state) { - return mState.mSource.getData().getLand().getSize(); -} - -void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) -{ - const CSMWorld::Record& record = - mState.mSource.getData().getLand().getRecord (stage); - - if (!record.isDeleted()) - { - const CSMWorld::Land& land = record.get(); - - // make sure record is loaded - land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | - ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX); - - if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX)) - { - // list texture indices - std::pair key; - key.second = land.mPlugin; - - for (int i=0; imTextures[i]; - - mState.mTextureIndices[key] = -1; - } - } - } } - -CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state) -: mState (state), mNext (mState.mTextureIndices.end()) -{} - -int CSMTools::MergeLandTexturesStage::setup() +int CSMTools::PopulateLandTexturesMergeStage::setup() { - // Should use the size of mState.mTextureIndices instead, but that is not available at this - // point. Unless there are any errors in the land and land texture records this will not - // make a difference. return mState.mSource.getData().getLandTextures().getSize(); } -void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages) +void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) { - if (stage==0) - mNext = mState.mTextureIndices.begin(); + const CSMWorld::Record& record = + mState.mSource.getData().getLandTextures().getRecord (stage); - bool found = false; - - do + if (!record.isDeleted()) { - if (mNext==mState.mTextureIndices.end()) - return; - - mNext->second = stage+1; - - std::ostringstream stream; - stream << mNext->first.first-1 << "_" << mNext->first.second; - - int index = mState.mSource.getData().getLandTextures().searchId (stream.str()); - - if (index!=-1) - { - CSMWorld::LandTexture texture = - mState.mSource.getData().getLandTextures().getRecord (index).get(); - - stream.clear(); - stream << mNext->second-1 << "_0"; - - texture.mIndex = mNext->second-1; - texture.mId = stream.str(); - - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture); - - mState.mTarget->getData().getLandTextures().appendRecord (newRecord); - - found = true; - } - - ++mNext; + mState.mTarget->getData().getLandTextures().appendRecord(record); } - while (!found); } -CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {} +CSMTools::MergeLandStage::MergeLandStage (MergeState& state) + : mState (state) +{ +} int CSMTools::MergeLandStage::setup() { @@ -218,40 +150,35 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages) if (!record.isDeleted()) { - const CSMWorld::Land& land = record.get(); - - land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | - ESM::Land::DATA_VTEX); + mState.mTarget->getData().getLand().appendRecord (record); + } +} - CSMWorld::Land newLand (land); - newLand.mPlugin = 0; +CSMTools::FixLandsAndLandTexturesMergeStage::FixLandsAndLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} - if (land.mDataTypes & ESM::Land::DATA_VTEX) - { - // adjust land texture references - if (ESM::Land::LandData *data = newLand.getLandData()) - { - std::pair key; - key.second = land.mPlugin; +int CSMTools::FixLandsAndLandTexturesMergeStage::setup() +{ + // We will have no more than the source + return mState.mSource.getData().getLand().getSize(); +} - for (int i=0; imTextures[i]; - std::map, int>::const_iterator iter = - mState.mTextureIndices.find (key); +void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + if (stage < mState.mTarget->getData().getLand().getSize()) + { + CSMWorld::IdTable& landTable = dynamic_cast( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_Lands)); - if (iter!=mState.mTextureIndices.end()) - data->mTextures[i] = iter->second; - else - data->mTextures[i] = 0; - } - } - } + CSMWorld::IdTable& ltexTable = dynamic_cast( + *mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures)); - CSMWorld::Record newRecord ( - CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand); + std::string id = mState.mTarget->getData().getLand().getId(stage); - mState.mTarget->getData().getLand().appendRecord (newRecord); + CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id); + cmd.redo(); } } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index f88f5be9f..96339ed4c 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -116,13 +116,14 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class ListLandTexturesMergeStage : public CSMDoc::Stage + /// Adds all land texture records that could potentially be referenced when merging + class PopulateLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; public: - ListLandTexturesMergeStage (MergeState& state); + PopulateLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -131,14 +132,13 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class MergeLandTexturesStage : public CSMDoc::Stage + class MergeLandStage : public CSMDoc::Stage { MergeState& mState; - std::map, int>::iterator mNext; public: - MergeLandTexturesStage (MergeState& state); + MergeLandStage (MergeState& state); virtual int setup(); ///< \return number of steps @@ -147,13 +147,14 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - class MergeLandStage : public CSMDoc::Stage + /// Flattens the added land and land texture records. + class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; public: - MergeLandStage (MergeState& state); + FixLandsAndLandTexturesMergeStage (MergeState& state); virtual int setup(); ///< \return number of steps From 98c38ad7d1201fe951d8c94ffcff4175f7c90875 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 13:18:31 -0400 Subject: [PATCH 404/521] Merge cleanup. --- apps/opencs/model/tools/mergeoperation.cpp | 1 + apps/opencs/model/tools/mergestages.cpp | 31 ++++++++++++++++++++++ apps/opencs/model/tools/mergestages.hpp | 16 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/apps/opencs/model/tools/mergeoperation.cpp b/apps/opencs/model/tools/mergeoperation.cpp index cbd2abe0d..b15b4b83f 100644 --- a/apps/opencs/model/tools/mergeoperation.cpp +++ b/apps/opencs/model/tools/mergeoperation.cpp @@ -41,6 +41,7 @@ CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::Fr appendStage (new PopulateLandTexturesMergeStage (mState)); appendStage (new MergeLandStage (mState)); appendStage (new FixLandsAndLandTexturesMergeStage (mState)); + appendStage (new CleanupLandTexturesMergeStage (mState)); appendStage (new FinishMergedDocumentStage (mState, encoding)); } diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index eea0656b7..897c3329c 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -180,5 +180,36 @@ void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Me CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id); cmd.redo(); + + // Get rid of base data + const CSMWorld::Record& oldRecord = + mState.mTarget->getData().getLand().getRecord (stage); + + CSMWorld::Record newRecord(CSMWorld::RecordBase::State_ModifiedOnly, + nullptr, &oldRecord.get()); + + mState.mTarget->getData().getLand().setRecord(stage, newRecord); + } +} + +CSMTools::CleanupLandTexturesMergeStage::CleanupLandTexturesMergeStage (MergeState& state) + : mState (state) +{ +} + +int CSMTools::CleanupLandTexturesMergeStage::setup() +{ + return 1; +} + +void CSMTools::CleanupLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages) +{ + auto& landTextures = mState.mTarget->getData().getLandTextures(); + for (int i = 0; i < landTextures.getSize(); ) + { + if (!landTextures.getRecord(i).isModified()) + landTextures.removeRows(i, 1); + else + ++i; } } diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 96339ed4c..9a16e03ab 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -162,6 +162,22 @@ namespace CSMTools virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this stage will be appended to \a messages. }; + + // Removes base LandTexture records. + class CleanupLandTexturesMergeStage : public CSMDoc::Stage + { + MergeState& mState; + + public: + + CleanupLandTexturesMergeStage (MergeState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, CSMDoc::Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; } #endif From d27071f06a1276e1b5450bb8a02a565516b8b575 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 13:18:54 -0400 Subject: [PATCH 405/521] Fix LTEX import bug. --- apps/opencs/model/world/idtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index fcfc8577e..3e503a80c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -336,7 +336,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import int oldRow = idCollection()->searchId(id); // If it does not exist or it is in the current plugin, it can be skipped. - if (oldRow <= 0 || plugin == 0) + if (oldRow < 0 || plugin == 0) { results.recordMapping.push_back(std::make_pair(id, id)); continue; From 5fbdb64bb913717a81ccbf919dea2789b227df74 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sat, 14 Oct 2017 18:28:46 +0000 Subject: [PATCH 406/521] Add OPENMW_DECOMPRESS_TEXTURES environment variable to decompress textures in software if not supported by graphics hardware Disabled by default due to requiring new functionality that was just added to OSG 3.6 or OpenMW/OSG. --- components/resource/imagemanager.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 441fd8212..000a833cf 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -69,7 +69,6 @@ namespace Resource // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. && !osg::isGLExtensionSupported(0, "GL_S3_s3tc")) { - std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; return false; } break; @@ -123,12 +122,31 @@ namespace Resource return mWarningImage; } - osg::Image* image = result.getImage(); + osg::ref_ptr image = result.getImage(); + image->setFileName(normalized); if (!checkSupported(image, filename)) { - mCache->addEntryToObjectCache(normalized, mWarningImage); - return mWarningImage; + static bool uncompress = (getenv("OPENMW_DECOMPRESS_TEXTURES") != 0); + if (!uncompress) + { + std::cerr << "Error loading " << filename << ": no S3TC texture compression support installed" << std::endl; + mCache->addEntryToObjectCache(normalized, mWarningImage); + return mWarningImage; + } + else + { + // decompress texture in software if not supported by GPU + // requires update to getColor() to be released with OSG 3.6 + osg::ref_ptr newImage = new osg::Image; + newImage->setFileName(image->getFileName()); + newImage->allocateImage(image->s(), image->t(), image->r(), image->isImageTranslucent() ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE); + for (int s=0; ss(); ++s) + for (int t=0; tt(); ++t) + for (int r=0; rr(); ++r) + newImage->setColor(image->getColor(s,t,r), s,t,r); + image = newImage; + } } mCache->addEntryToObjectCache(normalized, image); From 11eae166458440c99908e8a38c4b512a3e361062 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Sat, 14 Oct 2017 15:09:12 -0400 Subject: [PATCH 407/521] Get rid of duplicate function, fix flag checking --- apps/opencs/model/world/columnimp.cpp | 10 +++++----- components/esm/loadland.cpp | 11 +---------- components/esm/loadland.hpp | 1 - 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/world/columnimp.cpp b/apps/opencs/model/world/columnimp.cpp index 18da81b53..49e4bebe6 100644 --- a/apps/opencs/model/world/columnimp.cpp +++ b/apps/opencs/model/world/columnimp.cpp @@ -108,7 +108,7 @@ namespace CSMWorld throw std::runtime_error("invalid land map LOD data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_WNAM); + copy.add(Land::DATA_WNAM); for (int i = 0; i < values.size(); ++i) { @@ -155,7 +155,7 @@ namespace CSMWorld throw std::runtime_error("invalid land normals data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VNML); + copy.add(Land::DATA_VNML); for (int i = 0; i < values.size(); ++i) { @@ -202,7 +202,7 @@ namespace CSMWorld throw std::runtime_error("invalid land heights data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VHGT); + copy.add(Land::DATA_VHGT); for (int i = 0; i < values.size(); ++i) { @@ -249,7 +249,7 @@ namespace CSMWorld throw std::runtime_error("invalid land colours data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VCLR); + copy.add(Land::DATA_VCLR); for (int i = 0; i < values.size(); ++i) { @@ -296,7 +296,7 @@ namespace CSMWorld throw std::runtime_error("invalid land textures data"); Land copy = record.get(); - copy.setDataLoaded(Land::DATA_VTEX); + copy.add(Land::DATA_VTEX); for (int i = 0; i < values.size(); ++i) { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index f3f72e88a..a91dfe3d3 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -315,16 +315,7 @@ namespace ESM bool Land::isDataLoaded(int flags) const { - return mLandData && (mLandData->mDataLoaded & flags) == (flags & mDataTypes); - } - - void Land::setDataLoaded(int flags) - { - if (!mLandData) - mLandData = new LandData; - - mDataTypes |= flags; - mLandData->mDataLoaded |= flags; + return mLandData && (mLandData->mDataLoaded & flags) == flags; } Land::Land (const Land& land) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 7be954b3e..2163c30fc 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -132,7 +132,6 @@ struct Land void unloadData() const; /// Check if given data type is loaded - /// @note We only check data types that *can* be loaded (present in mDataTypes) bool isDataLoaded(int flags) const; /// Sets the flags and creates a LandData if needed From b95c9ba483c54362bc94d935704978c5b6f88ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 4 Oct 2017 16:41:55 +0200 Subject: [PATCH 408/521] rain independent from camera plus wrap-around --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 55 +++++++++++++++++++++-- apps/openmw/mwrender/sky.hpp | 5 ++- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3826fd5f6..37abb1ec3 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -255,7 +255,7 @@ namespace MWRender mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); - mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager(), this)); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 178c753c6..0603c18a1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -46,6 +47,8 @@ #include "vismask.hpp" #include "renderbin.hpp" +#define PARTICLE_WIDTH 600.0 + namespace { @@ -1091,8 +1094,9 @@ private: } }; -SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager) : mSceneManager(sceneManager) + , mRendering(renderingManager) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1337,6 +1341,43 @@ protected: osg::Uniform* mRainIntensityUniform; }; +class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback +{ +public: + WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager) : osg::Drawable::DrawCallback() + { + mRendering = renderingManager; + } + + virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const + { + osg::Vec3 cameraPos = mRendering->getCameraPosition(); + osg::Vec3 cameraOffset = osg::Vec3( + PARTICLE_WIDTH - fmod(cameraPos.x(), PARTICLE_WIDTH / 2), + PARTICLE_WIDTH - fmod(cameraPos.y(), PARTICLE_WIDTH / 2), + 0); + + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + + for (int xOff = 0; xOff < 3; xOff++) + for (int yOff = 0; yOff < 3; yOff++) + { + osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * PARTICLE_WIDTH, -1 * yOff * PARTICLE_WIDTH,0); + + for(int i = 0; i < ps->numParticles(); i++) + ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); + + ps->drawImplementation(renderInfo); + + for(int i = 0; i < ps->numParticles(); i++) + ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() - offset); + } + } + +protected: + MWRender::RenderingManager *mRendering; +}; + void SkyManager::createRain() { if (mRainNode) @@ -1345,6 +1386,8 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); @@ -1370,8 +1413,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-300, 300); // Rain_Diameter - placer->setYRange(-300, 300); + placer->setXRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); // Rain_Diameter + placer->setYRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1559,6 +1602,12 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); + + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) + (mParticleEffect->asGroup()->getChild(1)->asGroup()->getChild(0) + ->asGroup()->getChild(2)); + + ps->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 59a8ddc4e..37c999563 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,6 +9,8 @@ #include #include +#include + namespace osg { class Group; @@ -108,7 +110,7 @@ namespace MWRender class SkyManager { public: - SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager); ~SkyManager(); void update(float duration); @@ -170,6 +172,7 @@ namespace MWRender void updateRainParameters(); Resource::SceneManager* mSceneManager; + MWRender::RenderingManager *mRendering; osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; From 33a1459b11b3efca1ed566f8d58f3f3c16871648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 4 Oct 2017 22:29:59 +0200 Subject: [PATCH 409/521] search for particle system by class name --- apps/openmw/mwrender/sky.cpp | 49 ++++++++++++++++++++++---------- apps/openmw/mwrender/sky.hpp | 2 +- components/nifosg/particle.cpp | 5 ++++ components/nifosg/particle.hpp | 1 + components/sceneutil/visitor.cpp | 8 ++++++ components/sceneutil/visitor.hpp | 17 ++++++++++- 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0603c18a1..cce2e1b1d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -47,7 +47,7 @@ #include "vismask.hpp" #include "renderbin.hpp" -#define PARTICLE_WIDTH 600.0 +#define RAIN_WIDTH 600.0 namespace { @@ -1344,17 +1344,19 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager, float rangeX, float rangeY) : osg::Drawable::DrawCallback() { mRendering = renderingManager; + mRangeX = rangeX; + mRangeY = rangeY; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { osg::Vec3 cameraPos = mRendering->getCameraPosition(); osg::Vec3 cameraOffset = osg::Vec3( - PARTICLE_WIDTH - fmod(cameraPos.x(), PARTICLE_WIDTH / 2), - PARTICLE_WIDTH - fmod(cameraPos.y(), PARTICLE_WIDTH / 2), + mRangeX - fmod(cameraPos.x(), mRangeX / 2), + mRangeY - fmod(cameraPos.y(), mRangeY / 2), 0); osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; @@ -1362,7 +1364,7 @@ public: for (int xOff = 0; xOff < 3; xOff++) for (int yOff = 0; yOff < 3; yOff++) { - osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * PARTICLE_WIDTH, -1 * yOff * PARTICLE_WIDTH,0); + osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * mRangeX, -1 * yOff * mRangeY,0); for(int i = 0; i < ps->numParticles(); i++) ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); @@ -1376,6 +1378,7 @@ public: protected: MWRender::RenderingManager *mRendering; + float mRangeX, mRangeY; }; void SkyManager::createRain() @@ -1386,7 +1389,7 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering,RAIN_WIDTH,RAIN_WIDTH)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1413,8 +1416,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); // Rain_Diameter - placer->setYRange(-PARTICLE_WIDTH / 2, PARTICLE_WIDTH / 2); + placer->setXRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); // Rain_Diameter + placer->setYRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1493,8 +1496,6 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); - if (mParticleNode) - mParticleNode->setAttitude(quat); mCloudNode->setAttitude(quat); } else @@ -1586,7 +1587,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { if (!mParticleNode) { - mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode = new osg::Group; mParticleNode->addCullCallback(mUnderwaterSwitch); mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); @@ -1603,11 +1604,29 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) - (mParticleEffect->asGroup()->getChild(1)->asGroup()->getChild(0) - ->asGroup()->getChild(2)); + SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); + mParticleEffect->accept(findEmitterVisitor); - ps->setDrawCallback(new WeatherParticleDrawCallback(mRendering)); + float rangeX = RAIN_WIDTH; + float rangeY = RAIN_WIDTH; + + if (findEmitterVisitor.mFoundNode) + { + osgParticle::Placer *placer = ((NifOsg::Emitter *) findEmitterVisitor.mFoundNode)->getPlacer(); + + if (placer && strcmp(placer->className(),"BoxPlacer") == 0) + { + rangeX = ((osgParticle::BoxPlacer *) placer)->getXRange().maximum; + rangeY = ((osgParticle::BoxPlacer *) placer)->getYRange().maximum; + } + } + + + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); + + if (findPSVisitor.mFoundNode) + ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(mRendering,rangeX,rangeY)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 37c999563..fdcd27e5a 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -177,7 +177,7 @@ namespace MWRender osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; - osg::ref_ptr mParticleNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; osg::ref_ptr mUnderwaterSwitch; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 62360b9d6..547b71034 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -250,6 +250,11 @@ void Emitter::setPlacer(osgParticle::Placer *placer) mPlacer = placer; } +osgParticle::Placer *Emitter::getPlacer() +{ + return mPlacer; +} + void Emitter::setCounter(osgParticle::Counter *counter) { mCounter = counter; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 7a2377f9d..df93d5ced 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -225,6 +225,7 @@ namespace NifOsg void setShooter(osgParticle::Shooter* shooter); void setPlacer(osgParticle::Placer* placer); + osgParticle::Placer *getPlacer(); void setCounter(osgParticle::Counter* counter); private: diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 74b9be63d..202e6373e 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -19,6 +19,14 @@ namespace SceneUtil return false; } + void FindByClassVisitor::apply(osg::Node &node) + { + if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) + mFoundNode = &node; + else + traverse(node); + } + void FindByNameVisitor::apply(osg::Group &group) { if (!checkGroup(group)) diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 209f2d9bd..973f44646 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -20,7 +20,6 @@ namespace SceneUtil } virtual void apply(osg::Group& group); - virtual void apply(osg::MatrixTransform& node); virtual void apply(osg::Geometry& node); @@ -30,6 +29,22 @@ namespace SceneUtil osg::Group* mFoundNode; }; + class FindByClassVisitor : public osg::NodeVisitor + { + public: + FindByClassVisitor(const std::string& nameToFind) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mNameToFind(nameToFind) + , mFoundNode(NULL) + { + } + + virtual void apply(osg::Node &node); + + std::string mNameToFind; + osg::Node* mFoundNode; + }; + // Disable freezeOnCull for all visited particlesystems class DisableFreezeOnCullVisitor : public osg::NodeVisitor { From 8114126a62ecd4904f3c92fd0d5667d874700a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 5 Oct 2017 12:58:56 +0200 Subject: [PATCH 410/521] make use of renderinfo --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 63 ++++++++++++++--------- apps/openmw/mwrender/sky.hpp | 7 +-- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 37abb1ec3..3826fd5f6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -255,7 +255,7 @@ namespace MWRender mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); - mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager(), this)); + mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cce2e1b1d..81494d8e2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1094,9 +1094,8 @@ private: } }; -SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager) +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) - , mRendering(renderingManager) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1344,40 +1343,50 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(MWRender::RenderingManager *renderingManager, float rangeX, float rangeY) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(float rangeX, float rangeY) : osg::Drawable::DrawCallback() { - mRendering = renderingManager; mRangeX = rangeX; mRangeY = rangeY; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { - osg::Vec3 cameraPos = mRendering->getCameraPosition(); + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); + osg::Vec3 cameraOffset = osg::Vec3( - mRangeX - fmod(cameraPos.x(), mRangeX / 2), - mRangeY - fmod(cameraPos.y(), mRangeY / 2), - 0); + fmod(cameraPos.x(), mRangeX), + fmod(cameraPos.y(), mRangeY), + 0.0); - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + std::vector positionBackups; - for (int xOff = 0; xOff < 3; xOff++) - for (int yOff = 0; yOff < 3; yOff++) - { - osg::Vec3 offset = cameraOffset + osg::Vec3(-1 * xOff * mRangeX, -1 * yOff * mRangeY,0); + for (int i = 0; i < ps->numParticles(); i++) + { + osgParticle::Particle *particle = ps->getParticle(i); - for(int i = 0; i < ps->numParticles(); i++) - ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() + offset); + positionBackups.push_back(particle->getPosition()); - ps->drawImplementation(renderInfo); + particle->setPosition(particle->getPosition() - cameraOffset); - for(int i = 0; i < ps->numParticles(); i++) - ps->getParticle(i)->setPosition(ps->getParticle(i)->getPosition() - offset); - } + if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect + particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); + else if (particle->getPosition().x() < -mRangeX / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + + if (particle->getPosition().y() > mRangeY / 2.0) + particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); + else if (particle->getPosition().y() < -mRangeY / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); + } + + ps->drawImplementation(renderInfo); + + for (int i = 0; i < ps->numParticles(); i++) // restore positions + ps->getParticle(i)->setPosition(positionBackups[i]); } protected: - MWRender::RenderingManager *mRendering; float mRangeX, mRangeY; }; @@ -1389,11 +1398,12 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(mRendering,RAIN_WIDTH,RAIN_WIDTH)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(RAIN_WIDTH,RAIN_WIDTH)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); + mRainParticleSystem->setCullingActive(false); osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); @@ -1422,7 +1432,8 @@ void SkyManager::createRain() emitter->setPlacer(placer); osg::ref_ptr counter (new osgParticle::ConstantRateCounter); - counter->setNumberOfParticlesPerSecondToCreate(600.0); +// counter->setNumberOfParticlesPerSecondToCreate(600.0); + counter->setNumberOfParticlesPerSecondToCreate(2000); emitter->setCounter(counter); osg::ref_ptr shooter (new RainShooter); @@ -1496,6 +1507,9 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); + if (mParticleNode) + mParticleNode->setAttitude(quat); + mCloudNode->setAttitude(quat); } else @@ -1587,7 +1601,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { if (!mParticleNode) { - mParticleNode = new osg::Group; + mParticleNode = new osg::PositionAttitudeTransform; mParticleNode->addCullCallback(mUnderwaterSwitch); mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); @@ -1621,12 +1635,11 @@ void SkyManager::setWeather(const WeatherResult& weather) } } - SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); mParticleEffect->accept(findPSVisitor); if (findPSVisitor.mFoundNode) - ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(mRendering,rangeX,rangeY)); + ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(rangeX,rangeY)); } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index fdcd27e5a..59a8ddc4e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,8 +9,6 @@ #include #include -#include - namespace osg { class Group; @@ -110,7 +108,7 @@ namespace MWRender class SkyManager { public: - SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager, MWRender::RenderingManager *renderingManager); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); ~SkyManager(); void update(float duration); @@ -172,12 +170,11 @@ namespace MWRender void updateRainParameters(); Resource::SceneManager* mSceneManager; - MWRender::RenderingManager *mRendering; osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; - osg::ref_ptr mParticleNode; + osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; osg::ref_ptr mUnderwaterSwitch; From 38bfa64100414a4ab76c71805a569185c6cd8485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 8 Oct 2017 20:56:36 +0200 Subject: [PATCH 411/521] transform weather particles to world space --- apps/openmw/mwrender/sky.cpp | 50 +++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 81494d8e2..de1fb780c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1361,24 +1361,38 @@ public: std::vector positionBackups; - for (int i = 0; i < ps->numParticles(); i++) - { - osgParticle::Particle *particle = ps->getParticle(i); + osg::Matrix toWorld, toLocal; - positionBackups.push_back(particle->getPosition()); + toWorld.makeIdentity(); + toLocal.makeIdentity(); - particle->setPosition(particle->getPosition() - cameraOffset); + std::vector worldMatrices = drawable->getWorldMatrices(); - if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect - particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); - else if (particle->getPosition().x() < -mRangeX / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + if (!worldMatrices.empty()) + { + toWorld = worldMatrices[0]; + toLocal.invert(toWorld); + } - if (particle->getPosition().y() > mRangeY / 2.0) - particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); - else if (particle->getPosition().y() < -mRangeY / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); - } + for (int i = 0; i < ps->numParticles(); i++) + { + osgParticle::Particle *particle = ps->getParticle(i); + positionBackups.push_back(particle->getPosition()); + particle->setPosition(toWorld.preMult(particle->getPosition())); + particle->setPosition(particle->getPosition() - cameraOffset); + + if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect + particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); + else if (particle->getPosition().x() < -mRangeX / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + + if (particle->getPosition().y() > mRangeY / 2.0) + particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); + else if (particle->getPosition().y() < -mRangeY / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); + + particle->setPosition(toLocal.preMult(particle->getPosition())); + } ps->drawImplementation(renderInfo); @@ -1388,6 +1402,7 @@ public: protected: float mRangeX, mRangeY; + }; void SkyManager::createRain() @@ -1432,8 +1447,7 @@ void SkyManager::createRain() emitter->setPlacer(placer); osg::ref_ptr counter (new osgParticle::ConstantRateCounter); -// counter->setNumberOfParticlesPerSecondToCreate(600.0); - counter->setNumberOfParticlesPerSecondToCreate(2000); + counter->setNumberOfParticlesPerSecondToCreate(600.0); emitter->setCounter(counter); osg::ref_ptr shooter (new RainShooter); @@ -1507,8 +1521,8 @@ void SkyManager::update(float duration) osg::Quat quat; quat.makeRotate(osg::Vec3f(0,1,0), mStormDirection); - if (mParticleNode) - mParticleNode->setAttitude(quat); + if (mParticleNode) + mParticleNode->setAttitude(quat); mCloudNode->setAttitude(quat); } From 380a5799dd0afdefe92af185ca63209685068d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 12 Oct 2017 12:56:03 +0200 Subject: [PATCH 412/521] use bbox as wrap range & apply to all particle systems --- apps/openmw/mwrender/sky.cpp | 55 +++++++++++++------------------- components/sceneutil/visitor.cpp | 6 ++-- components/sceneutil/visitor.hpp | 3 +- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index de1fb780c..fb3e477bb 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -48,6 +48,7 @@ #include "renderbin.hpp" #define RAIN_WIDTH 600.0 +#define RAIN_HEIGHT 600.0 namespace { @@ -1343,10 +1344,9 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(float rangeX, float rangeY) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(osg::Vec3 wrapRange) : osg::Drawable::DrawCallback() { - mRangeX = rangeX; - mRangeY = rangeY; + mWrapRange = wrapRange; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const @@ -1355,8 +1355,8 @@ public: osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); osg::Vec3 cameraOffset = osg::Vec3( - fmod(cameraPos.x(), mRangeX), - fmod(cameraPos.y(), mRangeY), + fmod(cameraPos.x(), mWrapRange.x()), + fmod(cameraPos.y(), mWrapRange.y()), 0.0); std::vector positionBackups; @@ -1381,15 +1381,15 @@ public: particle->setPosition(toWorld.preMult(particle->getPosition())); particle->setPosition(particle->getPosition() - cameraOffset); - if (particle->getPosition().x() > mRangeX / 2.0) // wrap-around effect - particle->setPosition(particle->getPosition() - osg::Vec3(mRangeX,0,0)); - else if (particle->getPosition().x() < -mRangeX / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(mRangeX,0,0)); + if (particle->getPosition().x() > mWrapRange.x() / 2.0) // wrap-around effect + particle->setPosition(particle->getPosition() - osg::Vec3(mWrapRange.x(),0,0)); + else if (particle->getPosition().x() < -mWrapRange.x() / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(mWrapRange.x(),0,0)); - if (particle->getPosition().y() > mRangeY / 2.0) - particle->setPosition(particle->getPosition() - osg::Vec3(0,mRangeY,0)); - else if (particle->getPosition().y() < -mRangeY / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(0,mRangeY,0)); + if (particle->getPosition().y() > mWrapRange.y() / 2.0) + particle->setPosition(particle->getPosition() - osg::Vec3(0,mWrapRange.y(),0)); + else if (particle->getPosition().y() < -mWrapRange.y() / 2.0) + particle->setPosition(particle->getPosition() + osg::Vec3(0,mWrapRange.y(),0)); particle->setPosition(toLocal.preMult(particle->getPosition())); } @@ -1401,8 +1401,7 @@ public: } protected: - float mRangeX, mRangeY; - + osg::Vec3 mWrapRange; }; void SkyManager::createRain() @@ -1413,7 +1412,7 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(RAIN_WIDTH,RAIN_WIDTH)); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(osg::Vec3(RAIN_WIDTH,RAIN_WIDTH,RAIN_HEIGHT))); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1635,25 +1634,17 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); mParticleEffect->accept(findEmitterVisitor); - float rangeX = RAIN_WIDTH; - float rangeY = RAIN_WIDTH; + for (unsigned int i = 0; i < findEmitterVisitor.mFoundNodes.size(); i++) + { + NifOsg::Emitter *emitter = (NifOsg::Emitter *) findEmitterVisitor.mFoundNodes[i]; + NifOsg::ParticleSystem *ps = (NifOsg::ParticleSystem *) emitter->getParticleSystem(); - if (findEmitterVisitor.mFoundNode) - { - osgParticle::Placer *placer = ((NifOsg::Emitter *) findEmitterVisitor.mFoundNode)->getPlacer(); + osg::BoundingBox box = ps->getBoundingBox(); - if (placer && strcmp(placer->className(),"BoxPlacer") == 0) - { - rangeX = ((osgParticle::BoxPlacer *) placer)->getXRange().maximum; - rangeY = ((osgParticle::BoxPlacer *) placer)->getYRange().maximum; - } - } + osg::Vec3 wrapRange = osg::Vec3(box.xMax() - box.xMin(),box.yMax() - box.yMin(),box.zMax() - box.zMin()); - SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); - mParticleEffect->accept(findPSVisitor); - - if (findPSVisitor.mFoundNode) - ((osgParticle::ParticleSystem *) findPSVisitor.mFoundNode)->setDrawCallback(new WeatherParticleDrawCallback(rangeX,rangeY)); + ps->setDrawCallback(new WeatherParticleDrawCallback(wrapRange)); + } } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index 202e6373e..2f6123e34 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -22,9 +22,9 @@ namespace SceneUtil void FindByClassVisitor::apply(osg::Node &node) { if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) - mFoundNode = &node; - else - traverse(node); + mFoundNodes.push_back(&node); + + traverse(node); } void FindByNameVisitor::apply(osg::Group &group) diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index 973f44646..265fd6d02 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -35,14 +35,13 @@ namespace SceneUtil FindByClassVisitor(const std::string& nameToFind) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mNameToFind(nameToFind) - , mFoundNode(NULL) { } virtual void apply(osg::Node &node); std::string mNameToFind; - osg::Node* mFoundNode; + std::vector mFoundNodes; }; // Disable freezeOnCull for all visited particlesystems From 65977b910e017bbe4007fc1c71d47201c3bb02f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 12 Oct 2017 15:28:54 +0200 Subject: [PATCH 413/521] wrap weather around in all directions --- apps/openmw/mwrender/sky.cpp | 92 +++++++++++++++++----------------- components/nifosg/particle.cpp | 5 -- components/nifosg/particle.hpp | 1 - 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index fb3e477bb..eaa93ab88 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -39,7 +41,6 @@ #include #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -47,12 +48,8 @@ #include "vismask.hpp" #include "renderbin.hpp" -#define RAIN_WIDTH 600.0 -#define RAIN_HEIGHT 600.0 - namespace { - osg::ref_ptr createAlphaTrackingUnlitMaterial() { osg::ref_ptr mat = new osg::Material; @@ -1344,60 +1341,69 @@ protected: class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback { public: - WeatherParticleDrawCallback(osg::Vec3 wrapRange) : osg::Drawable::DrawCallback() + WeatherParticleDrawCallback(osg::Vec3 &wrapRange) : osg::Drawable::DrawCallback() { mWrapRange = wrapRange; } virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const { + osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; + + osgParticle::ParticleSystem::ScopedReadLock *lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); + osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); osg::Vec3 cameraOffset = osg::Vec3( fmod(cameraPos.x(), mWrapRange.x()), fmod(cameraPos.y(), mWrapRange.y()), - 0.0); + fmod(cameraPos.z(), mWrapRange.z())); std::vector positionBackups; osg::Matrix toWorld, toLocal; - toWorld.makeIdentity(); - toLocal.makeIdentity(); - std::vector worldMatrices = drawable->getWorldMatrices(); if (!worldMatrices.empty()) - { - toWorld = worldMatrices[0]; - toLocal.invert(toWorld); - } + { + toWorld = worldMatrices[0]; + toLocal.invert(toWorld); + } for (int i = 0; i < ps->numParticles(); i++) - { - osgParticle::Particle *particle = ps->getParticle(i); - positionBackups.push_back(particle->getPosition()); - particle->setPosition(toWorld.preMult(particle->getPosition())); - particle->setPosition(particle->getPosition() - cameraOffset); - - if (particle->getPosition().x() > mWrapRange.x() / 2.0) // wrap-around effect - particle->setPosition(particle->getPosition() - osg::Vec3(mWrapRange.x(),0,0)); - else if (particle->getPosition().x() < -mWrapRange.x() / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(mWrapRange.x(),0,0)); - - if (particle->getPosition().y() > mWrapRange.y() / 2.0) - particle->setPosition(particle->getPosition() - osg::Vec3(0,mWrapRange.y(),0)); - else if (particle->getPosition().y() < -mWrapRange.y() / 2.0) - particle->setPosition(particle->getPosition() + osg::Vec3(0,mWrapRange.y(),0)); - - particle->setPosition(toLocal.preMult(particle->getPosition())); + { + osgParticle::Particle *particle = ps->getParticle(i); + positionBackups.push_back(particle->getPosition()); + particle->setPosition(toWorld.preMult(particle->getPosition())); + particle->setPosition(particle->getPosition() - cameraOffset); + + for (int j = 0; j < 3; j++) // wrap-around effect in all 3 directions + { + osg::Vec3 newPosition = particle->getPosition(); + + if (particle->getPosition()[j] > mWrapRange[j] / 2.0) + newPosition[j] -= mWrapRange[j]; + else if (particle->getPosition()[j] < -mWrapRange[j] / 2.0) + newPosition[j] += mWrapRange[j]; + + particle->setPosition(newPosition); } + particle->setPosition(toLocal.preMult(particle->getPosition())); + } + + delete lock; // unlock the mutex as ps will try to lock it in the following command + ps->drawImplementation(renderInfo); + lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); + for (int i = 0; i < ps->numParticles(); i++) // restore positions ps->getParticle(i)->setPosition(positionBackups[i]); + + delete lock; } protected: @@ -1412,7 +1418,8 @@ void SkyManager::createRain() mRainNode = new osg::Group; mRainParticleSystem = new osgParticle::ParticleSystem; - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(osg::Vec3(RAIN_WIDTH,RAIN_WIDTH,RAIN_HEIGHT))); + osg::Vec3 rainRange = osg::Vec3(600,600,600); + mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(rainRange)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); @@ -1440,8 +1447,8 @@ void SkyManager::createRain() emitter->setParticleSystem(mRainParticleSystem); osg::ref_ptr placer (new osgParticle::BoxPlacer); - placer->setXRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); // Rain_Diameter - placer->setYRange(-RAIN_WIDTH / 2, RAIN_WIDTH / 2); + placer->setXRange(-rainRange.x() / 2, rainRange.x() / 2); // Rain_Diameter + placer->setYRange(-rainRange.y() / 2, rainRange.y() / 2); placer->setZRange(300, 300); emitter->setPlacer(placer); @@ -1631,19 +1638,14 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - SceneUtil::FindByClassVisitor findEmitterVisitor(std::string("Emitter")); - mParticleEffect->accept(findEmitterVisitor); + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); - for (unsigned int i = 0; i < findEmitterVisitor.mFoundNodes.size(); i++) + for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); i++) { - NifOsg::Emitter *emitter = (NifOsg::Emitter *) findEmitterVisitor.mFoundNodes[i]; - NifOsg::ParticleSystem *ps = (NifOsg::ParticleSystem *) emitter->getParticleSystem(); - - osg::BoundingBox box = ps->getBoundingBox(); - - osg::Vec3 wrapRange = osg::Vec3(box.xMax() - box.xMin(),box.yMax() - box.yMin(),box.zMax() - box.zMin()); - - ps->setDrawCallback(new WeatherParticleDrawCallback(wrapRange)); + osgParticle::ParticleSystem *ps = static_cast(findPSVisitor.mFoundNodes[i]); + osg::Vec3 weatherRange = osg::Vec3(1024,1024,800); + ps->setDrawCallback(new WeatherParticleDrawCallback(weatherRange)); } } } diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 547b71034..62360b9d6 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -250,11 +250,6 @@ void Emitter::setPlacer(osgParticle::Placer *placer) mPlacer = placer; } -osgParticle::Placer *Emitter::getPlacer() -{ - return mPlacer; -} - void Emitter::setCounter(osgParticle::Counter *counter) { mCounter = counter; diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index df93d5ced..7a2377f9d 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -225,7 +225,6 @@ namespace NifOsg void setShooter(osgParticle::Shooter* shooter); void setPlacer(osgParticle::Placer* placer); - osgParticle::Placer *getPlacer(); void setCounter(osgParticle::Counter* counter); private: From af6eeddbe551ac8ba7eb58f2be5085900908bc1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 14 Oct 2017 18:45:29 +0200 Subject: [PATCH 414/521] use operator instead of drawcallback --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/sky.cpp | 122 +++++++++++++--------- apps/openmw/mwrender/sky.hpp | 9 ++ 3 files changed, 81 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3826fd5f6..aa7b35b44 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -256,6 +256,7 @@ namespace MWRender mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); + mSky->setCamera(mViewer->getCamera()); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index eaa93ab88..1338a127c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -18,8 +18,6 @@ #include #include -#include - #include #include #include @@ -27,6 +25,9 @@ #include #include +#include +#include + #include #include @@ -1094,6 +1095,7 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) + , mCamera(NULL) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1338,76 +1340,85 @@ protected: osg::Uniform* mRainIntensityUniform; }; -class WeatherParticleDrawCallback : public osg::Drawable::DrawCallback +void SkyManager::setCamera(osg::Camera *camera) +{ + mCamera = camera; +} + +class WrapAroundOperator : public osgParticle::Operator { public: - WeatherParticleDrawCallback(osg::Vec3 &wrapRange) : osg::Drawable::DrawCallback() + WrapAroundOperator(osg::Camera *camera, const osg::Vec3 &wrapRange): osgParticle::Operator() { + mCamera = camera; mWrapRange = wrapRange; + mHalfWrapRange = mWrapRange / 2.0; + mPreviousCameraPosition = getCameraPosition(); } - virtual void drawImplementation(osg::RenderInfo& renderInfo, const osg::Drawable *drawable) const + virtual osg::Object *cloneType() const override { + return NULL; + } - osgParticle::ParticleSystem *ps = (osgParticle::ParticleSystem *) drawable; - - osgParticle::ParticleSystem::ScopedReadLock *lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); - - osg::Vec3 cameraPos = renderInfo.getCurrentCamera()->getInverseViewMatrix().getTrans(); + virtual osg::Object *clone(const osg::CopyOp &op) const override + { + return NULL; + } - osg::Vec3 cameraOffset = osg::Vec3( - fmod(cameraPos.x(), mWrapRange.x()), - fmod(cameraPos.y(), mWrapRange.y()), - fmod(cameraPos.z(), mWrapRange.z())); + virtual void operate(osgParticle::Particle *P, double dt) override + { + } - std::vector positionBackups; + virtual void operateParticles(osgParticle::ParticleSystem *ps, double dt) override + { + osg::Vec3 position = getCameraPosition(); + osg::Vec3 positionDifference = position - mPreviousCameraPosition; osg::Matrix toWorld, toLocal; - std::vector worldMatrices = drawable->getWorldMatrices(); - + std::vector worldMatrices = ps->getWorldMatrices(); + if (!worldMatrices.empty()) { toWorld = worldMatrices[0]; toLocal.invert(toWorld); } - for (int i = 0; i < ps->numParticles(); i++) + for (int i = 0; i < ps->numParticles(); ++i) { - osgParticle::Particle *particle = ps->getParticle(i); - positionBackups.push_back(particle->getPosition()); - particle->setPosition(toWorld.preMult(particle->getPosition())); - particle->setPosition(particle->getPosition() - cameraOffset); + osgParticle::Particle *p = ps->getParticle(i); + p->setPosition(toWorld.preMult(p->getPosition())); + p->setPosition(p->getPosition() - positionDifference); - for (int j = 0; j < 3; j++) // wrap-around effect in all 3 directions - { - osg::Vec3 newPosition = particle->getPosition(); + for (int j = 0; j < 3; ++j) // wrap-around in all 3 dimensions + { + osg::Vec3 pos = p->getPosition(); - if (particle->getPosition()[j] > mWrapRange[j] / 2.0) - newPosition[j] -= mWrapRange[j]; - else if (particle->getPosition()[j] < -mWrapRange[j] / 2.0) - newPosition[j] += mWrapRange[j]; + if (pos[j] < -mHalfWrapRange[j]) + pos[j] = mHalfWrapRange[j] + fmod(pos[j] - mHalfWrapRange[j],mWrapRange[j]); + else if (pos[j] > mHalfWrapRange[j]) + pos[j] = fmod(pos[j] + mHalfWrapRange[j],mWrapRange[j]) - mHalfWrapRange[j]; - particle->setPosition(newPosition); - } + p->setPosition(pos); + } - particle->setPosition(toLocal.preMult(particle->getPosition())); + p->setPosition(toLocal.preMult(p->getPosition())); } - delete lock; // unlock the mutex as ps will try to lock it in the following command - - ps->drawImplementation(renderInfo); - - lock = new osgParticle::ParticleSystem::ScopedReadLock(*ps->getReadWriteMutex()); - - for (int i = 0; i < ps->numParticles(); i++) // restore positions - ps->getParticle(i)->setPosition(positionBackups[i]); - - delete lock; + mPreviousCameraPosition = position; } protected: + osg::Camera *mCamera; + osg::Vec3 mPreviousCameraPosition; osg::Vec3 mWrapRange; + osg::Vec3 mHalfWrapRange; + + osg::Vec3 getCameraPosition() + { + return mCamera->getInverseViewMatrix().getTrans(); + } }; void SkyManager::createRain() @@ -1419,12 +1430,10 @@ void SkyManager::createRain() mRainParticleSystem = new osgParticle::ParticleSystem; osg::Vec3 rainRange = osg::Vec3(600,600,600); - mRainParticleSystem->setDrawCallback(new WeatherParticleDrawCallback(rainRange)); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); - mRainParticleSystem->setCullingActive(false); osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); @@ -1463,6 +1472,11 @@ void SkyManager::createRain() osg::ref_ptr updater (new osgParticle::ParticleSystemUpdater); updater->addParticleSystem(mRainParticleSystem); + osg::ref_ptr program (new osgParticle::ModularProgram); + program->addOperator(new WrapAroundOperator(mCamera,rainRange)); + program->setParticleSystem(mRainParticleSystem); + mRainNode->addChild(program); + mRainNode->addChild(emitter); mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); @@ -1638,14 +1652,20 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; mParticleEffect->accept(disableFreezeOnCullVisitor); - SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); - mParticleEffect->accept(findPSVisitor); - - for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); i++) + if (!weather.mIsStorm) { - osgParticle::ParticleSystem *ps = static_cast(findPSVisitor.mFoundNodes[i]); - osg::Vec3 weatherRange = osg::Vec3(1024,1024,800); - ps->setDrawCallback(new WeatherParticleDrawCallback(weatherRange)); + SceneUtil::FindByClassVisitor findPSVisitor(std::string("ParticleSystem")); + mParticleEffect->accept(findPSVisitor); + + for (unsigned int i = 0; i < findPSVisitor.mFoundNodes.size(); ++i) + { + osgParticle::ParticleSystem *ps = static_cast(findPSVisitor.mFoundNodes[i]); + + osg::ref_ptr program (new osgParticle::ModularProgram); + program->addOperator(new WrapAroundOperator(mCamera,osg::Vec3(1024,1024,800))); + program->setParticleSystem(ps); + mParticleNode->addChild(program); + } } } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 59a8ddc4e..097405b24 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -9,6 +9,11 @@ #include #include +namespace osg +{ + class Camera; +} + namespace osg { class Group; @@ -161,6 +166,8 @@ namespace MWRender void listAssetsToPreload(std::vector& models, std::vector& textures); + void setCamera(osg::Camera *camera); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -171,6 +178,8 @@ namespace MWRender Resource::SceneManager* mSceneManager; + osg::Camera* mCamera; + osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; From 28ff677337f9e6231a6be62cc4ec79aca6d3dd73 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 15 Oct 2017 00:07:46 +0100 Subject: [PATCH 415/521] Save 'data=...' lines correctly when exiting the wizard --- components/config/gamesettings.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index a897806c2..a1b5cc99e 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -152,9 +152,31 @@ bool Config::GameSettings::writeFile(QTextStream &stream) while (i.hasPrevious()) { i.previous(); + // 'data=...' lines need quotes and ampersands escaping to match how boost::filesystem::path uses boost::io::quoted + if (i.key() == QLatin1String("data")) + { + stream << i.key() << "="; + + // The following is based on boost::io::detail::quoted_manip.hpp, but calling this function did not work as there are too may QStrings involved + QChar delim = '\"'; + QChar escape = '&'; + QString string = i.value(); + + stream << delim; + for (QString::const_iterator it = string.begin(); it != string.end(); ++it) + { + if (*it == delim || *it == escape) + stream << escape; + stream << *it; + } + stream << delim; + + stream << '\n'; + continue; + } + // Quote paths with spaces - if (i.key() == QLatin1String("data") - || i.key() == QLatin1String("data-local") + if (i.key() == QLatin1String("data-local") || i.key() == QLatin1String("resources")) { if (i.value().contains(QChar(' '))) From 7329e6a9ef528c086f5169e570d46ed5567224f7 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 15 Oct 2017 01:59:21 +0100 Subject: [PATCH 416/521] Load 'data=...' lines correctly when starting the wizard or launcher, and save them correctly when exiting the launcher. --- components/config/gamesettings.cpp | 51 ++++++++++++++++++++--- components/files/configurationmanager.cpp | 2 - 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index a1b5cc99e..62aa034ee 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -55,7 +55,6 @@ void Config::GameSettings::validatePaths() for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromUtf8(it->string().c_str()); - path.remove(QChar('\"')); QDir dir(path); if (dir.exists()) @@ -64,6 +63,11 @@ void Config::GameSettings::validatePaths() // Do the same for data-local QString local = mSettings.value(QString("data-local")); + if (local.at(0) == QChar('\"')) + { + local.remove(0, 1); + local.chop(1); + } if (local.isEmpty()) return; @@ -76,7 +80,6 @@ void Config::GameSettings::validatePaths() if (!dataDirs.empty()) { QString path = QString::fromUtf8(dataDirs.front().string().c_str()); - path.remove(QChar('\"')); QDir dir(path); if (dir.exists()) @@ -120,6 +123,27 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap // Don't remove existing data entries if (key != QLatin1String("data")) settings.remove(key); + else + { + // 'data=...' line, so needs processing to deal with ampersands and quotes + QChar delim = '\"'; + QChar escape = '&'; + + if (value.at(0) == delim) + { + QString valueOriginal = value; + value = ""; + + for (QString::const_iterator it = valueOriginal.begin() + 1; it != valueOriginal.end(); ++it) + { + if (*it == escape) + ++it; + else if (*it == delim) + break; + value += *it; + } + } + } QStringList values = cache.values(key); values.append(settings.values(key)); @@ -157,7 +181,7 @@ bool Config::GameSettings::writeFile(QTextStream &stream) { stream << i.key() << "="; - // The following is based on boost::io::detail::quoted_manip.hpp, but calling this function did not work as there are too may QStrings involved + // The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved QChar delim = '\"'; QChar escape = '&'; QString string = i.value(); @@ -380,9 +404,26 @@ bool Config::GameSettings::writeFileWithComments(QFile &file) { it.previous(); + if (it.key() == QLatin1String("data")) + { + settingLine = it.key() + "="; + + // The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved + QChar delim = '\"'; + QChar escape = '&'; + QString string = it.value(); + + settingLine += delim; + for (QString::const_iterator iter = string.begin(); iter != string.end(); ++iter) + { + if (*iter == delim || *iter == escape) + settingLine += escape; + settingLine += *iter; + } + settingLine += delim; + } // Quote paths with spaces - if ((it.key() == QLatin1String("data") - || it.key() == QLatin1String("data-local") + else if ((it.key() == QLatin1String("data-local") || it.key() == QLatin1String("resources")) && it.value().contains(QChar(' '))) { QString stripped = it.value(); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 5316255ad..7c3956a29 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -75,8 +75,6 @@ void ConfigurationManager::processPaths(Files::PathContainer& dataDirs, bool cre for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { path = it->string(); - boost::erase_all(path, "\""); - *it = boost::filesystem::path(path); // Check if path contains a token if (!path.empty() && *path.begin() == '?') From 49dbb4a9ca16ebb3d9f6d585b6a3d975d8608313 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 15 Oct 2017 02:05:22 +0100 Subject: [PATCH 417/521] Add a third copy of a comment where I felt clarification was missing --- components/config/gamesettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 62aa034ee..0ea28dceb 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -126,6 +126,7 @@ bool Config::GameSettings::readFile(QTextStream &stream, QMap else { // 'data=...' line, so needs processing to deal with ampersands and quotes + // The following is based on boost::io::detail::quoted_manip.hpp, but calling those functions did not work as there are too may QStrings involved QChar delim = '\"'; QChar escape = '&'; From 8f255a6b726cc92c45690c313e0065df7723ec9d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 15 Oct 2017 11:03:02 +0400 Subject: [PATCH 418/521] Handle Trespassing crime differently from Theft (bug #4158) --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2c7b6a500..dfbcf0ea2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1123,6 +1123,10 @@ namespace MWMechanics if (playerFollowers.find(*it) != playerFollowers.end()) continue; + // NPC will complain about theft even if he will do nothing about it + if (type == OT_Theft || type == OT_Pickpocket) + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + crimeSeen = true; } } @@ -1243,9 +1247,7 @@ namespace MWMechanics { reported = true; - if (type == OT_Theft || type == OT_Pickpocket) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Trespassing) + if (type == OT_Trespassing) MWBase::Environment::get().getDialogueManager()->say(*it, "intruder"); } From 4c174ecd12b98ec3d31fb00ee28434385f2a679b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:06:34 +0200 Subject: [PATCH 419/521] Merge changes to coverity scan script --- .travis.yml | 4 ++-- extern/osg-ffmpeg-videoplayer/License.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6606b0290..d173ef6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,8 @@ addons: project: name: "OpenMW/openmw" description: "" - notification_email: scrawl@baseoftrash.de - build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE" + notification_email: 720642+scrawl@users.noreply.github.com + build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE -DBUILD_BSATOOL=FALSE -DBUILD_ESMTOOL=FALSE -DBUILD_MWINIIMPORTER=FALSE -DBUILD_LAUNCHER=FALSE" build_command: "make -j3" branch_pattern: coverity_scan matrix: diff --git a/extern/osg-ffmpeg-videoplayer/License.txt b/extern/osg-ffmpeg-videoplayer/License.txt index 49f534065..bb70d7d37 100644 --- a/extern/osg-ffmpeg-videoplayer/License.txt +++ b/extern/osg-ffmpeg-videoplayer/License.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 Jannik Heller , Chris Robinson +Copyright (c) 2014 scrawl, Chris Robinson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: From 50d7eb8e5470d02bec3224ec9b8df2ab1a35f29c Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:01:18 +0200 Subject: [PATCH 420/521] Fix crash when adding a NULL object to the cache --- components/resource/bulletshapemanager.cpp | 6 ++---- components/resource/multiobjectcache.cpp | 5 +++++ components/resource/objectcache.cpp | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index c1a7eb8f3..53b08b8be 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -141,10 +141,7 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & node->accept(visitor); shape = visitor.getShape(); if (!shape) - { - mCache->addEntryToObjectCache(normalized, NULL); return osg::ref_ptr(); - } } mCache->addEntryToObjectCache(normalized, shape); @@ -158,7 +155,8 @@ osg::ref_ptr BulletShapeManager::cacheInstance(const std::s mVFS->normalizeFilename(normalized); osg::ref_ptr instance = createInstance(normalized); - mInstanceCache->addEntryToObjectCache(normalized, instance.get()); + if (instance) + mInstanceCache->addEntryToObjectCache(normalized, instance.get()); return instance; } diff --git a/components/resource/multiobjectcache.cpp b/components/resource/multiobjectcache.cpp index 266139f3c..d6639d3ae 100644 --- a/components/resource/multiobjectcache.cpp +++ b/components/resource/multiobjectcache.cpp @@ -51,6 +51,11 @@ namespace Resource void MultiObjectCache::addEntryToObjectCache(const std::string &filename, osg::Object *object) { + if (!object) + { + OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl; + return; + } OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache.insert(std::make_pair(filename, object)); } diff --git a/components/resource/objectcache.cpp b/components/resource/objectcache.cpp index de0fa7a40..e8c082f91 100644 --- a/components/resource/objectcache.cpp +++ b/components/resource/objectcache.cpp @@ -34,6 +34,11 @@ ObjectCache::~ObjectCache() void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { + if (!object) + { + OSG_ALWAYS << " trying to add NULL object to cache for " << filename << std::endl; + return; + } OpenThreads::ScopedLock lock(_objectCacheMutex); _objectCache[filename]=ObjectTimeStampPair(object,timestamp); } From 624046c5581ba21c0da55e582e9b92cc8730a175 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:01:57 +0200 Subject: [PATCH 421/521] Fix unused event handler --- apps/openmw/mwgui/savegamedialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 6a290bef1..43e511144 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -84,6 +84,7 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed); dialog->eventCancelClicked.clear(); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotCancel); } void SaveGameDialog::onDeleteSlotConfirmed() From 64d02f577e83f9bc3405c9a4ba25bf9d6d016d64 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:02:36 +0200 Subject: [PATCH 422/521] Fix missing null check --- apps/openmw/mwphysics/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 887189a85..7f880d716 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1046,7 +1046,7 @@ namespace MWPhysics bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor) { Actor* physactor = getActor(actor); - return physactor->getOnGround(); + return physactor && physactor->getOnGround(); } bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel) From 03554b2f4bfedd27b9dca83c2147f299098a081b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:03:11 +0200 Subject: [PATCH 423/521] Fix some style issues flagged by cppcheck --- apps/openmw/mwgui/dialogue.hpp | 2 -- apps/openmw/mwgui/hud.cpp | 1 - apps/openmw/mwgui/hud.hpp | 1 - apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 6 ++---- apps/openmw/mwmechanics/combat.cpp | 20 -------------------- apps/openmw/mwmechanics/combat.hpp | 4 ---- apps/openmw/mwphysics/physicssystem.cpp | 2 -- components/nifbullet/bulletnifloader.cpp | 2 +- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifosg/nifloader.cpp | 4 ++-- components/resource/bulletshapemanager.cpp | 12 +++++------- components/sceneutil/util.cpp | 9 --------- components/sceneutil/util.hpp | 2 -- components/sceneutil/workqueue.cpp | 1 + 16 files changed, 14 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 97a0e8b37..5e362e9b5 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -155,8 +155,6 @@ namespace MWGui void restock(); void deleteLater(); - bool mEnabled; - bool mIsCompanion; std::list mKeywords; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1db2691f4..23eb499de 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -80,7 +80,6 @@ namespace MWGui , mSpellStatus(NULL) , mEffectBox(NULL) , mMinimap(NULL) - , mCompass(NULL) , mCrosshair(NULL) , mCellNameBox(NULL) , mDrowningFrame(NULL) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 3542f3ebf..73428c034 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -69,7 +69,6 @@ namespace MWGui MyGUI::Widget *mEffectBox, *mMinimapBox; MyGUI::Button* mMinimapButton; MyGUI::ScrollView* mMinimap; - MyGUI::ImageBox* mCompass; MyGUI::ImageBox* mCrosshair; MyGUI::TextBox* mCellNameBox; MyGUI::TextBox* mWeaponSpellBox; diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 649aab3f2..3414c1b94 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -46,7 +46,7 @@ namespace MWGui void onMouseWheel(MyGUI::Widget* _sender, int _rel); void addSpell(const ESM::Spell& spell); void clearSpells(); - int mLastPos,mCurrentY; + int mCurrentY; static const int sLineHeight; diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index bf505b00f..d3d487579 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -105,7 +105,7 @@ namespace MWGui std::stringstream out; out << val << "/" << max; - setText(tname, out.str().c_str()); + setText(tname, out.str()); pt->setProgressRange(std::max(0, max)); pt->setProgressPosition(std::max(0, val)); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 7f412b4d2..255874d88 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -451,11 +451,10 @@ namespace MWMechanics // Check if an idle actor is too close to a door - if so start walking storage.mDoorCheckDuration += duration; - static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); - if (storage.mDoorCheckDuration >= DOOR_CHECK_INTERVAL) { storage.mDoorCheckDuration = 0; // restart timer + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); if (mDistance && // actor is not intended to be stationary proximityToDoor(actor, distance*1.6f)) { @@ -531,11 +530,10 @@ namespace MWMechanics void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) { - static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); - if (mObstacleCheck.isEvading()) { // first check if we're walking into a door + static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); if (proximityToDoor(actor, distance)) { // remove allowed points then select another random destination diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 54ad75135..13cd4232d 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -424,26 +424,6 @@ namespace MWMechanics } } - bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) - { - const MWWorld::Class& attackerClass = attacker.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - - // If attacker is fish, victim must be in water - if (attackerClass.isPureWaterCreature(attacker)) - { - return world->isWading(victim); - } - - // If attacker can't swim, victim must not be in water - if (!attackerClass.canSwim(attacker)) - { - return !world->isSwimming(victim); - } - - return true; - } - float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) { osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 12961dc4b..8b93ca204 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -39,10 +39,6 @@ void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& vict /// Apply the fatigue loss incurred by attacking with the given weapon (weapon may be empty = hand-to-hand) void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float attackStrength); -/// Can attacker operate in victim's environment? -/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? -bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); - float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7f880d716..34932e360 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -702,8 +702,6 @@ namespace MWPhysics const char* env = getenv("OPENMW_PHYSICS_FPS"); if (env) { - std::string str(env); - float physFramerate = std::atof(env); if (physFramerate > 0) { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 3865b17a5..9e9fe3759 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -49,7 +49,7 @@ BulletNifLoader::~BulletNifLoader() { } -osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr nif) +osg::ref_ptr BulletNifLoader::load(const Nif::NIFFilePtr& nif) { mShape = new Resource::BulletShape; diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index a30bf8fdf..fff51933f 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -50,7 +50,7 @@ public: abort(); } - osg::ref_ptr load(const Nif::NIFFilePtr file); + osg::ref_ptr load(const Nif::NIFFilePtr& file); private: bool findBoundingBox(const Nif::Node* node, int flags = 0); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8810f171a..a3b81338e 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1191,8 +1191,8 @@ namespace NifOsg if (pixelData->mipmaps.empty()) return NULL; - unsigned int width = 0; - unsigned int height = 0; + int width = 0; + int height = 0; std::vector mipmapVector; for (unsigned int i=0; imipmaps.size()-3; ++i) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 53b08b8be..a3d09311a 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -63,7 +63,7 @@ class NodeToShapeVisitor : public osg::NodeVisitor public: NodeToShapeVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - , mTriangleMesh(NULL) + , mTriangleMesh(nullptr) { } @@ -71,11 +71,11 @@ public: virtual void apply(osg::Drawable &drawable) { if (!mTriangleMesh) - mTriangleMesh = new btTriangleMesh; + mTriangleMesh.reset(new btTriangleMesh); osg::Matrixf worldMat = osg::computeLocalToWorld(getNodePath()); osg::TriangleFunctor functor; - functor.setTriMesh(mTriangleMesh); + functor.setTriMesh(mTriangleMesh.get()); functor.setMatrix(worldMat); drawable.accept(functor); } @@ -86,14 +86,12 @@ public: return osg::ref_ptr(); osg::ref_ptr shape (new BulletShape); - TriangleMeshShape* meshShape = new TriangleMeshShape(mTriangleMesh, true); - shape->mCollisionShape = meshShape; - mTriangleMesh = NULL; + shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true); return shape; } private: - btTriangleMesh* mTriangleMesh; + std::unique_ptr mTriangleMesh; }; BulletShapeManager::BulletShapeManager(const VFS::Manager* vfs, SceneManager* sceneMgr, NifFileManager* nifFileManager) diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 3add3bb23..eec302965 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -42,13 +42,4 @@ osg::Vec4f colourFromRGB(unsigned int clr) return colour; } -osg::Vec4f colourFromRGBA(unsigned int clr) -{ - osg::Vec4f colour(((clr >> 0) & 0xFF) / 255.0f, - ((clr >> 8) & 0xFF) / 255.0f, - ((clr >> 16) & 0xFF) / 255.0f, - ((clr >> 24) & 0xFF) / 255.0f); - return colour; -} - } diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index d8fefdb29..109099740 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -15,8 +15,6 @@ namespace SceneUtil osg::Vec4f colourFromRGB (unsigned int clr); - osg::Vec4f colourFromRGBA (unsigned int clr); - } #endif diff --git a/components/sceneutil/workqueue.cpp b/components/sceneutil/workqueue.cpp index cc40506f0..2cd1ec806 100644 --- a/components/sceneutil/workqueue.cpp +++ b/components/sceneutil/workqueue.cpp @@ -119,6 +119,7 @@ unsigned int WorkQueue::getNumActiveThreads() const WorkThread::WorkThread(WorkQueue *workQueue) : mWorkQueue(workQueue) + , mActive(false) { } From 136ef1f738b84db1be424be412e45532fdeecf8b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 15 Oct 2017 17:24:23 +0200 Subject: [PATCH 424/521] Fix incomplete settings in recreateShaders() --- components/resource/scenemanager.cpp | 35 +++++++++++++++------------- components/resource/scenemanager.hpp | 3 +++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ab801ab82..9c5a2a14e 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -244,12 +244,9 @@ namespace Resource void SceneManager::recreateShaders(osg::ref_ptr node) { - Shader::ShaderVisitor shaderVisitor(*mShaderManager.get(), *mImageManager, "objects_vertex.glsl", "objects_fragment.glsl"); - shaderVisitor.setForceShaders(mForceShaders); - shaderVisitor.setClampLighting(mClampLighting); - shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting); - shaderVisitor.setAllowedToModifyStateSets(false); - node->accept(shaderVisitor); + osg::ref_ptr shaderVisitor(createShaderVisitor()); + shaderVisitor->setAllowedToModifyStateSets(false); + node->accept(*shaderVisitor); } void SceneManager::setClampLighting(bool clamp) @@ -516,16 +513,8 @@ namespace Resource SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy); loaded->accept(setFilterSettingsControllerVisitor); - Shader::ShaderVisitor 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); - shaderVisitor.setAutoUseSpecularMaps(mAutoUseSpecularMaps); - shaderVisitor.setSpecularMapPattern(mSpecularMapPattern); - loaded->accept(shaderVisitor); + osg::ref_ptr shaderVisitor (createShaderVisitor()); + loaded->accept(*shaderVisitor); // share state // do this before optimizing so the optimizer will be able to combine nodes more aggressively @@ -748,4 +737,18 @@ namespace Resource stats->setAttribute(frameNumber, "Node Instance", mInstanceCache->getCacheSize()); } + Shader::ShaderVisitor *SceneManager::createShaderVisitor() + { + 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); + shaderVisitor->setAutoUseSpecularMaps(mAutoUseSpecularMaps); + shaderVisitor->setSpecularMapPattern(mSpecularMapPattern); + return shaderVisitor; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index b223353c2..4f1523ece 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -31,6 +31,7 @@ namespace osgDB namespace Shader { class ShaderManager; + class ShaderVisitor; } namespace Resource @@ -149,6 +150,8 @@ namespace Resource private: + Shader::ShaderVisitor* createShaderVisitor(); + std::unique_ptr mShaderManager; bool mForceShaders; bool mClampLighting; From 654bd401fb9e005fef5bc2c243386616e2dc2123 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 16 Oct 2017 15:38:17 +0100 Subject: [PATCH 425/521] Switch openmw-cs to the escape versions of option types --- apps/opencs/editor.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 86c87962d..334674aa7 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -90,16 +90,16 @@ std::pair > CS::Editor::readConfi boost::program_options::options_description desc("Syntax: openmw-cs \nAllowed options"); desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("data-local", boost::program_options::value()->default_value("")) + ("data", boost::program_options::value()->default_value(Files::EscapePathContainer(), "data")->multitoken()->composing()) + ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")) - ("resources", boost::program_options::value()->default_value("resources")) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()) + ("encoding", boost::program_options::value()->default_value("win1252")) + ("resources", boost::program_options::value()->default_value("resources")) + ("fallback-archive", boost::program_options::value()-> + default_value(Files::EscapeStringVector(), "fallback-archive")->multitoken()) ("fallback", boost::program_options::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") - ("script-blacklist", boost::program_options::value >()->default_value(std::vector(), "") + ("script-blacklist", boost::program_options::value()->default_value(Files::EscapeStringVector(), "") ->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)") ("script-blacklist-use", boost::program_options::value()->implicit_value(true) ->default_value(true), "enable script blacklisting"); @@ -109,24 +109,24 @@ std::pair > CS::Editor::readConfi mCfgMgr.readConfiguration(variables, desc, quiet); mDocumentManager.setEncoding ( - ToUTF8::calculateEncoding (variables["encoding"].as())); + ToUTF8::calculateEncoding (variables["encoding"].as().toStdString())); - mDocumentManager.setResourceDir (mResources = variables["resources"].as()); + mDocumentManager.setResourceDir (mResources = variables["resources"].as().toStdString()); mDocumentManager.setFallbackMap (variables["fallback"].as().mMap); if (variables["script-blacklist-use"].as()) mDocumentManager.setBlacklistedScripts ( - variables["script-blacklist"].as >()); + variables["script-blacklist"].as().toStdStringVector()); mFsStrict = variables["fs-strict"].as(); Files::PathContainer dataDirs, dataLocal; if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); + dataDirs = Files::PathContainer(Files::EscapePath::toPathContainer(variables["data"].as())); } - std::string local = variables["data-local"].as(); + std::string local = variables["data-local"].as().toStdString(); if (!local.empty()) { dataLocal.push_back(Files::PathContainer::value_type(local)); } @@ -157,7 +157,7 @@ std::pair > CS::Editor::readConfi mFileDialog.addFiles(path); } - return std::make_pair (dataDirs, variables["fallback-archive"].as >()); + return std::make_pair (dataDirs, variables["fallback-archive"].as().toStdStringVector()); } void CS::Editor::createGame() From 6d7a24224b489c6fee804fc3d05350e615c77046 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Mon, 16 Oct 2017 12:52:13 -0400 Subject: [PATCH 426/521] Add documentation. --- apps/opencs/model/tools/mergestages.hpp | 6 ++++-- apps/opencs/model/world/commands.hpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/mergestages.hpp b/apps/opencs/model/tools/mergestages.hpp index 9a16e03ab..4b41c5a04 100644 --- a/apps/opencs/model/tools/mergestages.hpp +++ b/apps/opencs/model/tools/mergestages.hpp @@ -147,7 +147,8 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - /// Flattens the added land and land texture records. + /// During this stage, the complex process of combining LandTextures from + /// potentially multiple plugins is undertaken. class FixLandsAndLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; @@ -163,7 +164,8 @@ namespace CSMTools ///< Messages resulting from this stage will be appended to \a messages. }; - // Removes base LandTexture records. + /// Removes base LandTexture records. This gets rid of the base records previously + /// needed in FixLandsAndLandTexturesMergeStage. class CleanupLandTexturesMergeStage : public CSMDoc::Stage { MergeState& mState; diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index be86dd508..58a1b1d1c 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -44,6 +44,15 @@ namespace CSMWorld bool mChanged; }; + /// \brief Adds LandTexture records and modifies texture indices as needed. + /// + /// LandTexture records are different from other types of records, because + /// they only effect the current plugin. Thus, when modifying or copying + /// a Land record, all of the LandTexture records referenced need to be + /// added to the current plugin. Since these newly added LandTextures could + /// have indices that conflict with pre-existing LandTextures in the current + /// plugin, the indices might have to be changed, both for the newly added + /// LandRecord and within the Land record. class ImportLandTexturesCommand : public QUndoCommand { public: @@ -71,6 +80,9 @@ namespace CSMWorld std::vector mCreatedTextures; }; + /// \brief This command is used to fix LandTexture records and texture + /// indices after cloning a Land. See ImportLandTexturesCommand for + /// details. class CopyLandTexturesCommand : public ImportLandTexturesCommand { public: @@ -90,6 +102,9 @@ namespace CSMWorld std::string mDestId; }; + /// \brief This command brings a land record into the current plugin, adding + /// LandTexture records and modifying texture indices as needed. + /// \note See ImportLandTextures for more details. class TouchLandCommand : public ImportLandTexturesCommand { public: From da4765362593c80bed5c39b9333e6eec48e1500c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 16 Oct 2017 19:47:08 +0200 Subject: [PATCH 427/521] move rain intensity uniform to water node --- apps/openmw/mwrender/renderingmanager.cpp | 9 +++------ apps/openmw/mwrender/renderingmanager.hpp | 1 - apps/openmw/mwrender/sky.cpp | 13 ++++++++++--- apps/openmw/mwrender/sky.hpp | 6 +++++- apps/openmw/mwrender/water.cpp | 11 ++++++++++- apps/openmw/mwrender/water.hpp | 5 +++++ 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa7b35b44..7585ee32a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -251,12 +251,9 @@ namespace MWRender sceneRoot->setNodeMask(Mask_Scene); sceneRoot->setName("Scene Root"); - mUniformRainIntensity = new osg::Uniform("rainIntensity",(float) 0.0); - - mRootNode->getOrCreateStateSet()->addUniform(mUniformRainIntensity); - mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); mSky->setCamera(mViewer->getCamera()); + mSky->setRainIntensityUniform(mWater->getRainIntensityUniform()); source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); @@ -506,7 +503,7 @@ namespace MWRender } if (!mSky->isEnabled() || !mSky->hasRain()) - clearRainRipples(); + clearRainRipples(); mCamera->update(dt, paused); @@ -811,7 +808,7 @@ namespace MWRender void RenderingManager::clearRainRipples() { - mUniformRainIntensity->set((float) 0.0); + mWater->getRainIntensityUniform()->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 43059ab6d..f9e98b269 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -85,7 +85,6 @@ namespace MWRender osg::Uniform* mUniformNear; osg::Uniform* mUniformFar; - osg::Uniform* mUniformRainIntensity; void preloadCommonAssets(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1338a127c..cffa9909a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1096,6 +1096,7 @@ private: SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) , mCamera(NULL) + , mRainIntensityUniform(NULL) , mAtmosphereNightRoll(0.f) , mCreated(false) , mIsStorm(false) @@ -1138,6 +1139,11 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); } +void SkyManager::setRainIntensityUniform(osg::Uniform *uniform) +{ + mRainIntensityUniform = uniform; +} + void SkyManager::create() { assert(!mCreated); @@ -1315,7 +1321,6 @@ protected: class RainFader : public AlphaFader { public: - RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() { mRainIntensityUniform = rainIntensityUniform; @@ -1481,7 +1486,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader(mRootNode->getParent(0)->getParent(0)->getStateSet()->getUniform("rainIntensity")); + mRainFader = new RainFader(mRainIntensityUniform); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); @@ -1742,7 +1747,8 @@ void SkyManager::setWeather(const WeatherResult& weather) mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a()); float nextStarsOpacity = weather.mNightFade * weather.mGlareView; - if(weather.mNight && mStarsOpacity != nextStarsOpacity) + + if (weather.mNight && mStarsOpacity != nextStarsOpacity) { mStarsOpacity = nextStarsOpacity; @@ -1753,6 +1759,7 @@ 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); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 097405b24..816dbf798 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -8,6 +8,7 @@ #include #include +#include namespace osg { @@ -168,6 +169,8 @@ namespace MWRender void setCamera(osg::Camera *camera); + void setRainIntensityUniform(osg::Uniform *uniform); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -178,7 +181,8 @@ namespace MWRender Resource::SceneManager* mSceneManager; - osg::Camera* mCamera; + osg::Camera *mCamera; + osg::Uniform *mRainIntensityUniform; osg::ref_ptr mRootNode; osg::ref_ptr mEarlyRenderBinRoot; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 68c07c1ab..8935eb37a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -411,14 +411,20 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem createSimpleWaterStateSet(geom2, mFallback->getFallbackFloat("Water_Map_Alpha")); geom2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geom2); - + mSceneRoot->addChild(mWaterNode); setHeight(mTop); + mRainIntensityUniform = NULL; updateWaterMaterial(); } +osg::Uniform *Water::getRainIntensityUniform() +{ + return mRainIntensityUniform; +} + void Water::updateWaterMaterial() { if (mReflection) @@ -550,6 +556,9 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R program->addShader(fragmentShader); shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); + mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); + shaderStateset->addUniform(mRainIntensityUniform); + node->setStateSet(shaderStateset); node->setUpdateCallback(NULL); } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 33b314c51..6c7adac37 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -50,6 +51,8 @@ namespace MWRender { static const int CELL_SIZE = 8192; + osg::Uniform* mRainIntensityUniform; + osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; @@ -110,6 +113,8 @@ namespace MWRender void update(float dt); void processChangedSettings(const Settings::CategorySettingVector& settings); + + osg::Uniform *getRainIntensityUniform(); }; } From 797e407269b2e4aef6cba8e521f07a7f7819276f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 16 Oct 2017 20:23:56 +0200 Subject: [PATCH 428/521] make snow create water ripples --- apps/openmw/mwrender/sky.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index cffa9909a..05937742f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1245,9 +1245,11 @@ private: class AlphaFader : public SceneUtil::StateSetUpdater { public: - AlphaFader() + /// @param rainIntensityUniform rain uniform to update along with alpha, can be NULL + AlphaFader(osg::Uniform *rainIntensityUniform=NULL) : mAlpha(1.f) { + mRainIntensityUniform = rainIntensityUniform; } void setAlpha(float alpha) @@ -1266,15 +1268,19 @@ public: { osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); + + if (mRainIntensityUniform) + mRainIntensityUniform->set((float) mAlpha); } // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: - SetupVisitor() + SetupVisitor(osg::Uniform *rainIntensityUniform) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { + mRainIntensityUniform = rainIntensityUniform; } virtual void apply(osg::Node &node) @@ -1285,14 +1291,16 @@ public: { SceneUtil::CompositeStateSetUpdater* composite = NULL; osg::Callback* callback = node.getUpdateCallback(); + while (callback) { if ((composite = dynamic_cast(callback))) break; + callback = callback->getNestedCallback(); } - osg::ref_ptr alphaFader (new AlphaFader); + osg::ref_ptr alphaFader (new AlphaFader(mRainIntensityUniform)); if (composite) composite->addController(alphaFader); @@ -1312,10 +1320,12 @@ public: private: std::vector > mAlphaFaders; + osg::Uniform *mRainIntensityUniform; }; protected: float mAlpha; + osg::Uniform *mRainIntensityUniform; }; class RainFader : public AlphaFader @@ -1645,12 +1655,16 @@ void SkyManager::setWeather(const WeatherResult& weather) mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); } + mParticleEffect = mSceneManager->getInstance(mCurrentParticleEffect, mParticleNode); SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); - AlphaFader::SetupVisitor alphaFaderSetupVisitor; + osg::Uniform *rainUniform = weather.mIsStorm ? NULL : mRainIntensityUniform; + + AlphaFader::SetupVisitor alphaFaderSetupVisitor(rainUniform); + mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); From 8a1e0e74fd7f35ee4be220ab3796995fed0fbc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 16 Oct 2017 23:56:03 +0200 Subject: [PATCH 429/521] update uniform from one place --- apps/openmw/mwrender/renderingmanager.cpp | 9 ----- apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwrender/sky.cpp | 46 ++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 + 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7585ee32a..6c4cc802b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -502,9 +502,6 @@ namespace MWRender mWater->update(dt); } - if (!mSky->isEnabled() || !mSky->hasRain()) - clearRainRipples(); - mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; @@ -803,12 +800,6 @@ namespace MWRender void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); - mWater->clearRipples(); - } - - void RenderingManager::clearRainRipples() - { - mWater->getRainIntensityUniform()->set((float) 0.0); } void RenderingManager::clear() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f9e98b269..f0087e43d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -159,8 +159,6 @@ namespace MWRender /// Clear all worldspace-specific data void notifyWorldSpaceChanged(); - void clearRainRipples(); - void update(float dt, bool paused); Animation* getAnimation(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 05937742f..97633a6b9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1245,11 +1245,11 @@ private: class AlphaFader : public SceneUtil::StateSetUpdater { public: - /// @param rainIntensityUniform rain uniform to update along with alpha, can be NULL - AlphaFader(osg::Uniform *rainIntensityUniform=NULL) + /// @param alphaUpdate variable which to update with alpha value + AlphaFader(float *alphaUpdate) : mAlpha(1.f) { - mRainIntensityUniform = rainIntensityUniform; + mAlphaUpdate = alphaUpdate; } void setAlpha(float alpha) @@ -1269,18 +1269,18 @@ public: osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); - if (mRainIntensityUniform) - mRainIntensityUniform->set((float) mAlpha); + if (mAlphaUpdate) + *mAlphaUpdate = mAlpha; } // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: - SetupVisitor(osg::Uniform *rainIntensityUniform) + SetupVisitor(float *alphaUpdate) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - mRainIntensityUniform = rainIntensityUniform; + mAlphaUpdate = alphaUpdate; } virtual void apply(osg::Node &node) @@ -1300,7 +1300,7 @@ public: callback = callback->getNestedCallback(); } - osg::ref_ptr alphaFader (new AlphaFader(mRainIntensityUniform)); + osg::ref_ptr alphaFader (new AlphaFader(mAlphaUpdate)); if (composite) composite->addController(alphaFader); @@ -1310,6 +1310,7 @@ public: mAlphaFaders.push_back(alphaFader); } } + traverse(node); } @@ -1320,20 +1321,19 @@ public: private: std::vector > mAlphaFaders; - osg::Uniform *mRainIntensityUniform; + float *mAlphaUpdate; }; protected: float mAlpha; - osg::Uniform *mRainIntensityUniform; + float *mAlphaUpdate; }; class RainFader : public AlphaFader { public: - RainFader(osg::Uniform *rainIntensityUniform): AlphaFader() + RainFader(float *alphaUpdate): AlphaFader(alphaUpdate) { - mRainIntensityUniform = rainIntensityUniform; } virtual void setDefaults(osg::StateSet* stateset) @@ -1348,11 +1348,8 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) { AlphaFader::apply(stateset,nv); - mRainIntensityUniform->set((float) (mAlpha * 2.0)); // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity + *mAlphaUpdate = mAlpha * 2.0; // mAlpha is limited to 0.6 so multiply by 2 to reach full intensity } - -protected: - osg::Uniform* mRainIntensityUniform; }; void SkyManager::setCamera(osg::Camera *camera) @@ -1496,7 +1493,7 @@ void SkyManager::createRain() mRainNode->addChild(mRainParticleSystem); mRainNode->addChild(updater); - mRainFader = new RainFader(mRainIntensityUniform); + mRainFader = new RainFader(&mWeatherAlpha); mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); mRainNode->setNodeMask(Mask_WeatherParticles); @@ -1549,7 +1546,16 @@ bool SkyManager::hasRain() void SkyManager::update(float duration) { - if (!mEnabled) return; + if (!mEnabled) + { + mRainIntensityUniform->set((float) 0.0); + return; + } + + if (mIsStorm || (!hasRain() && !mParticleNode)) + mRainIntensityUniform->set((float) 0.0); + else + mRainIntensityUniform->set((float) mWeatherAlpha); if (mIsStorm) { @@ -1661,9 +1667,7 @@ void SkyManager::setWeather(const WeatherResult& weather) SceneUtil::AssignControllerSourcesVisitor assignVisitor(std::shared_ptr(new SceneUtil::FrameTimeSource)); mParticleEffect->accept(assignVisitor); - osg::Uniform *rainUniform = weather.mIsStorm ? NULL : mRainIntensityUniform; - - AlphaFader::SetupVisitor alphaFaderSetupVisitor(rainUniform); + AlphaFader::SetupVisitor alphaFaderSetupVisitor(&mWeatherAlpha); mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 816dbf798..4357d468c 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -252,6 +252,8 @@ namespace MWRender bool mEnabled; bool mSunEnabled; + float mWeatherAlpha; + osg::Vec4f mMoonScriptColor; }; } From a7cad65aab97f00757ef421452ba14ddd229cecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 17 Oct 2017 00:13:55 +0200 Subject: [PATCH 430/521] fix water shader switching bug --- apps/openmw/mwrender/sky.cpp | 15 ++++++++++----- apps/openmw/mwrender/water.cpp | 6 +++--- apps/openmw/mwrender/water.hpp | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 97633a6b9..6c599fc3f 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1548,14 +1548,19 @@ void SkyManager::update(float duration) { if (!mEnabled) { - mRainIntensityUniform->set((float) 0.0); + if (mRainIntensityUniform) + mRainIntensityUniform->set((float) 0.0); + return; } - if (mIsStorm || (!hasRain() && !mParticleNode)) - mRainIntensityUniform->set((float) 0.0); - else - mRainIntensityUniform->set((float) mWeatherAlpha); + if (mRainIntensityUniform) + { + if (mIsStorm || (!hasRain() && !mParticleNode)) + mRainIntensityUniform->set((float) 0.0); + else + mRainIntensityUniform->set((float) mWeatherAlpha); + } if (mIsStorm) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 8935eb37a..52b659984 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -416,13 +416,14 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem setHeight(mTop); - mRainIntensityUniform = NULL; updateWaterMaterial(); + + mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); } osg::Uniform *Water::getRainIntensityUniform() { - return mRainIntensityUniform; + return mRainIntensityUniform.get(); } void Water::updateWaterMaterial() @@ -556,7 +557,6 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R program->addShader(fragmentShader); shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); shaderStateset->addUniform(mRainIntensityUniform); node->setStateSet(shaderStateset); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6c7adac37..a4fd1ed36 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -51,7 +51,7 @@ namespace MWRender { static const int CELL_SIZE = 8192; - osg::Uniform* mRainIntensityUniform; + osg::ref_ptr mRainIntensityUniform; osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; From 4d4d247565338db653111fe92deb23c099966d3a Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 17 Oct 2017 23:26:55 +0400 Subject: [PATCH 431/521] Use SwimTurnLeft/Right animations correctly --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ec65255bc..03acfdaf2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1874,7 +1874,7 @@ void CharacterController::update(float duration) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack))); } - else if(rot.z() != 0.0f && !inwater && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) + else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; From 1f77f9654bba0e286ada5d3d593c1f4bf43ac781 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 01:42:11 +0100 Subject: [PATCH 432/521] Strip quotes from the data-local setting if present (because for whatever reason it's a string, not a boost::filesystem::path) --- apps/openmw/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 9e44f237e..ac891b980 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -194,6 +194,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat std::string local(variables["data-local"].as().toStdString()); if (!local.empty()) { + if (local.front() == '\"') + local = local.substr(1, local.length() - 2); + dataDirs.push_back(Files::PathContainer::value_type(local)); } From 43e9e955c88aaade0b68bd00d7ce00e7c5f65bf9 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 02:04:48 +0100 Subject: [PATCH 433/521] Do the same for the CS --- apps/opencs/editor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 334674aa7..35ce51337 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -127,7 +127,11 @@ std::pair > CS::Editor::readConfi } std::string local = variables["data-local"].as().toStdString(); - if (!local.empty()) { + if (!local.empty()) + { + if (local.front() == '\"') + local = local.substr(1, local.length() - 2); + dataLocal.push_back(Files::PathContainer::value_type(local)); } From 2aad5bed7a9789b2feb22b225f23eefc73777107 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 05:00:32 +0100 Subject: [PATCH 434/521] Mark worldimp functions as override to stop distracting Travis CI warnings and prevent future typos --- apps/openmw/mwworld/worldimp.hpp | 352 +++++++++++++++---------------- 1 file changed, 176 insertions(+), 176 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 774753b6c..c130c9d5b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -137,7 +137,7 @@ namespace MWWorld MWWorld::Ptr getFacedObject(float maxDistance, bool ignorePlayer=true); public: // FIXME - void removeContainerScripts(const Ptr& reference); + void removeContainerScripts(const Ptr& reference) override; private: void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); @@ -191,362 +191,362 @@ namespace MWWorld virtual ~World(); - virtual void startNewGame (bool bypass); + virtual void startNewGame (bool bypass) override; ///< \param bypass Bypass regular game start. - virtual void clear(); + virtual void clear() override; - virtual int countSavedGameRecords() const; - virtual int countSavedGameCells() const; + virtual int countSavedGameRecords() const override; + virtual int countSavedGameCells() const override; - virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const override; virtual void readRecord (ESM::ESMReader& reader, uint32_t type, - const std::map& contentFileMap); + const std::map& contentFileMap) override; - virtual CellStore *getExterior (int x, int y); + virtual CellStore *getExterior (int x, int y) override; - virtual CellStore *getInterior (const std::string& name); + virtual CellStore *getInterior (const std::string& name) override; - virtual CellStore *getCell (const ESM::CellId& id); + virtual CellStore *getCell (const ESM::CellId& id) override; //switch to POV before showing player's death animation - virtual void useDeathCamera(); + virtual void useDeathCamera() override; - virtual void setWaterHeight(const float height); + virtual void setWaterHeight(const float height) override; - virtual bool toggleWater(); - virtual bool toggleWorld(); + virtual bool toggleWater() override; + virtual bool toggleWorld() override; - virtual void adjustSky(); + virtual void adjustSky() override; - virtual const Fallback::Map *getFallback() const; + virtual const Fallback::Map *getFallback() const override; - virtual Player& getPlayer(); - virtual MWWorld::Ptr getPlayerPtr(); + virtual Player& getPlayer() override; + virtual MWWorld::Ptr getPlayerPtr() override; - virtual const MWWorld::ESMStore& getStore() const; + virtual const MWWorld::ESMStore& getStore() const override; virtual std::vector& getEsmReader(); - virtual LocalScripts& getLocalScripts(); + virtual LocalScripts& getLocalScripts() override; - virtual bool hasCellChanged() const; + virtual bool hasCellChanged() const override; ///< Has the set of active cells changed, since the last frame? - virtual bool isCellExterior() const; + virtual bool isCellExterior() const override; - virtual bool isCellQuasiExterior() const; + virtual bool isCellQuasiExterior() const override; - virtual osg::Vec2f getNorthVector (const CellStore* cell); + virtual osg::Vec2f getNorthVector (const CellStore* cell) override; ///< get north vector for given interior cell - virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); + virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) override; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void setGlobalInt (const std::string& name, int value); + virtual void setGlobalInt (const std::string& name, int value) override; ///< Set value independently from real type. - virtual void setGlobalFloat (const std::string& name, float value); + virtual void setGlobalFloat (const std::string& name, float value) override; ///< Set value independently from real type. - virtual int getGlobalInt (const std::string& name) const; + virtual int getGlobalInt (const std::string& name) const override; ///< Get value independently from real type. - virtual float getGlobalFloat (const std::string& name) const; + virtual float getGlobalFloat (const std::string& name) const override; ///< Get value independently from real type. - virtual char getGlobalVariableType (const std::string& name) const; + virtual char getGlobalVariableType (const std::string& name) const override; ///< Return ' ', if there is no global variable with this name. - virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const; + virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const override; ///< Return name of the cell. /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - virtual void removeRefScript (MWWorld::RefData *ref); + virtual void removeRefScript (MWWorld::RefData *ref) override; //< Remove the script attached to ref from mLocalScripts - virtual Ptr getPtr (const std::string& name, bool activeOnly); + virtual Ptr getPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtr (const std::string& name, bool activeOnly); + virtual Ptr searchPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtrViaActorId (int actorId); + virtual Ptr searchPtrViaActorId (int actorId) override; ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr); + virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override; ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - virtual void adjustPosition (const Ptr& ptr, bool force); + virtual void adjustPosition (const Ptr& ptr, bool force) override; ///< Adjust position after load to be on ground. Must be called after model load. /// @param force do this even if the ptr is flying - virtual void fixPosition (const Ptr& actor); + virtual void fixPosition (const Ptr& actor) override; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. - virtual void enable (const Ptr& ptr); + virtual void enable (const Ptr& ptr) override; - virtual void disable (const Ptr& ptr); + virtual void disable (const Ptr& ptr) override; - virtual void advanceTime (double hours, bool incremental = false); + virtual void advanceTime (double hours, bool incremental = false) override; ///< Advance in-game time. - virtual void setHour (double hour); + virtual void setHour (double hour) override; ///< Set in-game time hour. - virtual void setMonth (int month); + virtual void setMonth (int month) override; ///< Set in-game time month. - virtual void setDay (int day); + virtual void setDay (int day) override; ///< Set in-game time day. - virtual int getDay() const; - virtual int getMonth() const; - virtual int getYear() const; + virtual int getDay() const override; + virtual int getMonth() const override; + virtual int getYear() const override; - virtual std::string getMonthName (int month = -1) const; + virtual std::string getMonthName (int month = -1) const override; ///< Return name of month (-1: current month) - virtual TimeStamp getTimeStamp() const; + virtual TimeStamp getTimeStamp() const override; ///< Return current in-game time stamp. - virtual bool toggleSky(); + virtual bool toggleSky() override; ///< \return Resulting mode - virtual void changeWeather (const std::string& region, const unsigned int id); + virtual void changeWeather (const std::string& region, const unsigned int id) override; - virtual int getCurrentWeather() const; + virtual int getCurrentWeather() const override; - virtual int getMasserPhase() const; + virtual int getMasserPhase() const override; - virtual int getSecundaPhase() const; + virtual int getSecundaPhase() const override; - virtual void setMoonColour (bool red); + virtual void setMoonColour (bool red) override; - virtual void modRegion(const std::string ®ionid, const std::vector &chances); + virtual void modRegion(const std::string ®ionid, const std::vector &chances) override; - virtual float getTimeScaleFactor() const; + virtual float getTimeScaleFactor() const override; - virtual void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true); + virtual void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to interior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true); + virtual void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to exterior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true); + virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual const ESM::Cell *getExterior (const std::string& cellName) const; + virtual const ESM::Cell *getExterior (const std::string& cellName) const override; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. - virtual void markCellAsUnchanged(); + virtual void markCellAsUnchanged() override; - virtual MWWorld::Ptr getFacedObject(); + virtual MWWorld::Ptr getFacedObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - virtual float getDistanceToFacedObject(); + virtual float getDistanceToFacedObject() override; /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets); + virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets) override; /// @note No-op for items in containers. Use ContainerStore::removeItem instead. - virtual void deleteObject (const Ptr& ptr); + virtual void deleteObject (const Ptr& ptr) override; - virtual void undeleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr) override; - virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z) override; ///< @return an updated Ptr in case the Ptr's cell changes - virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; ///< @return an updated Ptr - virtual void scaleObject (const Ptr& ptr, float scale); + virtual void scaleObject (const Ptr& ptr, float scale) override; /// World rotates object, uses radians /// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This /// could be considered a bug, but is needed for MW compatibility. /// \param adjust indicates rotation should be set or adjusted - virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override; - virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); + virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override; ///< Place an object. Makes a copy of the Ptr. - virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance); + virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) override; ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). - virtual float getMaxActivationDistance(); + virtual float getMaxActivationDistance() override; virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) - const; + const override; ///< Convert cell numbers to position. - virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; + virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const override; ///< Convert position to cell numbers - virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity); + virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) override; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. - virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2); + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; ///< cast a Ray and return true if there is an object in the ray path. - virtual bool toggleCollisionMode(); + virtual bool toggleCollisionMode() override; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. ///< \return Resulting mode - virtual bool toggleRenderMode (MWRender::RenderMode mode); + virtual bool toggleRenderMode (MWRender::RenderMode mode) override; ///< Toggle a render mode. ///< \return Resulting mode - virtual const ESM::Potion *createRecord (const ESM::Potion& record); + virtual const ESM::Potion *createRecord (const ESM::Potion& record) override; ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record - virtual const ESM::Spell *createRecord (const ESM::Spell& record); + virtual const ESM::Spell *createRecord (const ESM::Spell& record) override; ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record - virtual const ESM::Class *createRecord (const ESM::Class& record); + virtual const ESM::Class *createRecord (const ESM::Class& record) override; ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record - virtual const ESM::Cell *createRecord (const ESM::Cell& record); + virtual const ESM::Cell *createRecord (const ESM::Cell& record) override; ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record - virtual const ESM::NPC *createRecord(const ESM::NPC &record); + virtual const ESM::NPC *createRecord(const ESM::NPC &record) override; ///< Create a new record (of type npc) in the ESM store. /// \return pointer to created record - virtual const ESM::Armor *createRecord (const ESM::Armor& record); + virtual const ESM::Armor *createRecord (const ESM::Armor& record) override; ///< Create a new record (of type armor) in the ESM store. /// \return pointer to created record - virtual const ESM::Weapon *createRecord (const ESM::Weapon& record); + virtual const ESM::Weapon *createRecord (const ESM::Weapon& record) override; ///< Create a new record (of type weapon) in the ESM store. /// \return pointer to created record - virtual const ESM::Clothing *createRecord (const ESM::Clothing& record); + virtual const ESM::Clothing *createRecord (const ESM::Clothing& record) override; ///< Create a new record (of type clothing) in the ESM store. /// \return pointer to created record - virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record); + virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record) override; ///< Create a new record (of type enchantment) in the ESM store. /// \return pointer to created record - virtual const ESM::Book *createRecord (const ESM::Book& record); + virtual const ESM::Book *createRecord (const ESM::Book& record) override; ///< Create a new record (of type book) in the ESM store. /// \return pointer to created record - virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record); + virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record); + virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual void update (float duration, bool paused); + virtual void update (float duration, bool paused) override; - virtual void updateWindowManager (); + virtual void updateWindowManager () override; - virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount); + virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override; ///< copy and place an object into the gameworld at the specified cursor position /// @param object /// @param cursor X (relative 0-1) /// @param cursor Y (relative 0-1) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount); + virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override; ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object /// @param number of objects to place - virtual bool canPlaceObject(float cursorX, float cursorY); + virtual bool canPlaceObject(float cursorX, float cursorY) override; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings(const Settings::CategorySettingVector& settings); + virtual void processChangedSettings(const Settings::CategorySettingVector& settings) override; - virtual bool isFlying(const MWWorld::Ptr &ptr) const; - virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const; + virtual bool isFlying(const MWWorld::Ptr &ptr) const override; + virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const override; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::ConstPtr &object) const; - virtual bool isSwimming(const MWWorld::ConstPtr &object) const; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; - virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const; - virtual bool isWading(const MWWorld::ConstPtr &object) const; - virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const; - virtual bool isOnGround(const MWWorld::Ptr &ptr) const; + virtual bool isSubmerged(const MWWorld::ConstPtr &object) const override; + virtual bool isSwimming(const MWWorld::ConstPtr &object) const override; + virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const override; + virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const override; + virtual bool isWading(const MWWorld::ConstPtr &object) const override; + virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const override; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const; + virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; - virtual void togglePOV(); + virtual void togglePOV() override; - virtual bool isFirstPerson() const; + virtual bool isFirstPerson() const override; - virtual void togglePreviewMode(bool enable); + virtual void togglePreviewMode(bool enable) override; - virtual bool toggleVanityMode(bool enable); + virtual bool toggleVanityMode(bool enable) override; - virtual void allowVanityMode(bool allow); + virtual void allowVanityMode(bool allow) override; - virtual void togglePlayerLooking(bool enable); + virtual void togglePlayerLooking(bool enable) override; - virtual void changeVanityModeScale(float factor); + virtual void changeVanityModeScale(float factor) override; - virtual bool vanityRotateCamera(float * rot); - virtual void setCameraDistance(float dist, bool adjust = false, bool override = true); + virtual bool vanityRotateCamera(float * rot) override; + virtual void setCameraDistance(float dist, bool adjust = false, bool override = true) override; - virtual void setupPlayer(); - virtual void renderPlayer(); + virtual void setupPlayer() override; + virtual void renderPlayer() override; /// open or close a non-teleport door (depending on current state) - virtual void activateDoor(const MWWorld::Ptr& door); + virtual void activateDoor(const MWWorld::Ptr& door) override; /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState /// @note throws an exception when invoked on a teleport door - virtual void activateDoor(const MWWorld::Ptr& door, int state); + virtual void activateDoor(const MWWorld::Ptr& door, int state) override; - virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object); ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::ConstPtr& object); ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object); ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object); ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); + virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object + virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object + virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object + virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is colliding with \a object + virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond); + virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual float getWindSpeed(); + virtual float getWindSpeed() override; - virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); + virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out); + virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor); + virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false); + virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; - virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); + virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - virtual int canRest(); + virtual int canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n @@ -554,132 +554,132 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo Probably shouldn't be here - virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); - virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const; - virtual void reattachPlayerCamera(); + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; + virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; + virtual void reattachPlayerCamera() override; /// \todo this does not belong here - virtual void screenshot (osg::Image* image, int w, int h); + virtual void screenshot (osg::Image* image, int w, int h) override; /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos); + virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos); + virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). - virtual void enableTeleporting(bool enable); + virtual void enableTeleporting(bool enable) override; /// Returns true if teleport spell effects are allowed. - virtual bool isTeleportingEnabled() const; + virtual bool isTeleportingEnabled() const override; /// Enables or disables use of levitation spell effect. - virtual void enableLevitation(bool enable); + virtual void enableLevitation(bool enable) override; /// Returns true if levitation spell effect is allowed. - virtual bool isLevitationEnabled() const; + virtual bool isLevitationEnabled() const override; - virtual bool getGodModeState(); + virtual bool getGodModeState() override; - virtual bool toggleGodMode(); + virtual bool toggleGodMode() override; - virtual bool toggleScripts(); - virtual bool getScriptsEnabled() const; + virtual bool toggleScripts() override; + virtual bool getScriptsEnabled() const override; /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor * @return true if the spell can be casted (i.e. the animation should start) */ - virtual bool startSpellCast (const MWWorld::Ptr& actor); + virtual bool startSpellCast (const MWWorld::Ptr& actor) override; /** * @brief Cast the actual spell, should be called mid-animation * @param actor */ - virtual void castSpell (const MWWorld::Ptr& actor); + virtual void castSpell (const MWWorld::Ptr& actor) override; virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, - const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); + const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; - virtual const std::vector& getContentFiles() const; + virtual const std::vector& getContentFiles() const override; - virtual void breakInvisibility (const MWWorld::Ptr& actor); + virtual void breakInvisibility (const MWWorld::Ptr& actor) override; // Are we in an exterior or pseudo-exterior cell and it's night? - virtual bool isDark() const; + virtual bool isDark() const override; - virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result); + virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, - const std::string& id); + const std::string& id) override; /// List all references (filtered by \a type) detected by \a ptr. The range /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. /// @note This also works for references in containers. virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, - DetectionType type); + DetectionType type) override; /// Update the value of some globals according to the world state, which may be used by dialogue entries. /// This should be called when initiating a dialogue. - virtual void updateDialogueGlobals(); + virtual void updateDialogueGlobals() override; /// Moves all stolen items from \a ptr to the closest evidence chest. - virtual void confiscateStolenItems(const MWWorld::Ptr& ptr); + virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) override; - virtual void goToJail (); + virtual void goToJail () override; /// Spawn a random creature from a levelled list next to the player - virtual void spawnRandomCreature(const std::string& creatureList); + virtual void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition); + virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); + virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, - const bool fromProjectile=false); + const bool fromProjectile=false) override; - virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); + virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; /// @see MWWorld::WeatherManager::isInStorm - virtual bool isInStorm() const; + virtual bool isInStorm() const override; /// @see MWWorld::WeatherManager::getStormDirection - virtual osg::Vec3f getStormDirection() const; + virtual osg::Vec3f getStormDirection() const override; /// Resets all actors in the current active cells to their original location within that cell. - virtual void resetActors(); + virtual void resetActors() override; - virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const; + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); + virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); + virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; - virtual bool isPlayerInJail() const; + virtual bool isPlayerInJail() const override; /// Return terrain height at \a worldPos position. - virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const; + virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; /// Return physical or rendering half extents of the given actor. - virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const; + virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) - virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr); + virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list - virtual void preloadEffects(const ESM::EffectList* effectList); + virtual void preloadEffects(const ESM::EffectList* effectList) override; }; } From 69da89be3994c6d825bc4d62e399e93b48350465 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 13:05:04 +0100 Subject: [PATCH 435/521] Mark a method I missed out the first time as override --- apps/openmw/mwworld/worldimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c130c9d5b..83b81d22c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -227,7 +227,7 @@ namespace MWWorld virtual const MWWorld::ESMStore& getStore() const override; - virtual std::vector& getEsmReader(); + virtual std::vector& getEsmReader() override; virtual LocalScripts& getLocalScripts() override; From 7440cf37bc96556771f5cf21fc591e8cc9d2505b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 13:37:37 +0100 Subject: [PATCH 436/521] Remove redundant virtual keywords implied by override keywords --- apps/openmw/mwworld/worldimp.hpp | 354 +++++++++++++++---------------- 1 file changed, 177 insertions(+), 177 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 83b81d22c..784c01593 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -191,362 +191,362 @@ namespace MWWorld virtual ~World(); - virtual void startNewGame (bool bypass) override; + void startNewGame (bool bypass) override; ///< \param bypass Bypass regular game start. - virtual void clear() override; + void clear() override; - virtual int countSavedGameRecords() const override; - virtual int countSavedGameCells() const override; + int countSavedGameRecords() const override; + int countSavedGameCells() const override; - virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const override; + void write (ESM::ESMWriter& writer, Loading::Listener& progress) const override; - virtual void readRecord (ESM::ESMReader& reader, uint32_t type, + void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) override; - virtual CellStore *getExterior (int x, int y) override; + CellStore *getExterior (int x, int y) override; - virtual CellStore *getInterior (const std::string& name) override; + CellStore *getInterior (const std::string& name) override; - virtual CellStore *getCell (const ESM::CellId& id) override; + CellStore *getCell (const ESM::CellId& id) override; //switch to POV before showing player's death animation - virtual void useDeathCamera() override; + void useDeathCamera() override; - virtual void setWaterHeight(const float height) override; + void setWaterHeight(const float height) override; - virtual bool toggleWater() override; - virtual bool toggleWorld() override; + bool toggleWater() override; + bool toggleWorld() override; - virtual void adjustSky() override; + void adjustSky() override; - virtual const Fallback::Map *getFallback() const override; + const Fallback::Map *getFallback() const override; - virtual Player& getPlayer() override; - virtual MWWorld::Ptr getPlayerPtr() override; + Player& getPlayer() override; + MWWorld::Ptr getPlayerPtr() override; - virtual const MWWorld::ESMStore& getStore() const override; + const MWWorld::ESMStore& getStore() const override; - virtual std::vector& getEsmReader() override; + std::vector& getEsmReader() override; - virtual LocalScripts& getLocalScripts() override; + LocalScripts& getLocalScripts() override; - virtual bool hasCellChanged() const override; + bool hasCellChanged() const override; ///< Has the set of active cells changed, since the last frame? - virtual bool isCellExterior() const override; + bool isCellExterior() const override; - virtual bool isCellQuasiExterior() const override; + bool isCellQuasiExterior() const override; - virtual osg::Vec2f getNorthVector (const CellStore* cell) override; + osg::Vec2f getNorthVector (const CellStore* cell) override; ///< get north vector for given interior cell - virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) override; + void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) override; ///< get a list of teleport door markers for a given cell, to be displayed on the local map - virtual void setGlobalInt (const std::string& name, int value) override; + void setGlobalInt (const std::string& name, int value) override; ///< Set value independently from real type. - virtual void setGlobalFloat (const std::string& name, float value) override; + void setGlobalFloat (const std::string& name, float value) override; ///< Set value independently from real type. - virtual int getGlobalInt (const std::string& name) const override; + int getGlobalInt (const std::string& name) const override; ///< Get value independently from real type. - virtual float getGlobalFloat (const std::string& name) const override; + float getGlobalFloat (const std::string& name) const override; ///< Get value independently from real type. - virtual char getGlobalVariableType (const std::string& name) const override; + char getGlobalVariableType (const std::string& name) const override; ///< Return ' ', if there is no global variable with this name. - virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const override; + std::string getCellName (const MWWorld::CellStore *cell = 0) const override; ///< Return name of the cell. /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - virtual void removeRefScript (MWWorld::RefData *ref) override; + void removeRefScript (MWWorld::RefData *ref) override; //< Remove the script attached to ref from mLocalScripts - virtual Ptr getPtr (const std::string& name, bool activeOnly) override; + Ptr getPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtr (const std::string& name, bool activeOnly) override; + Ptr searchPtr (const std::string& name, bool activeOnly) override; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. - virtual Ptr searchPtrViaActorId (int actorId) override; + Ptr searchPtrViaActorId (int actorId) override; ///< Search is limited to the active cells. - virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override; + MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override; ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - virtual void adjustPosition (const Ptr& ptr, bool force) override; + void adjustPosition (const Ptr& ptr, bool force) override; ///< Adjust position after load to be on ground. Must be called after model load. /// @param force do this even if the ptr is flying - virtual void fixPosition (const Ptr& actor) override; + void fixPosition (const Ptr& actor) override; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. - virtual void enable (const Ptr& ptr) override; + void enable (const Ptr& ptr) override; - virtual void disable (const Ptr& ptr) override; + void disable (const Ptr& ptr) override; - virtual void advanceTime (double hours, bool incremental = false) override; + void advanceTime (double hours, bool incremental = false) override; ///< Advance in-game time. - virtual void setHour (double hour) override; + void setHour (double hour) override; ///< Set in-game time hour. - virtual void setMonth (int month) override; + void setMonth (int month) override; ///< Set in-game time month. - virtual void setDay (int day) override; + void setDay (int day) override; ///< Set in-game time day. - virtual int getDay() const override; - virtual int getMonth() const override; - virtual int getYear() const override; + int getDay() const override; + int getMonth() const override; + int getYear() const override; - virtual std::string getMonthName (int month = -1) const override; + std::string getMonthName (int month = -1) const override; ///< Return name of month (-1: current month) - virtual TimeStamp getTimeStamp() const override; + TimeStamp getTimeStamp() const override; ///< Return current in-game time stamp. - virtual bool toggleSky() override; + bool toggleSky() override; ///< \return Resulting mode - virtual void changeWeather (const std::string& region, const unsigned int id) override; + void changeWeather (const std::string& region, const unsigned int id) override; - virtual int getCurrentWeather() const override; + int getCurrentWeather() const override; - virtual int getMasserPhase() const override; + int getMasserPhase() const override; - virtual int getSecundaPhase() const override; + int getSecundaPhase() const override; - virtual void setMoonColour (bool red) override; + void setMoonColour (bool red) override; - virtual void modRegion(const std::string ®ionid, const std::vector &chances) override; + void modRegion(const std::string ®ionid, const std::vector &chances) override; - virtual float getTimeScaleFactor() const override; + float getTimeScaleFactor() const override; - virtual void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; + void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to interior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; + void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true) override; ///< Move to exterior cell. ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true) override; + void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true) override; ///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes - virtual const ESM::Cell *getExterior (const std::string& cellName) const override; + const ESM::Cell *getExterior (const std::string& cellName) const override; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. - virtual void markCellAsUnchanged() override; + void markCellAsUnchanged() override; - virtual MWWorld::Ptr getFacedObject() override; + MWWorld::Ptr getFacedObject() override; ///< Return pointer to the object the player is looking at, if it is within activation range - virtual float getDistanceToFacedObject() override; + float getDistanceToFacedObject() override; /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node as a basis. - virtual std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets) override; + std::pair getHitContact(const MWWorld::ConstPtr &ptr, float distance, std::vector &targets) override; /// @note No-op for items in containers. Use ContainerStore::removeItem instead. - virtual void deleteObject (const Ptr& ptr) override; + void deleteObject (const Ptr& ptr) override; - virtual void undeleteObject (const Ptr& ptr) override; + void undeleteObject (const Ptr& ptr) override; - virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z) override; + MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z) override; ///< @return an updated Ptr in case the Ptr's cell changes - virtual MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; + MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; ///< @return an updated Ptr - virtual void scaleObject (const Ptr& ptr, float scale) override; + void scaleObject (const Ptr& ptr, float scale) override; /// World rotates object, uses radians /// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This /// could be considered a bug, but is needed for MW compatibility. /// \param adjust indicates rotation should be set or adjusted - virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override; + void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override; - virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override; + MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override; ///< Place an object. Makes a copy of the Ptr. - virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) override; + MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) override; ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). - virtual float getMaxActivationDistance() override; + float getMaxActivationDistance() override; - virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) + void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const override; ///< Convert cell numbers to position. - virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const override; + void positionToIndex (float x, float y, int &cellX, int &cellY) const override; ///< Convert position to cell numbers - virtual void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) override; + void queueMovement(const Ptr &ptr, const osg::Vec3f &velocity) override; ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. - virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; + bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; ///< cast a Ray and return true if there is an object in the ray path. - virtual bool toggleCollisionMode() override; + bool toggleCollisionMode() override; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. ///< \return Resulting mode - virtual bool toggleRenderMode (MWRender::RenderMode mode) override; + bool toggleRenderMode (MWRender::RenderMode mode) override; ///< Toggle a render mode. ///< \return Resulting mode - virtual const ESM::Potion *createRecord (const ESM::Potion& record) override; + const ESM::Potion *createRecord (const ESM::Potion& record) override; ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record - virtual const ESM::Spell *createRecord (const ESM::Spell& record) override; + const ESM::Spell *createRecord (const ESM::Spell& record) override; ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record - virtual const ESM::Class *createRecord (const ESM::Class& record) override; + const ESM::Class *createRecord (const ESM::Class& record) override; ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record - virtual const ESM::Cell *createRecord (const ESM::Cell& record) override; + const ESM::Cell *createRecord (const ESM::Cell& record) override; ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record - virtual const ESM::NPC *createRecord(const ESM::NPC &record) override; + const ESM::NPC *createRecord(const ESM::NPC &record) override; ///< Create a new record (of type npc) in the ESM store. /// \return pointer to created record - virtual const ESM::Armor *createRecord (const ESM::Armor& record) override; + const ESM::Armor *createRecord (const ESM::Armor& record) override; ///< Create a new record (of type armor) in the ESM store. /// \return pointer to created record - virtual const ESM::Weapon *createRecord (const ESM::Weapon& record) override; + const ESM::Weapon *createRecord (const ESM::Weapon& record) override; ///< Create a new record (of type weapon) in the ESM store. /// \return pointer to created record - virtual const ESM::Clothing *createRecord (const ESM::Clothing& record) override; + const ESM::Clothing *createRecord (const ESM::Clothing& record) override; ///< Create a new record (of type clothing) in the ESM store. /// \return pointer to created record - virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record) override; + const ESM::Enchantment *createRecord (const ESM::Enchantment& record) override; ///< Create a new record (of type enchantment) in the ESM store. /// \return pointer to created record - virtual const ESM::Book *createRecord (const ESM::Book& record) override; + const ESM::Book *createRecord (const ESM::Book& record) override; ///< Create a new record (of type book) in the ESM store. /// \return pointer to created record - virtual const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) override; + const ESM::CreatureLevList *createOverrideRecord (const ESM::CreatureLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) override; + const ESM::ItemLevList *createOverrideRecord (const ESM::ItemLevList& record) override; ///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID. /// \return pointer to created record - virtual void update (float duration, bool paused) override; + void update (float duration, bool paused) override; - virtual void updateWindowManager () override; + void updateWindowManager () override; - virtual MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override; + MWWorld::Ptr placeObject (const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override; ///< copy and place an object into the gameworld at the specified cursor position /// @param object /// @param cursor X (relative 0-1) /// @param cursor Y (relative 0-1) /// @param number of objects to place - virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override; + MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override; ///< copy and place an object into the gameworld at the given actor's position /// @param actor giving the dropped object position /// @param object /// @param number of objects to place - virtual bool canPlaceObject(float cursorX, float cursorY) override; + bool canPlaceObject(float cursorX, float cursorY) override; ///< @return true if it is possible to place on object at specified cursor location - virtual void processChangedSettings(const Settings::CategorySettingVector& settings) override; + void processChangedSettings(const Settings::CategorySettingVector& settings) override; - virtual bool isFlying(const MWWorld::Ptr &ptr) const override; - virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const override; + bool isFlying(const MWWorld::Ptr &ptr) const override; + bool isSlowFalling(const MWWorld::Ptr &ptr) const override; ///Is the head of the creature underwater? - virtual bool isSubmerged(const MWWorld::ConstPtr &object) const override; - virtual bool isSwimming(const MWWorld::ConstPtr &object) const override; - virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const override; - virtual bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const override; - virtual bool isWading(const MWWorld::ConstPtr &object) const override; - virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; - virtual bool isOnGround(const MWWorld::Ptr &ptr) const override; + bool isSubmerged(const MWWorld::ConstPtr &object) const override; + bool isSwimming(const MWWorld::ConstPtr &object) const override; + bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const override; + bool isUnderwater(const MWWorld::ConstPtr &object, const float heightRatio) const override; + bool isWading(const MWWorld::ConstPtr &object) const override; + bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const override; + bool isOnGround(const MWWorld::Ptr &ptr) const override; - virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; + osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const override; - virtual void togglePOV() override; + void togglePOV() override; - virtual bool isFirstPerson() const override; + bool isFirstPerson() const override; - virtual void togglePreviewMode(bool enable) override; + void togglePreviewMode(bool enable) override; - virtual bool toggleVanityMode(bool enable) override; + bool toggleVanityMode(bool enable) override; - virtual void allowVanityMode(bool allow) override; + void allowVanityMode(bool allow) override; - virtual void togglePlayerLooking(bool enable) override; + void togglePlayerLooking(bool enable) override; - virtual void changeVanityModeScale(float factor) override; + void changeVanityModeScale(float factor) override; - virtual bool vanityRotateCamera(float * rot) override; - virtual void setCameraDistance(float dist, bool adjust = false, bool override = true) override; + bool vanityRotateCamera(float * rot) override; + void setCameraDistance(float dist, bool adjust = false, bool override = true) override; - virtual void setupPlayer() override; - virtual void renderPlayer() override; + void setupPlayer() override; + void renderPlayer() override; /// open or close a non-teleport door (depending on current state) - virtual void activateDoor(const MWWorld::Ptr& door) override; + void activateDoor(const MWWorld::Ptr& door) override; /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState /// @note throws an exception when invoked on a teleport door - virtual void activateDoor(const MWWorld::Ptr& door, int state) override; + void activateDoor(const MWWorld::Ptr& door, int state) override; - virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object - virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object - virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object - virtual bool getActorCollidingWith (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is colliding with \a object - virtual void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; + bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object + bool getActorStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is standing on \a object + bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) override; ///< @return true if the player is colliding with \a object + bool getActorCollidingWith (const MWWorld::ConstPtr& object) override; ///< @return true if any actor is colliding with \a object + void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; + void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - virtual float getWindSpeed() override; + float getWindSpeed() override; - virtual void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all containers in active cells owned by this Npc - virtual void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all items in active cells owned by this Npc - virtual bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; + bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; ///< get Line of Sight (morrowind stupid implementation) - virtual float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; + float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; - virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; + void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - virtual int canRest() override; + int canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n @@ -554,132 +554,132 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo Probably shouldn't be here - virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; - virtual const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; - virtual void reattachPlayerCamera() override; + MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; + const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; + void reattachPlayerCamera() override; /// \todo this does not belong here - virtual void screenshot (osg::Image* image, int w, int h) override; + void screenshot (osg::Image* image, int w, int h) override; /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). - virtual void enableTeleporting(bool enable) override; + void enableTeleporting(bool enable) override; /// Returns true if teleport spell effects are allowed. - virtual bool isTeleportingEnabled() const override; + bool isTeleportingEnabled() const override; /// Enables or disables use of levitation spell effect. - virtual void enableLevitation(bool enable) override; + void enableLevitation(bool enable) override; /// Returns true if levitation spell effect is allowed. - virtual bool isLevitationEnabled() const override; + bool isLevitationEnabled() const override; - virtual bool getGodModeState() override; + bool getGodModeState() override; - virtual bool toggleGodMode() override; + bool toggleGodMode() override; - virtual bool toggleScripts() override; - virtual bool getScriptsEnabled() const override; + bool toggleScripts() override; + bool getScriptsEnabled() const override; /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor * @return true if the spell can be casted (i.e. the animation should start) */ - virtual bool startSpellCast (const MWWorld::Ptr& actor) override; + bool startSpellCast (const MWWorld::Ptr& actor) override; /** * @brief Cast the actual spell, should be called mid-animation * @param actor */ - virtual void castSpell (const MWWorld::Ptr& actor) override; + void castSpell (const MWWorld::Ptr& actor) override; - virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; - virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, + void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; + void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; - virtual const std::vector& getContentFiles() const override; + const std::vector& getContentFiles() const override; - virtual void breakInvisibility (const MWWorld::Ptr& actor) override; + void breakInvisibility (const MWWorld::Ptr& actor) override; // Are we in an exterior or pseudo-exterior cell and it's night? - virtual bool isDark() const override; + bool isDark() const override; - virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; + bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case - virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, + void teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) override; /// List all references (filtered by \a type) detected by \a ptr. The range /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. /// @note This also works for references in containers. - virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, + void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, DetectionType type) override; /// Update the value of some globals according to the world state, which may be used by dialogue entries. /// This should be called when initiating a dialogue. - virtual void updateDialogueGlobals() override; + void updateDialogueGlobals() override; /// Moves all stolen items from \a ptr to the closest evidence chest. - virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) override; + void confiscateStolenItems(const MWWorld::Ptr& ptr) override; - virtual void goToJail () override; + void goToJail () override; /// Spawn a random creature from a levelled list next to the player - virtual void spawnRandomCreature(const std::string& creatureList) override; + void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition - virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; + void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; + void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; - virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, + void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, const bool fromProjectile=false) override; - virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; + void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; /// @see MWWorld::WeatherManager::isInStorm - virtual bool isInStorm() const override; + bool isInStorm() const override; /// @see MWWorld::WeatherManager::getStormDirection - virtual osg::Vec3f getStormDirection() const override; + osg::Vec3f getStormDirection() const override; /// Resets all actors in the current active cells to their original location within that cell. - virtual void resetActors() override; + void resetActors() override; - virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; + bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - virtual osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. - virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; - virtual bool isPlayerInJail() const override; + bool isPlayerInJail() const override; /// Return terrain height at \a worldPos position. - virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; + float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; /// Return physical or rendering half extents of the given actor. - virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; + osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) - virtual std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; + std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list - virtual void preloadEffects(const ESM::EffectList* effectList) override; + void preloadEffects(const ESM::EffectList* effectList) override; }; } From 2abff22c08525235d917afc60d79198f4467dfda Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 18 Oct 2017 13:48:31 +0100 Subject: [PATCH 437/521] Make MWWorld::World final to enable compiler optimisations --- apps/openmw/mwworld/worldimp.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 784c01593..d7fec2fec 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -69,7 +69,7 @@ namespace MWWorld /// \brief The game world and its visual representation - class World : public MWBase::World + class World final: public MWBase::World { Resource::ResourceSystem* mResourceSystem; From 9571cd8754d88be35623eddeb19dd79c9d5c2173 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Oct 2017 00:50:57 +0100 Subject: [PATCH 438/521] Switch defaultfilters to be handled by a binary-friendly version of the resource macro --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bf2896da..b47678e7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -329,8 +329,9 @@ endif () configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg "${OpenMW_BINARY_DIR}" "openmw-cs.cfg") -configure_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters - "${OpenMW_BINARY_DIR}" "resources/defaultfilters" COPYONLY) +# Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate. +copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters + "${OpenMW_BINARY_DIR}" "resources/defaultfilters") configure_resource_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt "${OpenMW_BINARY_DIR}" "gamecontrollerdb.txt") From 6d8666d80dc5ac58bd193ea4cf22ebac4034e959 Mon Sep 17 00:00:00 2001 From: Kyle Cooley Date: Wed, 18 Oct 2017 20:21:44 -0400 Subject: [PATCH 439/521] Force new project file when creating new project --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7257b2fe3..7a825ba39 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -288,7 +288,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); - if (!boost::filesystem::exists (mProjectPath)) + if (mNew || !boost::filesystem::exists (mProjectPath)) { boost::filesystem::path customFiltersPath (configuration.getUserDataPath()); customFiltersPath /= "defaultfilters"; From d9fe3aac994f97ae9b69bfb97ad1eb86fdf3a4e8 Mon Sep 17 00:00:00 2001 From: Rhiyo Date: Thu, 19 Oct 2017 22:46:08 +1030 Subject: [PATCH 440/521] fixed new clothing replacing old clothing of same value Found on the bug http://bugs.openmw.org/issues/4165. In original Morrowind, new clothing of the same value wouldn't replace old clothing. Tested with common and expensive clothing by selling to merchants and using the AddItem console command in original Morrowind. In OpenMW, before this change, new clothing of the same value would replace old clothing, tested with the same methods used above. --- apps/openmw/mwworld/inventorystore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 50ee97d1c..3d3c8e4ef 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -340,7 +340,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) if (old.getTypeName() == typeid(ESM::Clothing).name()) { // check value - if (old.getClass().getValue (old) > test.getClass().getValue (test)) + if (old.getClass().getValue (old) >= test.getClass().getValue (test)) // old clothing was more valuable continue; } From 43f94a889016a508273bcc43a8c71ef210f8a2b5 Mon Sep 17 00:00:00 2001 From: lukago Date: Thu, 19 Oct 2017 16:50:04 +0200 Subject: [PATCH 441/521] simplify drag and drop on avatar for potions and ingredients --- apps/openmw/mwgui/inventorywindow.cpp | 19 +++++++++++++++---- apps/openmw/mwgui/inventorywindow.hpp | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 735bf3682..2f3099c09 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -213,11 +213,13 @@ namespace MWGui void InventoryWindow::onItemSelected (int index) { - onItemSelectedFromSourceModel (mSortModel->mapToSource(index)); + onItemSelectedFromSourceModel (mSortModel->mapToSource(index), false); } - void InventoryWindow::onItemSelectedFromSourceModel (int index) + void InventoryWindow::onItemSelectedFromSourceModel (int index, bool takeMaxItemCount) { + mLastItemIndex = index; + if (mDragAndDrop->mIsOnDragAndDrop) { mDragAndDrop->drop(mTradeModel, mItemView); @@ -230,7 +232,8 @@ namespace MWGui MWWorld::Ptr object = item.mBase; int count = item.mCount; - bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); + bool shift = takeMaxItemCount ? true : MyGUI::InputManager::getInstance().isShiftPressed(); + if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -528,6 +531,8 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; + int itemType = ptr.getContainerStore()->getType(ptr); + mDragAndDrop->finish(); if (mDragAndDrop->mSourceModel != mTradeModel) @@ -536,6 +541,12 @@ namespace MWGui ptr = mDragAndDrop->mSourceModel->moveItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel); } useItem(ptr); + + if ((itemType == MWWorld::ContainerStore::Type_Ingredient || itemType == MWWorld::ContainerStore::Type_Potion) && mDragAndDrop->mDraggedCount > 1) + { + onItemSelectedFromSourceModel(mLastItemIndex, true); + } + } else { @@ -550,7 +561,7 @@ namespace MWGui { if (mTradeModel->getItem(i).mBase == itemSelected) { - onItemSelectedFromSourceModel(i); + onItemSelectedFromSourceModel(i, false); return; } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 5576b52ed..dde46558f 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -69,6 +69,7 @@ namespace MWGui DragAndDrop* mDragAndDrop; int mSelectedItem; + int mLastItemIndex; MWWorld::Ptr mPtr; @@ -103,7 +104,7 @@ namespace MWGui bool mTrading; void onItemSelected(int index); - void onItemSelectedFromSourceModel(int index); + void onItemSelectedFromSourceModel(int index, bool takeMaxCount); void onBackgroundSelected(); From f3e6b26e6bcda2c0899e3549e62722ac24d8688b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Oct 2017 16:34:11 +0100 Subject: [PATCH 442/521] Tidy up indentation --- apps/openmw/mwworld/worldimp.hpp | 98 ++++++++++++++++---------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d7fec2fec..5b772b4b1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -528,25 +528,25 @@ namespace MWWorld void hurtStandingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors standing on \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; + void hurtCollidingActors (const MWWorld::ConstPtr& object, float dmgPerSecond) override; ///< Apply a health difference to any actors colliding with \a object. /// To hurt actors, healthPerSecond should be a positive value. For a negative value, actors will be healed. - float getWindSpeed() override; + float getWindSpeed() override; - void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getContainersOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all containers in active cells owned by this Npc - void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; + void getItemsOwnedBy (const MWWorld::ConstPtr& npc, std::vector& out) override; ///< get all items in active cells owned by this Npc - bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; + bool getLOS(const MWWorld::ConstPtr& actor,const MWWorld::ConstPtr& targetActor) override; ///< get Line of Sight (morrowind stupid implementation) - float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; + float getDistToNearestRayHit(const osg::Vec3f& from, const osg::Vec3f& dir, float maxDist, bool includeWater = false) override; - void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; + void enableActorCollision(const MWWorld::Ptr& actor, bool enable) override; - int canRest() override; + int canRest() override; ///< check if the player is allowed to rest \n /// 0 - yes \n /// 1 - only waiting \n @@ -554,132 +554,132 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo Probably shouldn't be here - MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; - const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; - void reattachPlayerCamera() override; + MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override; + const MWRender::Animation* getAnimation(const MWWorld::ConstPtr &ptr) const override; + void reattachPlayerCamera() override; /// \todo this does not belong here - void screenshot (osg::Image* image, int w, int h) override; + void screenshot (osg::Image* image, int w, int h) override; /// Find center of exterior cell above land surface /// \return false if exterior with given name not exists, true otherwise - bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findExteriorPosition(const std::string &name, ESM::Position &pos) override; /// Find position in interior cell near door entrance /// \return false if interior with given name not exists, true otherwise - bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; + bool findInteriorPosition(const std::string &name, ESM::Position &pos) override; /// Enables or disables use of teleport spell effects (recall, intervention, etc). - void enableTeleporting(bool enable) override; + void enableTeleporting(bool enable) override; /// Returns true if teleport spell effects are allowed. - bool isTeleportingEnabled() const override; + bool isTeleportingEnabled() const override; /// Enables or disables use of levitation spell effect. - void enableLevitation(bool enable) override; + void enableLevitation(bool enable) override; /// Returns true if levitation spell effect is allowed. - bool isLevitationEnabled() const override; + bool isLevitationEnabled() const override; - bool getGodModeState() override; + bool getGodModeState() override; - bool toggleGodMode() override; + bool toggleGodMode() override; - bool toggleScripts() override; - bool getScriptsEnabled() const override; + bool toggleScripts() override; + bool getScriptsEnabled() const override; /** * @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met. * @param actor * @return true if the spell can be casted (i.e. the animation should start) */ - bool startSpellCast (const MWWorld::Ptr& actor) override; + bool startSpellCast (const MWWorld::Ptr& actor) override; /** * @brief Cast the actual spell, should be called mid-animation * @param actor */ - void castSpell (const MWWorld::Ptr& actor) override; + void castSpell (const MWWorld::Ptr& actor) override; - void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; - void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, + void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; + void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; - const std::vector& getContentFiles() const override; + const std::vector& getContentFiles() const override; - void breakInvisibility (const MWWorld::Ptr& actor) override; + void breakInvisibility (const MWWorld::Ptr& actor) override; // Are we in an exterior or pseudo-exterior cell and it's night? - bool isDark() const override; + bool isDark() const override; - bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; + bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// @note id must be lower case - void teleportToClosestMarker (const MWWorld::Ptr& ptr, + void teleportToClosestMarker (const MWWorld::Ptr& ptr, const std::string& id) override; /// List all references (filtered by \a type) detected by \a ptr. The range /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. /// @note This also works for references in containers. - void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, + void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, DetectionType type) override; /// Update the value of some globals according to the world state, which may be used by dialogue entries. /// This should be called when initiating a dialogue. - void updateDialogueGlobals() override; + void updateDialogueGlobals() override; /// Moves all stolen items from \a ptr to the closest evidence chest. - void confiscateStolenItems(const MWWorld::Ptr& ptr) override; + void confiscateStolenItems(const MWWorld::Ptr& ptr) override; - void goToJail () override; + void goToJail () override; /// Spawn a random creature from a levelled list next to the player void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition - void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; + void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; - void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; + void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) override; - void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, + void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName, const bool fromProjectile=false) override; - void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; + void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) override; /// @see MWWorld::WeatherManager::isInStorm - bool isInStorm() const override; + bool isInStorm() const override; /// @see MWWorld::WeatherManager::getStormDirection - osg::Vec3f getStormDirection() const override; + osg::Vec3f getStormDirection() const override; /// Resets all actors in the current active cells to their original location within that cell. - void resetActors() override; + void resetActors() override; - bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; + bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const override; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. - float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; - bool isPlayerInJail() const override; + bool isPlayerInJail() const override; /// Return terrain height at \a worldPos position. - float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; + float getTerrainHeightAt(const osg::Vec3f& worldPos) const override; /// Return physical or rendering half extents of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; + osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const override; /// Export scene graph to a file and return the filename. /// \param ptr object to export scene graph for (if empty, export entire scene graph) - std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; + std::string exportSceneGraph(const MWWorld::Ptr& ptr) override; /// Preload VFX associated with this effect list - void preloadEffects(const ESM::EffectList* effectList) override; + void preloadEffects(const ESM::EffectList* effectList) override; }; } From 03fc3353b9e3d1f9a7ebad673f96841140a77e4f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Oct 2017 16:34:50 +0100 Subject: [PATCH 443/521] Tidy up indentation 2 --- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5b772b4b1..7af7b2968 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -635,7 +635,7 @@ namespace MWWorld void goToJail () override; /// Spawn a random creature from a levelled list next to the player - void spawnRandomCreature(const std::string& creatureList) override; + void spawnRandomCreature(const std::string& creatureList) override; /// Spawn a blood effect for \a ptr at \a worldPosition void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; @@ -661,7 +661,7 @@ namespace MWWorld /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. - osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; + osg::Vec3f aimToTarget(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; /// Return the distance between actor's weapon and target's collision box. float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) override; From a3225364ff2e689ff43c3f93b3961c91b0b505c0 Mon Sep 17 00:00:00 2001 From: lukago Date: Thu, 19 Oct 2017 17:17:14 +0200 Subject: [PATCH 444/521] refactor, use dragItem method --- apps/openmw/mwgui/inventorywindow.cpp | 22 ++++++++++------------ apps/openmw/mwgui/inventorywindow.hpp | 3 +-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 2f3099c09..d0af00e5f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,7 +1,5 @@ #include "inventorywindow.hpp" -#include - #include #include #include @@ -26,7 +24,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" #include "../mwscript/interpretercontext.hpp" -#include "../mwrender/characterpreview.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -213,13 +210,11 @@ namespace MWGui void InventoryWindow::onItemSelected (int index) { - onItemSelectedFromSourceModel (mSortModel->mapToSource(index), false); + onItemSelectedFromSourceModel (mSortModel->mapToSource(index)); } - void InventoryWindow::onItemSelectedFromSourceModel (int index, bool takeMaxItemCount) + void InventoryWindow::onItemSelectedFromSourceModel (int index) { - mLastItemIndex = index; - if (mDragAndDrop->mIsOnDragAndDrop) { mDragAndDrop->drop(mTradeModel, mItemView); @@ -230,10 +225,9 @@ namespace MWGui std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); MWWorld::Ptr object = item.mBase; + bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); int count = item.mCount; - bool shift = takeMaxItemCount ? true : MyGUI::InputManager::getInstance().isShiftPressed(); - if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -540,11 +534,15 @@ namespace MWGui // Move item to the player's inventory ptr = mDragAndDrop->mSourceModel->moveItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel); } + useItem(ptr); - if ((itemType == MWWorld::ContainerStore::Type_Ingredient || itemType == MWWorld::ContainerStore::Type_Potion) && mDragAndDrop->mDraggedCount > 1) + // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 item + if ((itemType == MWWorld::ContainerStore::Type_Ingredient + || itemType == MWWorld::ContainerStore::Type_Potion) + && mDragAndDrop->mDraggedCount > 1) { - onItemSelectedFromSourceModel(mLastItemIndex, true); + dragItem (nullptr, mDragAndDrop->mDraggedCount - 1); } } @@ -561,7 +559,7 @@ namespace MWGui { if (mTradeModel->getItem(i).mBase == itemSelected) { - onItemSelectedFromSourceModel(i, false); + onItemSelectedFromSourceModel(i); return; } } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index dde46558f..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -69,7 +69,6 @@ namespace MWGui DragAndDrop* mDragAndDrop; int mSelectedItem; - int mLastItemIndex; MWWorld::Ptr mPtr; @@ -104,7 +103,7 @@ namespace MWGui bool mTrading; void onItemSelected(int index); - void onItemSelectedFromSourceModel(int index, bool takeMaxCount); + void onItemSelectedFromSourceModel(int index); void onBackgroundSelected(); From e64f14b7ce07fabc0b31e7557f0b4003ed2a3df2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 20 Oct 2017 23:05:12 +0400 Subject: [PATCH 445/521] Do not replace an equpped ring of the same value --- apps/openmw/mwworld/inventorystore.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3d3c8e4ef..ba3ea2381 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -330,10 +330,8 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) Ptr rightRing = *slots_.at(Slot_RightRing); // we want to swap cheaper ring only if both are equipped - if (rightRing.getClass().getValue(rightRing) < old.getClass().getValue(old)) - { + if (old.getClass().getValue (old) >= rightRing.getClass().getValue (rightRing)) continue; - } } } From eaff7e30aa052f311a7c8e00b85d9aa50004016f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 21 Oct 2017 16:56:21 +0400 Subject: [PATCH 446/521] Fix a 'Good Beast' companion window --- apps/openmw/mwgui/dialogue.cpp | 13 +++++++++---- apps/openmw/mwgui/dialogue.hpp | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e13e626ae..39c73a23d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -391,8 +391,8 @@ namespace MWGui // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); - if (isCompanion()) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr); + if (isCompanion(actor)) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, actor); return; } @@ -698,8 +698,13 @@ namespace MWGui bool DialogueWindow::isCompanion() { - return !mPtr.getClass().getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); + return isCompanion(mPtr); + } + + bool DialogueWindow::isCompanion(const MWWorld::Ptr& actor) + { + return !actor.getClass().getScript(actor).empty() + && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5e362e9b5..472996a6c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -133,6 +133,7 @@ namespace MWGui protected: void updateTopics(); void updateTopicsPane(); + bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); void onPersuadeResult(const std::string& title, const std::string& text); From b6cb3b445cb5406b3c06d48c54fc1427d426d1bf Mon Sep 17 00:00:00 2001 From: lukago Date: Fri, 20 Oct 2017 01:10:17 +0200 Subject: [PATCH 447/521] use getIndex to handle other windows, nullsafe fixes --- apps/openmw/mwgui/inventorywindow.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index d0af00e5f..b3697008c 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,5 +1,7 @@ #include "inventorywindow.hpp" +#include + #include #include #include @@ -225,8 +227,8 @@ namespace MWGui std::string sound = item.mBase.getClass().getDownSoundId(item.mBase); MWWorld::Ptr object = item.mBase; - bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); int count = item.mCount; + bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -525,7 +527,6 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) { MWWorld::Ptr ptr = mDragAndDrop->mItem.mBase; - int itemType = ptr.getContainerStore()->getType(ptr); mDragAndDrop->finish(); @@ -538,13 +539,15 @@ namespace MWGui useItem(ptr); // If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 item - if ((itemType == MWWorld::ContainerStore::Type_Ingredient - || itemType == MWWorld::ContainerStore::Type_Potion) + if ((ptr.getTypeName() == typeid(ESM::Potion).name() || + ptr.getTypeName() == typeid(ESM::Ingredient).name()) && mDragAndDrop->mDraggedCount > 1) { - dragItem (nullptr, mDragAndDrop->mDraggedCount - 1); + // Item can be provided from other window for example container. + // But after DragAndDrop::startDrag item automaticly always gets to player inventory. + mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem); + dragItem(nullptr, mDragAndDrop->mDraggedCount - 1); } - } else { From 46b015d3d93fdc03eddbb8dd725b36e9671adcae Mon Sep 17 00:00:00 2001 From: Marcin Baszczewski Date: Sun, 22 Oct 2017 10:10:04 +0200 Subject: [PATCH 448/521] Fix assert with empty setting value Local value could be empty, so it's important to check it size before read first char. --- components/config/gamesettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 0ea28dceb..b35612ee4 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -63,7 +63,7 @@ void Config::GameSettings::validatePaths() // Do the same for data-local QString local = mSettings.value(QString("data-local")); - if (local.at(0) == QChar('\"')) + if (local.length() && local.at(0) == QChar('\"')) { local.remove(0, 1); local.chop(1); From 768da57da2163af5806efb8206aee4006bb58e96 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 22 Oct 2017 19:06:47 +0200 Subject: [PATCH 449/521] Fix dialogue topics displayed in lower case --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 5 ++--- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 6fac03e92..acfe7f5ee 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -325,8 +325,7 @@ namespace MWDialogue { if (filter.responseAvailable (*iter)) { - std::string lower = Misc::StringUtils::lowerCase(iter->mId); - mActorKnownTopics.insert (lower); + mActorKnownTopics.insert (iter->mId); } } } @@ -342,7 +341,7 @@ namespace MWDialogue for (const std::string& topic : mActorKnownTopics) { //does the player know the topic? - if (mKnownTopics.count(Misc::StringUtils::lowerCase(topic))) + if (mKnownTopics.count(topic)) keywordList.push_back(topic); } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index d9c622120..a914d9a3e 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -22,13 +23,13 @@ namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - std::set mKnownTopics;// Those are the topics the player knows. + std::set mKnownTopics;// Those are the topics the player knows. // Modified faction reactions. > typedef std::map > ModFactionReactionMap; ModFactionReactionMap mChangedFactionReaction; - std::set mActorKnownTopics; + std::set mActorKnownTopics; Translation::Storage& mTranslationDataStorage; MWScript::CompilerContext mCompilerContext; From 3d0094bd2e7cb4e0ee5929f3f1d909c18d4d33ff Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 22 Oct 2017 19:30:55 +0200 Subject: [PATCH 450/521] Fix behavior of 'journal' command when invoked with already seen entry --- apps/openmw/mwdialogue/journalimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 27a3b31b5..41eaed080 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -77,11 +77,15 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index, const MWWorld::Ptr& actor) { - // bail out of we already have heard this... + // bail out if we already have heard this... std::string infoId = JournalEntry::idFromIndex (id, index); for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i) if (i->mTopic == id && i->mInfoId == infoId) + { + setJournalIndex(id, index); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}"); return; + } StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index, actor); From 32bdd500afde5cfc9c7825ad2b1884896c6978c8 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 22 Oct 2017 23:13:01 +0200 Subject: [PATCH 451/521] Updating OSG packages to 3.4.1 --- CI/before_script.msvc.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index a7f30d7ed..39cb37bed 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -330,9 +330,9 @@ if [ -z $SKIP_DOWNLOAD ]; then "OpenAL-Soft-1.17.2.zip" # OSG - download "OpenSceneGraph 3.4.0-scrawl" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" + download "OpenSceneGraph 3.4.1-scrawl" \ + "http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" # Qt if [ -z $APPVEYOR ]; then @@ -527,20 +527,20 @@ cd $DEPS echo # OSG -printf "OSG 3.4.0-scrawl... " +printf "OSG 3.4.1-scrawl... " { cd $DEPS_INSTALL if [ -d OSG ] && \ grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \ - grep "OPENSCENEGRAPH_PATCH_VERSION 0" OSG/include/osg/Version > /dev/null + grep "OPENSCENEGRAPH_PATCH_VERSION 1" OSG/include/osg/Version > /dev/null then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf OSG - eval 7z x -y "${DEPS}/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG + eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP + mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG fi OSG_SDK="$(real_pwd)/OSG" @@ -556,8 +556,8 @@ printf "OSG 3.4.0-scrawl... " add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${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_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll echo Done. } @@ -717,10 +717,10 @@ if [ -z $CI ]; then echo echo "- OSG Plugin DLLs..." - mkdir -p $BUILD_CONFIG/osgPlugins-3.4.0 + mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1 for DLL in $OSG_PLUGINS; do echo " $(basename $DLL)." - cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.0 + cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1 done echo From 2a0b2c4e2485ca4e08ec1d440f515a0d77808a9d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 23 Oct 2017 23:31:59 +0200 Subject: [PATCH 452/521] Hide modal window before deleting it (Fixes #4168) --- apps/openmw/mwgui/messagebox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 376a28aa7..7c89c4979 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -126,6 +126,7 @@ namespace MWGui if (mInterMessageBoxe != NULL) { std::cerr << "Warning: replacing an interactive message box that was not answered yet" << std::endl; + mInterMessageBoxe->setVisible(false); delete mInterMessageBoxe; mInterMessageBoxe = NULL; } From e564dd842e79f8518b6b336054867e0f8435d10b Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 24 Oct 2017 00:25:41 +0200 Subject: [PATCH 453/521] Refactor dialogue responses to make sure messages from scripts are printer afterwards, not before the dialogue response (Fixes #4166) Don't delete Link objects prematurely (Fixes #4171) --- apps/openmw/mwbase/dialoguemanager.hpp | 17 ++-- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 30 +++--- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 12 +-- apps/openmw/mwgui/dialogue.cpp | 93 ++++++++++--------- apps/openmw/mwgui/dialogue.hpp | 13 ++- 5 files changed, 86 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index c928fa940..a9afae786 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -36,6 +36,12 @@ namespace MWBase public: + class ResponseCallback + { + public: + virtual void addResponse(const std::string& title, const std::string& text) = 0; + }; + DialogueManager() {} virtual void clear() = 0; @@ -44,8 +50,7 @@ namespace MWBase virtual bool isInChoice() const = 0; - typedef std::pair Response; // title, text - virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response) = 0; + virtual bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) = 0; virtual void addTopic (const std::string& topic) = 0; @@ -58,15 +63,15 @@ namespace MWBase virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0; - virtual Response keywordSelected (const std::string& keyword) = 0; + virtual void keywordSelected (const std::string& keyword, ResponseCallback* callback) = 0; virtual void goodbyeSelected() = 0; - virtual Response questionAnswered (int answer) = 0; + virtual void questionAnswered (int answer, ResponseCallback* callback) = 0; virtual std::list getAvailableTopics() = 0; - virtual bool checkServiceRefused (Response& response) = 0; + virtual bool checkServiceRefused (ResponseCallback* callback) = 0; - virtual Response persuade (int type) = 0; + virtual void persuade (int type, ResponseCallback* callback) = 0; virtual int getTemporaryDispositionChange () const = 0; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index acfe7f5ee..88e65e535 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -101,7 +101,7 @@ namespace MWDialogue } } - bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, Response& response) + bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback) { updateGlobals(); @@ -151,7 +151,7 @@ namespace MWDialogue parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response ("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; @@ -240,9 +240,8 @@ namespace MWDialogue } } - DialogueManager::Response DialogueManager::executeTopic (const std::string& topic) + void DialogueManager::executeTopic (const std::string& topic, ResponseCallback* callback) { - DialogueManager::Response response; Filter filter (mActor, mChoice, mTalkedTo); const MWWorld::Store &dialogues = @@ -274,7 +273,7 @@ namespace MWDialogue title = topic; MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); if (dialogue.mType == ESM::Dialogue::Topic) { @@ -295,7 +294,6 @@ namespace MWDialogue mLastTopic = topic; } - return response; } const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id) @@ -350,18 +348,16 @@ namespace MWDialogue return keywordList; } - DialogueManager::Response DialogueManager::keywordSelected (const std::string& keyword) + void DialogueManager::keywordSelected (const std::string& keyword, ResponseCallback* callback) { - Response response; if(!mIsInChoice) { const ESM::Dialogue* dialogue = searchDialogue(keyword); if (dialogue && dialogue->mType == ESM::Dialogue::Topic) { - response = executeTopic (keyword); + executeTopic (keyword, callback); } } - return response; } bool DialogueManager::isInChoice() const @@ -386,10 +382,9 @@ namespace MWDialogue mTemporaryDispositionChange = 0; } - DialogueManager::Response DialogueManager::questionAnswered (int answer) + void DialogueManager::questionAnswered (int answer, ResponseCallback* callback) { mChoice = answer; - DialogueManager::Response response; const ESM::Dialogue* dialogue = searchDialogue(mLastTopic); if (dialogue) @@ -408,7 +403,7 @@ namespace MWDialogue mChoices.clear(); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response("", Interpreter::fixDefinesDialog(text, interpreterContext)); + callback->addResponse("", Interpreter::fixDefinesDialog(text, interpreterContext)); // Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group, // in which case it should not be added to the journal. @@ -434,7 +429,6 @@ namespace MWDialogue } updateActorKnownTopics(); - return response; } void DialogueManager::addChoice (const std::string& text, int choice) @@ -460,7 +454,7 @@ namespace MWDialogue mGoodbye = true; } - DialogueManager::Response DialogueManager::persuade(int type) + void DialogueManager::persuade(int type, ResponseCallback* callback) { bool success; float temp, perm; @@ -509,7 +503,7 @@ namespace MWDialogue text = "Bribe"; } - return executeTopic (text + (success ? " Success" : " Fail")); + executeTopic (text + (success ? " Success" : " Fail"), callback); } int DialogueManager::getTemporaryDispositionChange() const @@ -522,7 +516,7 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } - bool DialogueManager::checkServiceRefused(Response& response) + bool DialogueManager::checkServiceRefused(ResponseCallback* callback) { Filter filter (mActor, mChoice, mTalkedTo); @@ -543,7 +537,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); - response = Response(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + callback->addResponse(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); return true; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index a914d9a3e..f267f7542 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -57,7 +57,7 @@ namespace MWDialogue bool compile (const std::string& cmd, std::vector& code, const MWWorld::Ptr& actor); void executeScript (const std::string& script, const MWWorld::Ptr& actor); - Response executeTopic (const std::string& topic); + void executeTopic (const std::string& topic, ResponseCallback* callback); const ESM::Dialogue* searchDialogue(const std::string& id); @@ -69,7 +69,7 @@ namespace MWDialogue virtual bool isInChoice() const; - virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response); + virtual bool startDialogue (const MWWorld::Ptr& actor, ResponseCallback* callback); std::list getAvailableTopics(); @@ -82,16 +82,16 @@ namespace MWDialogue virtual void goodbye(); - virtual bool checkServiceRefused (Response& response); + virtual bool checkServiceRefused (ResponseCallback* callback); virtual void say(const MWWorld::Ptr &actor, const std::string &topic); //calbacks for the GUI - virtual Response keywordSelected (const std::string& keyword); + virtual void keywordSelected (const std::string& keyword, ResponseCallback* callback); virtual void goodbyeSelected(); - virtual Response questionAnswered (int answer); + virtual void questionAnswered (int answer, ResponseCallback* callback); - virtual Response persuade (int type); + virtual void persuade (int type, ResponseCallback* callback); virtual int getTemporaryDispositionChange () const; /// @note This change is temporary and gets discarded when dialogue ends. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 39c73a23d..8a7ae85ea 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -30,8 +30,29 @@ namespace MWGui { - PersuasionDialog::PersuasionDialog() + class ResponseCallback : public MWBase::DialogueManager::ResponseCallback + { + public: + ResponseCallback(DialogueWindow* win, bool needMargin=true) + : mWindow(win) + , mNeedMargin(needMargin) + { + + } + + void addResponse(const std::string& title, const std::string& text) + { + mWindow->addResponse(title, text, mNeedMargin); + } + + private: + DialogueWindow* mWindow; + bool mNeedMargin; + }; + + PersuasionDialog::PersuasionDialog(ResponseCallback* callback) : WindowModal("openmw_persuasion_dialog.layout") + , mCallback(callback) { getWidget(mCancelButton, "CancelButton"); getWidget(mAdmireButton, "AdmireButton"); @@ -69,9 +90,7 @@ namespace MWGui else /*if (sender == mBribe1000Button)*/ type = MWBase::MechanicsManager::PT_Bribe1000; - MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->persuade(type); - - eventPersuadeMsg(response.first, response.second); + MWBase::Environment::get().getDialogueManager()->persuade(type, mCallback.get()); setVisible(false); } @@ -244,13 +263,14 @@ namespace MWGui : WindowBase("openmw_dialogue_window.layout") , mIsCompanion(false) , mGoodbye(false) - , mPersuasionDialog() + , mPersuasionDialog(new ResponseCallback(this)) + , mCallback(new ResponseCallback(this)) + , mGreetingCallback(new ResponseCallback(this, false)) { // Centre dialog center(); mPersuasionDialog.setVisible(false); - mPersuasionDialog.eventPersuadeMsg += MyGUI::newDelegate(this, &DialogueWindow::onPersuadeResult); //History view getWidget(mHistory, "History"); @@ -277,8 +297,6 @@ namespace MWGui DialogueWindow::~DialogueWindow() { - mPersuasionDialog.eventPersuadeMsg.clear(); - deleteLater(); for (Link* link : mLinks) delete link; @@ -356,12 +374,11 @@ namespace MWGui const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - MWBase::DialogueManager::Response response; if (topic == gmst.find("sPersuasion")->getString()) mPersuasionDialog.setVisible(true); else if (topic == gmst.find("sCompanionShare")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr); - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(response)) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(mCallback.get())) { if (topic == gmst.find("sBarter")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr); @@ -378,19 +395,34 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } - else - addResponse(response.first, response.second); } } void DialogueWindow::setPtr(const MWWorld::Ptr& actor) { - MWBase::DialogueManager::Response response; - if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, response)) + bool sameActor = (mPtr == actor); + if (!sameActor) + { + for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) + delete (*it); + 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 + mLinks.clear(); + } + + mPtr = actor; + mGoodbye = false; + mTopicsList->setEnabled(true); + + if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, mGreetingCallback.get())) { // No greetings found. The dialogue window should not be shown. // If this is a companion, we must show the companion window directly (used by BM_bear_be_unique). MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + mPtr = MWWorld::Ptr(); if (isCompanion(actor)) MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, actor); return; @@ -398,32 +430,11 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton); - mGoodbye = false; - bool sameActor = (mPtr == actor); - mPtr = actor; - mTopicsList->setEnabled(true); setTitle(mPtr.getClass().getName(mPtr)); - mTopicsList->clear(); - - if (!sameActor) - { - for (std::vector::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it) - delete (*it); - mHistoryContents.clear(); - - mKeywords.clear(); - updateTopicsPane(); - } - - 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 - mLinks.clear(); - + updateTopicsPane(); updateDisposition(); restock(); - - addResponse(response.first, response.second, false); } void DialogueWindow::restock() @@ -608,14 +619,12 @@ namespace MWGui void DialogueWindow::onTopicActivated(const std::string &topicId) { - MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId); - addResponse(response.first, response.second); + MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get()); } void DialogueWindow::onChoiceActivated(int id) { - MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id); - addResponse(response.first, response.second); + MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); } void DialogueWindow::onGoodbyeActivated() @@ -707,8 +716,4 @@ namespace MWGui && actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"); } - void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text) - { - addResponse(title, text); - } } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 472996a6c..277032513 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -22,19 +22,20 @@ namespace MWGui namespace MWGui { + class ResponseCallback; + class PersuasionDialog : public WindowModal { public: - PersuasionDialog(); - - typedef MyGUI::delegates::CMultiDelegate2 EventHandle_Result; - EventHandle_Result eventPersuadeMsg; + PersuasionDialog(ResponseCallback* callback); virtual void onOpen(); virtual MyGUI::Widget* getDefaultKeyFocus(); private: + std::unique_ptr mCallback; + MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; MyGUI::Button* mIntimidateButton; @@ -136,7 +137,6 @@ namespace MWGui bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); - void onPersuadeResult(const std::string& title, const std::string& text); void onSelectListItem(const std::string& topic, int id); void onByeClicked(MyGUI::Widget* _sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); @@ -180,6 +180,9 @@ namespace MWGui PersuasionDialog mPersuasionDialog; MyGUI::IntSize mCurrentWindowSize; + + std::unique_ptr mCallback; + std::unique_ptr mGreetingCallback; }; } #endif From 0c6ef17fb56babe42343bff7a3bc5d4f611b0767 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 24 Oct 2017 00:40:17 +0200 Subject: [PATCH 454/521] Add explicit variant of 'OnActivate' --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/miscextensions.cpp | 9 ++++----- components/compiler/extensions0.cpp | 2 +- components/compiler/opcodes.hpp | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 851a6a29c..e999097db 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -453,5 +453,6 @@ op 0x2000302: Fixme op 0x2000303: Fixme, explicit op 0x2000304: Show op 0x2000305: Show, explicit +op 0x2000306: OnActivate, explicit -opcodes 0x2000304-0x3ffffff unused +opcodes 0x2000307-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 98b1a6b47..1067b5536 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -131,16 +131,14 @@ namespace MWScript } }; + template class OpOnActivate : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - MWWorld::Ptr ptr = context.getReference(); + MWWorld::Ptr ptr = R()(runtime); runtime.push (ptr.getRefData().onActivate()); } @@ -1280,7 +1278,8 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); - interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate); + interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate); + interpreter.installSegment5 (Compiler::Misc::opcodeOnActivateExplicit, new OpOnActivate); interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate); interpreter.installSegment5 (Compiler::Misc::opcodeActivateExplicit, new OpActivate); interpreter.installSegment3 (Compiler::Misc::opcodeLock, new OpLock); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index eb3e1e4ee..cd5bf7ef7 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -240,7 +240,7 @@ namespace Compiler void registerExtensions (Extensions& extensions) { extensions.registerFunction ("xbox", 'l', "", opcodeXBox); - extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate); + extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate, opcodeOnActivateExplicit); extensions.registerInstruction ("activate", "x", opcodeActivate, opcodeActivateExplicit); extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit); extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index b2333032b..6a6552467 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -200,6 +200,7 @@ namespace Compiler { const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; + const int opcodeOnActivateExplicit = 0x2000306; const int opcodeActivate = 0x2000075; const int opcodeActivateExplicit = 0x2000244; const int opcodeLock = 0x20004; From 3731e2022887024758c80725f6c85d15e5463303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 24 Oct 2017 14:12:41 +0200 Subject: [PATCH 455/521] fix rain ripple regression --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/water.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6c4cc802b..4fbcdc4d5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -252,6 +252,7 @@ namespace MWRender sceneRoot->setName("Scene Root"); mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); + mSky->setCamera(mViewer->getCamera()); mSky->setRainIntensityUniform(mWater->getRainIntensityUniform()); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 52b659984..c4dffb7a4 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -416,9 +416,9 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem setHeight(mTop); - updateWaterMaterial(); - mRainIntensityUniform = new osg::Uniform("rainIntensity",(float) 0.0); + + updateWaterMaterial(); } osg::Uniform *Water::getRainIntensityUniform() @@ -517,6 +517,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R osg::ref_ptr fragmentShader (shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT)); osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); + if (normalMap->getImage()) normalMap->getImage()->flipVertical(); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); @@ -531,6 +532,7 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON); shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON); + if (refraction) { shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON); @@ -552,13 +554,13 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + shaderStateset->addUniform(mRainIntensityUniform.get()); + osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - shaderStateset->addUniform(mRainIntensityUniform); - node->setStateSet(shaderStateset); node->setUpdateCallback(NULL); } From 4a7be0ffda9368e4e2efc3cc61dc42ca9d5cd5b8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 24 Oct 2017 20:02:35 +0000 Subject: [PATCH 456/521] Don't reset journal index to a lower value (Fixes #4172) --- apps/openmw/mwdialogue/journalimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 41eaed080..b56db1ebd 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -82,7 +82,8 @@ namespace MWDialogue for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i) if (i->mTopic == id && i->mInfoId == infoId) { - setJournalIndex(id, index); + if (getJournalIndex(id) < index) + setJournalIndex(id, index); MWBase::Environment::get().getWindowManager()->messageBox ("#{sJournalEntry}"); return; } From e3142b9643eff1ce1e6d631098aeb4c67d0e4d42 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 24 Oct 2017 23:10:50 +0100 Subject: [PATCH 457/521] Add missing variables to those forwarded to the git-version target --- components/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e9b992e02..e9c872628 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -17,6 +17,8 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake + "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" + "-DCMAKE_GENERATOR=${CMAKE_GENERATOR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From daf7d8451cb507a38de54363bd82a65fd422ce71 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 24 Oct 2017 23:29:18 +0100 Subject: [PATCH 458/521] Switch to a more reliable method of passing the git-version targt the data it needs --- cmake/OpenMWMacros.cmake | 14 +++++++++----- components/CMakeLists.txt | 5 +++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 5f66705e7..fe2837a09 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -166,11 +166,15 @@ macro (openmw_add_executable target) endmacro (openmw_add_executable) macro (get_generator_is_multi_config VALUE) - if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) - else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) - list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) - endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + if (DEFINED generator_is_multi_config_var) + set(${VALUE} ${generator_is_multi_config_var}) + else (DEFINED generator_is_multi_config_var) + if (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + get_cmake_property(${VALUE} GENERATOR_IS_MULTI_CONFIG) + else (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + list(LENGTH "${CMAKE_CONFIGURATION_TYPES}" ${VALUE}) + endif (CMAKE_VERSION VERSION_GREATER 3.9 OR CMAKE_VERSION VERSION_EQUAL 3.9) + endif (DEFINED generator_is_multi_config_var) endmacro (get_generator_is_multi_config) macro (copy_resource_file source_path destination_dir_base dest_path_relative) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e9c872628..fb78bd432 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -5,7 +5,8 @@ set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") set (VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") set (VERSION_FILE_PATH_RELATIVE resources/version) if (GIT_CHECKOUT) - add_custom_target (git-version + get_generator_is_multi_config(multi_config) + add_custom_target (git-version COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} @@ -18,7 +19,7 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION=${OPENMW_VERSION} -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" - "-DCMAKE_GENERATOR=${CMAKE_GENERATOR}" + -Dgenerator_is_multi_config_var=${multi_config} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From c1a871ff1fe4b20d2dc26dbc56a5ddaf28514e22 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 24 Oct 2017 23:31:40 +0100 Subject: [PATCH 459/521] Make indentation consistent. --- components/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index fb78bd432..a0b426a16 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -17,9 +17,9 @@ if (GIT_CHECKOUT) -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} -DOPENMW_VERSION=${OPENMW_VERSION} - -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake - "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" - -Dgenerator_is_multi_config_var=${multi_config} + -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake + "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" + -Dgenerator_is_multi_config_var=${multi_config} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake VERBATIM) else (GIT_CHECKOUT) From d19839a66670f4410ebf97e7dcd42f1c89300114 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 25 Oct 2017 21:55:58 +0200 Subject: [PATCH 460/521] standerdise on 3.1.0 --- CMakeLists.txt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b47678e7d..f4b912c70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,16 +24,8 @@ if (USE_QT) set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5) endif() -if (APPLE) - # OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db - cmake_minimum_required(VERSION 3.1.0) -elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5) - # 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows. - cmake_minimum_required(VERSION 2.8.11) -else() - # We probably support older versions than this. - cmake_minimum_required(VERSION 2.6) -endif() +# set the minimum required version across the board +cmake_minimum_required(VERSION 3.1.0) project(OpenMW) From 03401bb5df4a804d9ae016ee8fe147ed4eb0b246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 27 Oct 2017 20:19:20 +0200 Subject: [PATCH 461/521] remove redundant condition --- apps/openmw/mwphysics/physicssystem.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 34932e360..36041a85e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -357,10 +357,9 @@ namespace MWPhysics osg::Vec3f nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - if(newPosition.z() < swimlevel && - !isFlying && // can't fly + if(!isFlying && // can't fly nextpos.z() > swimlevel && // but about to go above water - newPosition.z() <= swimlevel) + newPosition.z() < swimlevel) { const osg::Vec3f down(0,0,-1); velocity = slide(velocity, down); From f9c396e0eae7037d0217b79cbbb5fe3878853a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 28 Oct 2017 15:48:07 +0200 Subject: [PATCH 462/521] stop landing animation when turning --- apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 03acfdaf2..dc910c577 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -372,6 +372,9 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } + if (jumpAnimName.length() > 0) + mJumpAnimName = jumpAnimName; + if(mJumpState == JumpState_InAir) { mAnimation->disable(mCurrentJump); @@ -555,6 +558,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (mPtr.getClass().isActor()) refreshHitRecoilAnims(); + if (isTurning() && mJumpState != JumpState_InAir) + mAnimation->disable(mJumpAnimName); + const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index af90c18b8..c03702ef2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -184,6 +184,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener JumpingState mJumpState; std::string mCurrentJump; + std::string mJumpAnimName; WeaponType mWeaponType; std::string mCurrentWeapon; From 5c8f4914419fa3421d86f8884a517e942ce08f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 28 Oct 2017 18:46:52 +0200 Subject: [PATCH 463/521] move animation disabling code to a better place --- apps/openmw/mwmechanics/character.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index dc910c577..83c7ce844 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -558,9 +558,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (mPtr.getClass().isActor()) refreshHitRecoilAnims(); - if (isTurning() && mJumpState != JumpState_InAir) - mAnimation->disable(mJumpAnimName); - const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); if (!mPtr.getClass().isBipedal(mPtr)) weap = sWeaponTypeListEnd; @@ -1883,9 +1880,15 @@ void CharacterController::update(float duration) else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) + { movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; + mAnimation->disable(mJumpAnimName); + } else if(rot.z() < 0.0f) + { movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; + mAnimation->disable(mJumpAnimName); + } } } From 1ee5dcff775995f783478204954786ece270b677 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 28 Oct 2017 20:56:08 +0100 Subject: [PATCH 464/521] added a function to determine if a script contains OnActivate --- apps/openmw/mwbase/scriptmanager.hpp | 4 ++++ apps/openmw/mwscript/scriptmanagerimp.cpp | 6 ++++++ apps/openmw/mwscript/scriptmanagerimp.hpp | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/apps/openmw/mwbase/scriptmanager.hpp b/apps/openmw/mwbase/scriptmanager.hpp index 7bdeba132..44d350115 100644 --- a/apps/openmw/mwbase/scriptmanager.hpp +++ b/apps/openmw/mwbase/scriptmanager.hpp @@ -42,6 +42,10 @@ namespace MWBase ///< Compile script with the given namen /// \return Success? + virtual bool hasOnActivate (const std::string& name) = 0; + ///< Determine if a script with the given name contains OnActivate + /// \return Contains OnActivate? + virtual std::pair compileAll() = 0; ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 7c1f9bf4d..01ff97be2 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -88,6 +88,12 @@ namespace MWScript return false; } + bool ScriptManager::hasOnActivate(const std::string& name) + { + const ESM::Script *script = mStore.get().find(name); + return script->mScriptText.find("OnActivate"); + } + void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext) { // compile script diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index c22a5da81..3835be26e 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -62,6 +62,10 @@ namespace MWScript ///< Compile script with the given namen /// \return Success? + virtual bool hasOnActivate(const std::string& name); + ///< Determine if a script with the given name contains OnActivate + /// \return Contains OnActivate? + virtual std::pair compileAll(); ///< Compile all scripts /// \return count, success From 4e6f53d6f16572086ad1c0d5455e16ed3ce359af Mon Sep 17 00:00:00 2001 From: rexelion Date: Sun, 29 Oct 2017 11:45:17 +0000 Subject: [PATCH 465/521] item added to the player and OnActivate is triggered when the inventory is closed --- apps/openmw/mwgui/inventorywindow.cpp | 20 ++++++++++++++++++++ apps/openmw/mwgui/inventorywindow.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 3 files changed, 26 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b3697008c..8586cfb5b 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,6 +1,7 @@ #include "inventorywindow.hpp" #include +#include #include #include @@ -149,6 +150,15 @@ namespace MWGui mItemView->setModel(NULL); } + void InventoryWindow::activateItems() + { + for (std::vector::iterator it = mItemsToActivate.begin(); it != mItemsToActivate.end(); it++) + { + it->getRefData().activate(); + } + mItemsToActivate.clear(); + } + void InventoryWindow::setGuiMode(GuiMode mode) { std::string setting = "inventory"; @@ -653,6 +663,16 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; + std::string scriptName = object.getClass().getScript(object); // Objects that have OnActivte in their script cannot be picked up through inventory + if (!scriptName.empty() && MWBase::Environment::get().getScriptManager()->hasOnActivate(scriptName)) + { + if (std::find(mItemsToActivate.begin(), mItemsToActivate.end(), object) == mItemsToActivate.end()) + { + mItemsToActivate.push_back(object); + } + return; + } + int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 5576b52ed..3f88d8822 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -58,6 +58,8 @@ namespace MWGui void clear(); + void activateItems(); + void useItem(const MWWorld::Ptr& ptr); void setGuiMode(GuiMode mode); @@ -70,6 +72,8 @@ namespace MWGui int mSelectedItem; + std::vector mItemsToActivate; + MWWorld::Ptr mPtr; MWGui::ItemView* mItemView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccdd6916c..e2a10ccc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1171,6 +1171,8 @@ namespace MWGui mGuiModeStates[mode].update(false); if (!noSound) playSound(mGuiModeStates[mode].mCloseSound); + if (mode == GM_Inventory) + mInventoryWindow->activateItems(); // Activate cursed items when inventory is closed } if (!mGuiModes.empty()) From 7bc512974f2d2d663c6813cd3d55de337b7c1858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 30 Oct 2017 15:26:38 +0100 Subject: [PATCH 466/521] use mcurrentjump instead of custom attrib --- apps/openmw/mwmechanics/character.cpp | 12 +++++------- apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83c7ce844..a2e07fc5c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -372,9 +372,6 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } - if (jumpAnimName.length() > 0) - mJumpAnimName = jumpAnimName; - if(mJumpState == JumpState_InAir) { mAnimation->disable(mCurrentJump); @@ -385,8 +382,9 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } else { - mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); + if (startAtLoop) + mAnimation->disable(mCurrentJump); + if (mAnimation->hasAnimation("jump")) mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); @@ -1882,12 +1880,12 @@ void CharacterController::update(float duration) if(rot.z() > 0.0f) { movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; - mAnimation->disable(mJumpAnimName); + mAnimation->disable(mCurrentJump); } else if(rot.z() < 0.0f) { movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; - mAnimation->disable(mJumpAnimName); + mAnimation->disable(mCurrentJump); } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c03702ef2..af90c18b8 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -184,7 +184,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener JumpingState mJumpState; std::string mCurrentJump; - std::string mJumpAnimName; WeaponType mWeaponType; std::string mCurrentWeapon; From 3c65bdaf1408632bcbc0019b3cf7bb060294ead0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Mon, 30 Oct 2017 18:05:45 +0100 Subject: [PATCH 467/521] weapon cycle fix --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index b3697008c..a92c77760 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -735,7 +735,7 @@ namespace MWGui } } - if (!found) + if (!found || selected == cycled) return; useItem(model.getItem(cycled).mBase); From e8743f3f795ff8b4b7c3bfe103ca930587872258 Mon Sep 17 00:00:00 2001 From: rexelion Date: Mon, 30 Oct 2017 20:59:36 +0000 Subject: [PATCH 468/521] check the presence of OnActivate using the SuppressActivate flag instead of looking for keywords --- apps/openmw/mwbase/scriptmanager.hpp | 4 ---- apps/openmw/mwgui/inventorywindow.cpp | 3 +-- apps/openmw/mwscript/scriptmanagerimp.cpp | 6 ------ apps/openmw/mwscript/scriptmanagerimp.hpp | 4 ---- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 2 ++ 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/scriptmanager.hpp b/apps/openmw/mwbase/scriptmanager.hpp index 44d350115..7bdeba132 100644 --- a/apps/openmw/mwbase/scriptmanager.hpp +++ b/apps/openmw/mwbase/scriptmanager.hpp @@ -42,10 +42,6 @@ namespace MWBase ///< Compile script with the given namen /// \return Success? - virtual bool hasOnActivate (const std::string& name) = 0; - ///< Determine if a script with the given name contains OnActivate - /// \return Contains OnActivate? - virtual std::pair compileAll() = 0; ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 8586cfb5b..5fe644d45 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -663,8 +663,7 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; - std::string scriptName = object.getClass().getScript(object); // Objects that have OnActivte in their script cannot be picked up through inventory - if (!scriptName.empty() && MWBase::Environment::get().getScriptManager()->hasOnActivate(scriptName)) + if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item { if (std::find(mItemsToActivate.begin(), mItemsToActivate.end(), object) == mItemsToActivate.end()) { diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 01ff97be2..7c1f9bf4d 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -88,12 +88,6 @@ namespace MWScript return false; } - bool ScriptManager::hasOnActivate(const std::string& name) - { - const ESM::Script *script = mStore.get().find(name); - return script->mScriptText.find("OnActivate"); - } - void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext) { // compile script diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 3835be26e..c22a5da81 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -62,10 +62,6 @@ namespace MWScript ///< Compile script with the given namen /// \return Success? - virtual bool hasOnActivate(const std::string& name); - ///< Determine if a script with the given name contains OnActivate - /// \return Contains OnActivate? - virtual std::pair compileAll(); ///< Compile all scripts /// \return count, success diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f6fa3556f..95b0fb3e0 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -192,6 +192,11 @@ namespace MWWorld return mEnabled; } + bool RefData::hasSuppressActivate() + { + return mFlags & Flag_SuppressActivate; + } + void RefData::enable() { if (!mEnabled) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 75eec6742..4dfa9e91c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -111,6 +111,8 @@ namespace MWWorld bool isEnabled() const; + bool hasSuppressActivate(); + void enable(); void disable(); From ff1265c0e7b67e68462886ab0d2d3b5cbeda8d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 31 Oct 2017 14:22:24 +0100 Subject: [PATCH 469/521] refactor jump animation --- apps/openmw/mwmechanics/character.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a2e07fc5c..f262850a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -380,7 +380,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); } - else + else if (mJumpState == JumpState_Landing) { if (startAtLoop) mAnimation->disable(mCurrentJump); @@ -389,6 +389,14 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); } + else // JumpState_None + { + if (mCurrentJump.length() > 0) + { + mAnimation->disable(mCurrentJump); + mCurrentJump.clear(); + } + } } } @@ -1693,7 +1701,6 @@ void CharacterController::update(float duration) mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; isrunning = isrunning && mHasMovedInXY; - // advance athletics if(mHasMovedInXY && mPtr == getPlayer()) { @@ -1848,7 +1855,8 @@ void CharacterController::update(float duration) } else { - jumpstate = JumpState_None; + jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None; + vec.z() = 0.0f; inJump = false; From a9e5e1948270945bbb16be1219cb61a10ce8ddd8 Mon Sep 17 00:00:00 2001 From: rexelion Date: Tue, 31 Oct 2017 18:16:40 +0000 Subject: [PATCH 470/521] OnActivate is triggered when the item is picked up --- apps/openmw/mwgui/inventorywindow.cpp | 26 +++++++------------------- apps/openmw/mwgui/inventorywindow.hpp | 4 ---- apps/openmw/mwgui/windowmanagerimp.cpp | 2 -- apps/openmw/mwworld/actiontake.cpp | 3 +++ 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5fe644d45..1e9f534d6 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,7 +1,6 @@ #include "inventorywindow.hpp" #include -#include #include #include @@ -150,15 +149,6 @@ namespace MWGui mItemView->setModel(NULL); } - void InventoryWindow::activateItems() - { - for (std::vector::iterator it = mItemsToActivate.begin(); it != mItemsToActivate.end(); it++) - { - it->getRefData().activate(); - } - mItemsToActivate.clear(); - } - void InventoryWindow::setGuiMode(GuiMode mode) { std::string setting = "inventory"; @@ -663,15 +653,6 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; - if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item - { - if (std::find(mItemsToActivate.begin(), mItemsToActivate.end(), object) == mItemsToActivate.end()) - { - mItemsToActivate.push_back(object); - } - return; - } - int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -682,6 +663,13 @@ namespace MWGui // add to player inventory // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); + + if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item + { + newObject.getRefData().onActivate(); // set the flag_SuppressActivate flag for the new item + newObject.getRefData().activate(); + } + // remove from world MWBase::Environment::get().getWorld()->deleteObject (object); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 3f88d8822..5576b52ed 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -58,8 +58,6 @@ namespace MWGui void clear(); - void activateItems(); - void useItem(const MWWorld::Ptr& ptr); void setGuiMode(GuiMode mode); @@ -72,8 +70,6 @@ namespace MWGui int mSelectedItem; - std::vector mItemsToActivate; - MWWorld::Ptr mPtr; MWGui::ItemView* mItemView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e2a10ccc3..ccdd6916c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1171,8 +1171,6 @@ namespace MWGui mGuiModeStates[mode].update(false); if (!noSound) playSound(mGuiModeStates[mode].mCloseSound); - if (mode == GM_Inventory) - mInventoryWindow->activateItems(); // Activate cursed items when inventory is closed } if (!mGuiModes.empty()) diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index d858859a6..52e30c8ac 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -14,6 +14,9 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { + //No need to do anything if moving items from the player's inventory back into player's inventory + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && getTarget().getCell() == 0) + return; MWBase::Environment::get().getMechanicsManager()->itemTaken( actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); MWWorld::Ptr newitem = *actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); From 5b8610b34b61e5b587cc196205aa3bb1275d5967 Mon Sep 17 00:00:00 2001 From: rexelion Date: Wed, 1 Nov 2017 23:44:50 +0000 Subject: [PATCH 471/521] knocked out characters wait some time before getting up --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 03acfdaf2..c3ca8f512 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -248,12 +248,15 @@ void CharacterController::refreshHitRecoilAnims() bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { + mKnockoutTime = MWBase::Environment::get().getWorld()->getTimeStamp(); if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -338,7 +341,8 @@ void CharacterController::refreshHitRecoilAnims() mPtr.getClass().getCreatureStats(mPtr).setBlock(false); mHitState = CharState_None; } - else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0) + else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0 + && (currentTime - mKnockoutTime) > 3*timeScale/3600) //Wait 3 seconds before getting up { mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index af90c18b8..0654b8534 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -7,6 +7,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/timestamp.hpp" #include "../mwrender/animation.hpp" @@ -196,6 +197,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; + MWWorld::TimeStamp mKnockoutTime; + MWWorld::ConstPtr mHeadTrackTarget; float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning From de83ad0116c434e8bf90ab4f330a93e50f392191 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 00:24:09 +0000 Subject: [PATCH 472/521] use real time; wait random number of seconds --- apps/openmw/mwmechanics/character.cpp | 7 +++---- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c3ca8f512..dffc095e9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -248,15 +248,14 @@ void CharacterController::refreshHitRecoilAnims() bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown(); bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock(); bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr); - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); if(mHitState == CharState_None) { if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { - mKnockoutTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mTimeToWake = time(NULL); + mTimeToWake += rand() % 2 + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -342,7 +341,7 @@ void CharacterController::refreshHitRecoilAnims() mHitState = CharState_None; } else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0 - && (currentTime - mKnockoutTime) > 3*timeScale/3600) //Wait 3 seconds before getting up + && time(NULL) > mTimeToWake) { mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0654b8534..af8415e35 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -197,7 +197,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - MWWorld::TimeStamp mKnockoutTime; + time_t mTimeToWake; MWWorld::ConstPtr mHeadTrackTarget; From bcbfa5fe1e97696a96794b0b55d3ec8b427a1212 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 00:38:33 +0000 Subject: [PATCH 473/521] prevent activation, leave the rest to the script --- apps/openmw/mwgui/inventorywindow.cpp | 9 +++------ apps/openmw/mwworld/actiontake.cpp | 3 --- apps/openmw/mwworld/refdata.cpp | 5 ----- apps/openmw/mwworld/refdata.hpp | 2 -- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1e9f534d6..063bc5c01 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,6 +653,9 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; + if (!object.getRefData().activate()) + return; + int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -663,12 +666,6 @@ namespace MWGui // add to player inventory // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); - - if (object.getRefData().hasSuppressActivate()) // if Flag_SuppressActivate is set, script that contains OnActivate is attached to the item - { - newObject.getRefData().onActivate(); // set the flag_SuppressActivate flag for the new item - newObject.getRefData().activate(); - } // remove from world MWBase::Environment::get().getWorld()->deleteObject (object); diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 52e30c8ac..d858859a6 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -14,9 +14,6 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { - //No need to do anything if moving items from the player's inventory back into player's inventory - if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && getTarget().getCell() == 0) - return; MWBase::Environment::get().getMechanicsManager()->itemTaken( actor, getTarget(), MWWorld::Ptr(), getTarget().getRefData().getCount()); MWWorld::Ptr newitem = *actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 95b0fb3e0..f6fa3556f 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -192,11 +192,6 @@ namespace MWWorld return mEnabled; } - bool RefData::hasSuppressActivate() - { - return mFlags & Flag_SuppressActivate; - } - void RefData::enable() { if (!mEnabled) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 4dfa9e91c..75eec6742 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -111,8 +111,6 @@ namespace MWWorld bool isEnabled() const; - bool hasSuppressActivate(); - void enable(); void disable(); From 8c2cc0f42fa6b6e7717962a87a1d2c584460ca0b Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 00:44:16 +0000 Subject: [PATCH 474/521] break invisibility first --- apps/openmw/mwgui/inventorywindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 063bc5c01..e1301edd4 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -653,13 +653,13 @@ namespace MWGui if (object.getClass().getName(object) == "") // objects without name presented to user can never be picked up return; - if (!object.getRefData().activate()) - return; - int count = object.getRefData().getCount(); MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getWorld()->breakInvisibility(player); + + if (!object.getRefData().activate()) + return; MWBase::Environment::get().getMechanicsManager()->itemTaken(player, object, MWWorld::Ptr(), count); From ee2f3db9a87abf24341f4247b7748d5aa935ef6e Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 01:31:15 +0000 Subject: [PATCH 475/521] fixed randomness --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index dffc095e9..deb9daa93 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -255,7 +255,7 @@ void CharacterController::refreshHitRecoilAnims() && mAnimation->hasAnimation("knockout")) { mTimeToWake = time(NULL); - mTimeToWake += rand() % 2 + 1; // Wake up after 1 to 3 seconds + mTimeToWake += (int)( (float)rand() / (float)RAND_MAX * 2) + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; From ab66034ed17f045839f4fd16ac1fec4872e6afad Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 02:15:56 +0000 Subject: [PATCH 476/521] use uniform_int_distribution instead of rand() --- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index deb9daa93..ade9d635b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,6 +20,7 @@ #include "character.hpp" #include +#include #include @@ -254,8 +255,11 @@ void CharacterController::refreshHitRecoilAnims() || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { + std::random_device r; + std::mt19937 gen(r()); + std::uniform_int_distribution dist(1, 3); mTimeToWake = time(NULL); - mTimeToWake += (int)( (float)rand() / (float)RAND_MAX * 2) + 1; // Wake up after 1 to 3 seconds + mTimeToWake += dist(gen); // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index af8415e35..12b4d6adc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -7,7 +7,6 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwworld/timestamp.hpp" #include "../mwrender/animation.hpp" From f34223fce9ec847a5694825e32867294be1e326f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 2 Nov 2017 20:01:22 +0100 Subject: [PATCH 477/521] check the real distance to target in aipursue --- apps/openmw/mwmechanics/aipursue.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index f9884eb6d..835966467 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -50,8 +50,13 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte //Set the target desition from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; + ESM::Position aPos = actor.getRefData().getPosition(); - if (pathTo(actor, dest, duration, 100)) { + float pathTolerance = 100.0; + + if (pathTo(actor, dest, duration, pathTolerance) && + MWMechanics::distance(dest,aPos.pos[0],aPos.pos[1],aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction + { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; } From 48ec680f233f2ea616569e77872d757df7a488a0 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 4 Nov 2017 19:37:20 +0000 Subject: [PATCH 478/521] use game time instead of real time --- apps/openmw/mwmechanics/character.cpp | 17 ++++++++++------- apps/openmw/mwmechanics/character.hpp | 4 +++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ade9d635b..83d6cc1f3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,7 +20,6 @@ #include "character.hpp" #include -#include #include @@ -243,6 +242,11 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } +void CharacterController::updateKnockoutTimer(float duration) +{ + mTimeUntilWake -= duration; +} + void CharacterController::refreshHitRecoilAnims() { bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); @@ -255,11 +259,7 @@ void CharacterController::refreshHitRecoilAnims() || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0) && mAnimation->hasAnimation("knockout")) { - std::random_device r; - std::mt19937 gen(r()); - std::uniform_int_distribution dist(1, 3); - mTimeToWake = time(NULL); - mTimeToWake += dist(gen); // Wake up after 1 to 3 seconds + mTimeUntilWake = Misc::Rng::rollClosedProbability() * 2 + 1; // Wake up after 1 to 3 seconds if (isSwimming && mAnimation->hasAnimation("swimknockout")) { mHitState = CharState_SwimKnockOut; @@ -345,7 +345,7 @@ void CharacterController::refreshHitRecoilAnims() mHitState = CharState_None; } else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0 - && time(NULL) > mTimeToWake) + && mTimeUntilWake <= 0) { mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown; mAnimation->disable(mCurrentHit); @@ -1635,6 +1635,9 @@ void CharacterController::update(float duration) float speed = 0.f; updateMagicEffects(); + + if (isKnockedOut()) + updateKnockoutTimer(duration); bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 12b4d6adc..0b9e60c11 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,7 +196,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - time_t mTimeToWake; + float mTimeUntilWake; MWWorld::ConstPtr mHeadTrackTarget; @@ -226,6 +226,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener void updateMagicEffects(); + void updateKnockoutTimer(float duration); + void playDeath(float startpoint, CharacterState death); CharacterState chooseRandomDeathState() const; void playRandomDeath(float startpoint = 0.0f); From e3c42251f99744e30164d0a258a0b4cc82e3a4f7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Sun, 5 Nov 2017 15:36:26 +0000 Subject: [PATCH 479/521] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 839a04e42..c4190343d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -129,6 +129,7 @@ Programmers Radu-Marius Popovici (rpopovici) Rafael Moura (dhustkoder) rdimesio + rexelion riothamus Rob Cutmore (rcutmore) Robert MacGregor (Ragora) From 282800b5b24b6ac9aa127031dfcec7a78e873bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 5 Nov 2017 16:37:38 +0100 Subject: [PATCH 480/521] Create LICENSE (#1532) * Create LICENSE Let's add the license file so that GitHub officially registers it and displays it next to the project. * move license files * update licenses in cmakelists.txt * fix link in README --- CMakeLists.txt | 6 +++--- docs/license/GPL3.txt => LICENSE | 6 +++--- README.md | 4 ++-- {docs/license => files/mygui}/DejaVu Font License.txt | 0 4 files changed, 8 insertions(+), 8 deletions(-) rename docs/license/GPL3.txt => LICENSE (99%) rename {docs/license => files/mygui}/DejaVu Font License.txt (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b47678e7d..507c89c45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,7 @@ IF(NOT WIN32 AND NOT APPLE) #ENDIF(BUILD_MYGUI_PLUGIN) # Install licenses - INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) + INSTALL(FILES "files/mygui/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) # Install icon and desktop file INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw") @@ -446,9 +446,9 @@ if(WIN32) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/LICENSE" DESTINATION "." RENAME "LICENSE.txt") INSTALL(FILES - "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" - "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" + "${OpenMW_SOURCE_DIR}/files/mygui/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION ".") diff --git a/docs/license/GPL3.txt b/LICENSE similarity index 99% rename from docs/license/GPL3.txt rename to LICENSE index 94a9ed024..9cecc1d46 100644 --- a/docs/license/GPL3.txt +++ b/LICENSE @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) + {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index aa6ae47b4..3e5556cb4 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ OpenMW is a recreation of the engine for the popular role-playing game Morrowind OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set. * Version: 0.42.0 -* License: GPLv3 (see [docs/license/GPL3.txt](https://github.com/OpenMW/openmw/blob/master/docs/license/GPL3.txt) for more information) +* License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net Font Licenses: -* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information) +* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVu Font License.txt](https://github.com/OpenMW/openmw/blob/master/files/mygui/DejaVu%20Font%20License.txt) for more information) Current Status -------------- diff --git a/docs/license/DejaVu Font License.txt b/files/mygui/DejaVu Font License.txt similarity index 100% rename from docs/license/DejaVu Font License.txt rename to files/mygui/DejaVu Font License.txt From de7a7d842bb6d90660c8da66c47ec30ec8091c06 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sun, 5 Nov 2017 18:30:34 +0000 Subject: [PATCH 481/521] mTimeUntilWake is initialised in the constructor --- apps/openmw/mwmechanics/character.cpp | 8 ++------ apps/openmw/mwmechanics/character.hpp | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83d6cc1f3..0f99725fd 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -242,11 +242,6 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i return prefix + toString(roll); } -void CharacterController::updateKnockoutTimer(float duration) -{ - mTimeUntilWake -= duration; -} - void CharacterController::refreshHitRecoilAnims() { bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery(); @@ -766,6 +761,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSecondsOfRunning(0) , mTurnAnimationThreshold(0) , mAttackingOrSpell(false) + , mTimeUntilWake(0.f) { if(!mAnimation) return; @@ -1637,7 +1633,7 @@ void CharacterController::update(float duration) updateMagicEffects(); if (isKnockedOut()) - updateKnockoutTimer(duration); + mTimeUntilWake -= duration; bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0b9e60c11..6de18fe62 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -226,8 +226,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener void updateMagicEffects(); - void updateKnockoutTimer(float duration); - void playDeath(float startpoint, CharacterState death); CharacterState chooseRandomDeathState() const; void playRandomDeath(float startpoint = 0.0f); From 430d01a39a61342e11048c4c166692fbb2a1c64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 5 Nov 2017 20:19:47 +0100 Subject: [PATCH 482/521] additional animation refactor --- apps/openmw/mwmechanics/character.cpp | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f262850a4..107ccf09b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -372,29 +372,28 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } - if(mJumpState == JumpState_InAir) + if (!mCurrentJump.empty()) { mAnimation->disable(mCurrentJump); - mCurrentJump = jumpAnimName; - if (mAnimation->hasAnimation("jump")) - mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, + mCurrentJump.clear(); + } + + if(mJumpState == JumpState_InAir) + { + if (mAnimation->hasAnimation(jumpAnimName)) + { + mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); + mCurrentJump = jumpAnimName; + } } else if (mJumpState == JumpState_Landing) { - if (startAtLoop) - mAnimation->disable(mCurrentJump); - - if (mAnimation->hasAnimation("jump")) + if (mAnimation->hasAnimation(jumpAnimName)) + { mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); - } - else // JumpState_None - { - if (mCurrentJump.length() > 0) - { - mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); + mCurrentJump = jumpAnimName; } } } From 7d39c5450ca099e2b61e0380c338241e2b7bdf39 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Sun, 5 Nov 2017 21:40:35 +0100 Subject: [PATCH 483/521] Fixed escaping @ in boost program options filter --- components/files/escape.cpp | 3 ++- components/files/escape.hpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index f28870c70..3c3d04d51 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -27,7 +27,8 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char)escape_hash_filter::sEscape, 1)); + auto format = std::string(1, (char)escape_hash_filter::sEscape); + boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 2017c2ed2..64410f3ab 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -78,6 +78,12 @@ namespace Files mFinishLine = true; } } + else if (character == sEscape) + { + mNext.push(sEscape); + mNext.push(sEscapeIdentifier); + record = false; + } else if (mPrevious == sEscape) { mNext.push(sEscape); From f98a821482e51b2c1bbb5a6c7c43393608dee2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sun, 5 Nov 2017 23:46:15 +0100 Subject: [PATCH 484/521] fix possible bug in aipursue --- apps/openmw/mwmechanics/aipursue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 835966467..27d4ab0cb 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -55,7 +55,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte float pathTolerance = 100.0; if (pathTo(actor, dest, duration, pathTolerance) && - MWMechanics::distance(dest,aPos.pos[0],aPos.pos[1],aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction + abs(dest.mZ - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; From a1d9f11b04dbff794889d816ee4bb31fab05bb32 Mon Sep 17 00:00:00 2001 From: rexelion Date: Tue, 7 Nov 2017 11:43:21 +0000 Subject: [PATCH 485/521] use fProjectileMaxSpeed for ranged weapons distance --- apps/openmw/mwmechanics/aicombataction.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index d44498966..df636dd56 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -115,6 +115,7 @@ namespace MWMechanics isRanged = false; static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fCombatDistance")->getFloat(); + static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get().find("fProjectileMaxSpeed")->getFloat(); if (mWeapon.isEmpty()) { @@ -128,7 +129,7 @@ namespace MWMechanics if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) { isRanged = true; - return 1000.f; + return fProjectileMaxSpeed; } else return weapon->mData.mReach * fCombatDistance; From cab00024615730360fba3f66fc2cfb058acabea3 Mon Sep 17 00:00:00 2001 From: rexelion Date: Tue, 7 Nov 2017 17:57:23 +0000 Subject: [PATCH 486/521] Backing up distance is now dependent on opponents's weapon range; don't back up from ranged oponents --- apps/openmw/mwmechanics/aicombat.cpp | 49 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 68d282d0c..cd9211a3f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -490,6 +490,28 @@ namespace MWMechanics void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { + // get the range of the target's weapon + float rangeAttackOfTarget = 0.f; + MWWorld::Ptr targetWeapon = MWWorld::Ptr(); + const MWWorld::Class& targetClass = target.getClass(); + + if (targetClass.hasInventoryStore(target)) + { + MWMechanics::WeaponType weapType = WeapType_None; + MWWorld::ContainerStoreIterator weaponSlot = + MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType); + if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand) + targetWeapon = *weaponSlot; + } + + std::shared_ptr targetWeaponAction(new ActionWeapon(targetWeapon)); + + bool isRangedCombat = false; + if (targetWeaponAction.get()) + { + rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat); + } + if (mMovement.mPosition[0] || mMovement.mPosition[1]) { mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); @@ -498,28 +520,6 @@ namespace MWMechanics // dodge movements (for NPCs and bipedal creatures) else if (actor.getClass().isBipedal(actor)) { - // get the range of the target's weapon - float rangeAttackOfTarget = 0.f; - MWWorld::Ptr targetWeapon = MWWorld::Ptr(); - const MWWorld::Class& targetClass = target.getClass(); - - if (targetClass.hasInventoryStore(target)) - { - MWMechanics::WeaponType weapType = WeapType_None; - MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType); - if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand) - targetWeapon = *weaponSlot; - } - - std::shared_ptr targetWeaponAction (new ActionWeapon(targetWeapon)); - - if (targetWeaponAction.get()) - { - bool isRangedCombat = false; - rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat); - } - // apply sideway movement (kind of dodging) with some probability // if actor is within range of target's weapon if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25) @@ -533,13 +533,14 @@ namespace MWMechanics // Below behavior for backing up during ranged combat differs from vanilla. // Vanilla is observed as backing up only as far as fCombatDistance or // opponent's weapon range, or not backing up if opponent is also using a ranged weapon - if (isDistantCombat && distToTarget < rangeAttack / 4) + if (isDistantCombat) { // actor should not back up into water if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f)) return; - mMovement.mPosition[1] = -1; + if (!isRangedCombat && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon + mMovement.mPosition[1] = -1; } } From af3e1f92ec71df8b3a10f638f9a7d6b18fa474d6 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 22:16:59 +0100 Subject: [PATCH 487/521] Added StringUtil::replaceAll() --- components/misc/stringops.hpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 9acd81710..12c222036 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -2,6 +2,7 @@ #define MISC_STRINGOPS_H #include +#include #include #include @@ -138,6 +139,35 @@ public: return notFound; } + + /** @brief Replaces all occurrences 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 what_len The length of the string to replace. + * @param with_len The length of the replacement string. + * + * @return A reference to the string passed in @p str. + */ + static std::string &replaceAll(std::string &str, const char *what, const char *with, + std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + { + if (what_len == std::string::npos) + what_len = strlen(what); + + if (with_len == std::string::npos) + with_len = strlen(with); + + std::size_t found; + std::size_t offset = 0; + while((found = str.find(what, offset, what_len)) != std::string::npos) + { + str.replace(found, what_len, with, with_len); + offset = found + with_len; + } + return str; + } }; } From 70d578d050ea9e26cf14064ee0e2bb62a051ceae Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:10:58 +0100 Subject: [PATCH 488/521] Removed escape_hash_filter::mPrevious, removed usage of boost::replace_all --- components/files/escape.cpp | 15 ++++++++++----- components/files/escape.hpp | 11 ----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/components/files/escape.cpp b/components/files/escape.cpp index 3c3d04d51..93ae9b885 100644 --- a/components/files/escape.cpp +++ b/components/files/escape.cpp @@ -1,6 +1,6 @@ #include "escape.hpp" -#include +#include namespace Files { @@ -8,7 +8,7 @@ namespace Files const int escape_hash_filter::sEscapeIdentifier = 'a'; const int escape_hash_filter::sHashIdentifier = 'h'; - escape_hash_filter::escape_hash_filter() : mNext(), mPrevious(), mSeenNonWhitespace(false), mFinishLine(false) + escape_hash_filter::escape_hash_filter() : mSeenNonWhitespace(false), mFinishLine(false) { } @@ -26,9 +26,14 @@ namespace Files std::string EscapeHashString::processString(const std::string & str) { - std::string temp = boost::replace_all_copy(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#"); - auto format = std::string(1, (char)escape_hash_filter::sEscape); - boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, format); + std::string temp = str; + + static const char hash[] = { escape_hash_filter::sEscape, escape_hash_filter::sHashIdentifier }; + Misc::StringUtils::replaceAll(temp, hash, "#", 2, 1); + + static const char escape[] = { escape_hash_filter::sEscape, escape_hash_filter::sEscapeIdentifier }; + Misc::StringUtils::replaceAll(temp, escape, "@", 2, 1); + return temp; } diff --git a/components/files/escape.hpp b/components/files/escape.hpp index 64410f3ab..d01bd8d98 100644 --- a/components/files/escape.hpp +++ b/components/files/escape.hpp @@ -30,7 +30,6 @@ namespace Files private: std::queue mNext; - int mPrevious; bool mSeenNonWhitespace; bool mFinishLine; @@ -42,11 +41,9 @@ namespace Files if (mNext.empty()) { int character = boost::iostreams::get(src); - bool record = true; if (character == boost::iostreams::WOULD_BLOCK) { mNext.push(character); - record = false; } else if (character == EOF) { @@ -79,12 +76,6 @@ namespace Files } } else if (character == sEscape) - { - mNext.push(sEscape); - mNext.push(sEscapeIdentifier); - record = false; - } - else if (mPrevious == sEscape) { mNext.push(sEscape); mNext.push(sEscapeIdentifier); @@ -95,8 +86,6 @@ namespace Files } if (!mSeenNonWhitespace && !isspace(character)) mSeenNonWhitespace = true; - if (record) - mPrevious = character; } int retval = mNext.front(); mNext.pop(); From 43b5c2e36bc19db88f391f6a40429be4cf25c3a0 Mon Sep 17 00:00:00 2001 From: Alexander Stillich Date: Tue, 7 Nov 2017 23:20:10 +0100 Subject: [PATCH 489/521] Fixed parameter naming --- components/misc/stringops.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 12c222036..9f4931d72 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -145,26 +145,26 @@ public: * @param str The string to operate on. * @param what The string to replace. * @param with The replacement string. - * @param what_len The length of the string to replace. - * @param with_len The length of 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 &replaceAll(std::string &str, const char *what, const char *with, - std::size_t what_len=std::string::npos, std::size_t with_len=std::string::npos) + std::size_t whatLen=std::string::npos, std::size_t withLen=std::string::npos) { - if (what_len == std::string::npos) - what_len = strlen(what); + if (whatLen == std::string::npos) + whatLen = strlen(what); - if (with_len == std::string::npos) - with_len = strlen(with); + if (withLen == std::string::npos) + withLen = strlen(with); std::size_t found; std::size_t offset = 0; - while((found = str.find(what, offset, what_len)) != std::string::npos) + while((found = str.find(what, offset, whatLen)) != std::string::npos) { - str.replace(found, what_len, with, with_len); - offset = found + with_len; + str.replace(found, whatLen, with, withLen); + offset = found + withLen; } return str; } From 7b4add2ae4b83aaad977c63e53322f7ed0055ce7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 7 Nov 2017 23:44:38 +0100 Subject: [PATCH 490/521] Fall back to non-shader material if creating the shader fails Also fixes an uncaught exception that will break the whole game. --- components/terrain/material.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 8aec54835..640f2932b 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -116,7 +116,10 @@ namespace Terrain osg::ref_ptr vertexShader = shaderManager->getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX); osg::ref_ptr fragmentShader = shaderManager->getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT); if (!vertexShader || !fragmentShader) - throw std::runtime_error("Unable to create shader"); + { + // Try again without shader. Error already logged by above + return createPasses(false, forcePerPixelLighting, clampLighting, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); + } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); } From 244cc5b861c58f284b01f071400cd47254006014 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Tue, 7 Nov 2017 23:54:31 +0100 Subject: [PATCH 491/521] Reduce error spam --- components/shader/shadermanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 7cb49c6cb..5efd1b86e 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -131,7 +131,11 @@ namespace Shader { std::string shaderSource = templateIt->second; if (!parseDefines(shaderSource, defines)) + { + // Add to the cache anyway to avoid logging the same error over and over. + mShaders.insert(std::make_pair(std::make_pair(shaderTemplate, defines), nullptr)); return NULL; + } osg::ref_ptr shader (new osg::Shader(shaderType)); shader->setShaderSource(shaderSource); From e42bd71081010b5c5484b54ed4fc811e7ccf13fe Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 00:03:02 +0100 Subject: [PATCH 492/521] Add missing WaitDialog::clear() (Fixes #4196) --- apps/openmw/mwgui/waitdialog.cpp | 6 ++++++ apps/openmw/mwgui/waitdialog.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a7ad687cb..61febf315 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -96,6 +96,12 @@ namespace MWGui return (!mTimeAdvancer.isRunning()); //Only exit if not currently waiting } + void WaitDialog::clear() + { + mSleeping = false; + mTimeAdvancer.stop(); + } + void WaitDialog::onOpen() { if (mTimeAdvancer.isRunning()) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index eb6a55640..2aecb002f 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -33,6 +33,8 @@ namespace MWGui virtual bool exit(); + virtual void clear(); + void onFrame(float dt); bool getSleeping() { return mTimeAdvancer.isRunning() && mSleeping; } From 95b3c1181a873ac9b5f3269e950a6ea17c4b732d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 00:53:06 +0100 Subject: [PATCH 493/521] Update shader with a non-color tracking material when equipment is changed during chameleon/invisibility effects (Fixes #4190) --- apps/openmw/mwrender/npcanimation.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8211c2f5f..ece57c273 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -388,9 +388,6 @@ void NpcAnimation::rebuild() { updateNpcBase(); - if (mAlpha != 1.f) - mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); - MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); } @@ -651,6 +648,9 @@ void NpcAnimation::updateParts() if (wasArrowAttached) attachArrow(); + + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } @@ -917,6 +917,8 @@ void NpcAnimation::showWeapons(bool showWeapon) attachArrow(); } } + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } else { @@ -942,6 +944,8 @@ void NpcAnimation::showCarriedLeft(bool show) if (iter->getTypeName() == typeid(ESM::Light).name() && mObjectParts[ESM::PRT_Shield]) addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), iter->get()->mBase); } + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); } else removeIndividualPart(ESM::PRT_Shield); From 9ecdcc187f76028bfa9c2a26d53345cb89b16dc5 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 8 Nov 2017 01:08:26 +0100 Subject: [PATCH 494/521] Clarify a warning message refers to inventory objects --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index cd04a425b..981f63e34 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -806,7 +806,7 @@ void MWWorld::ContainerStore::readState (const ESM::InventoryState& inventory) case ESM::REC_WEAP: readEquipmentState (getState (weapons, state), thisIndex, inventory); break; case ESM::REC_LIGH: readEquipmentState (getState (lights, state), thisIndex, inventory); break; case 0: - std::cerr << "Warning: Dropping reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; + std::cerr << "Dropping inventory reference to '" << state.mRef.mRefID << "' (object no longer exists)" << std::endl; break; default: std::cerr << "Warning: Invalid item type in inventory state, refid " << state.mRef.mRefID << std::endl; From 983c33c4c89209ef6679743cd9f17654d4265eb4 Mon Sep 17 00:00:00 2001 From: rexelion Date: Thu, 9 Nov 2017 14:23:26 +0000 Subject: [PATCH 495/521] don't use a pointer for ActionWeapon --- apps/openmw/mwmechanics/aicombat.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index cd9211a3f..6e3268831 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -504,13 +504,8 @@ namespace MWMechanics targetWeapon = *weaponSlot; } - std::shared_ptr targetWeaponAction(new ActionWeapon(targetWeapon)); - bool isRangedCombat = false; - if (targetWeaponAction.get()) - { - rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat); - } + rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); if (mMovement.mPosition[0] || mMovement.mPosition[1]) { From 3604b73d6016aaa62808e888e47c2da27d4c109c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 4 Oct 2017 21:25:22 +0400 Subject: [PATCH 496/521] Move onTakeItem() to item models --- apps/openmw/mwgui/container.cpp | 33 +++-------------------- apps/openmw/mwgui/containeritemmodel.cpp | 24 +++++++++++++++-- apps/openmw/mwgui/containeritemmodel.hpp | 1 + apps/openmw/mwgui/inventoryitemmodel.cpp | 15 +++++++++++ apps/openmw/mwgui/inventoryitemmodel.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 9 +++++++ apps/openmw/mwgui/itemmodel.hpp | 2 ++ apps/openmw/mwgui/pickpocketitemmodel.cpp | 29 ++++++++++++++++++-- apps/openmw/mwgui/pickpocketitemmodel.hpp | 4 +++ apps/openmw/mwgui/sortfilteritemmodel.cpp | 4 +++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 2 ++ 11 files changed, 91 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 74ed4fff9..be3cb1522 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -8,13 +8,13 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "countdialog.hpp" #include "inventorywindow.hpp" @@ -142,8 +142,7 @@ namespace MWGui if (mPtr.getClass().isNpc() && !loot) { // we are stealing stuff - MWWorld::Ptr player = MWMechanics::getPlayer(); - mModel = new PickpocketItemModel(player, new InventoryItemModel(container), + mModel = new PickpocketItemModel(mPtr, new InventoryItemModel(container), !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); } else @@ -271,32 +270,8 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - MWWorld::Ptr player = MWMechanics::getPlayer(); - // TODO: move to ItemModels - if (dynamic_cast(mModel) - && !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()) - { - MWMechanics::Pickpocket pickpocket(player, mPtr); - if (pickpocket.pick(item.mBase, count)) - { - MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - mPickpocketDetected = true; - return false; - } - else - player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1); - } - else - { - // Looting a dead corpse is considered OK - if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead()) - return true; - else - MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count); - } - return true; + // TODO: mPickpocketDetected = true; + return mModel->onTakeItem(item.mBase, count); } } diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 479638672..ee89f1350 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -2,12 +2,15 @@ #include +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/actorutil.hpp" @@ -183,4 +186,21 @@ void ContainerItemModel::update() } } +bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) +{ + if (mItemSources.empty()) + return false; + + MWWorld::Ptr target = mItemSources[0]; + + // Looting a dead corpse is considered OK + if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead()) + return true; + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, target, count); + + return true; +} + } diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index c6ecafd46..a0dbc2cf9 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -26,6 +26,7 @@ namespace MWGui virtual void removeItem (const ItemStack& item, size_t count); virtual void update(); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: std::vector mItemSources; diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 222243ec1..b807a58f4 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -9,6 +9,9 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" + namespace MWGui { @@ -116,4 +119,16 @@ void InventoryItemModel::update() } } +bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const +{ + // Looting a dead corpse is considered OK + if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) + return true; + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count); + + return true; +} + } diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index f58ee2939..95afeb5d4 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); virtual void update(); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; protected: MWWorld::Ptr mActor; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index ffcf9075e..5a6afdf02 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -129,6 +129,11 @@ namespace MWGui return true; } + bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return true; + } + ProxyItemModel::ProxyItemModel() : mSourceModel(NULL) @@ -198,4 +203,8 @@ namespace MWGui mSourceModel = sourceModel; } + bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem (item, count); + } } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index bc6be8023..c4a3a03e8 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -75,6 +75,7 @@ namespace MWGui /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: ItemModel(const ItemModel&); @@ -94,6 +95,7 @@ namespace MWGui virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); /// @note Takes ownership of the passed pointer. void setSourceModel(ItemModel* sourceModel); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index ec4b378a0..e610854c1 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -3,15 +3,24 @@ #include #include +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/pickpocket.hpp" + #include "../mwworld/class.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { - PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel, bool hideItems) + PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& actor, ItemModel *sourceModel, bool hideItems) + : mActor(actor) { + MWWorld::Ptr player = MWMechanics::getPlayer(); mSourceModel = sourceModel; - int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); + int chance = player.getClass().getSkill(player, ESM::Skill::Sneak); mSourceModel->update(); @@ -75,4 +84,20 @@ namespace MWGui return false; } + bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWMechanics::Pickpocket pickpocket(player, mActor); + if (pickpocket.pick(item, count)) + { + MWBase::Environment::get().getMechanicsManager()->commitCrime( + player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + return false; + } + else + player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1); + + return true; + } } diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 1b08ec485..ad8788da7 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -18,6 +18,10 @@ namespace MWGui virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); virtual bool allowedToInsertItems() const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + + protected: + MWWorld::Ptr mActor; private: std::vector mHiddenItems; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index e294ebe07..932f362fb 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -311,4 +311,8 @@ namespace MWGui std::sort(mItems.begin(), mItems.end(), cmp); } + bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem (item, count); + } } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 6ddb019b0..e99726b0f 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -29,6 +29,8 @@ namespace MWGui /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } + bool onTakeItem(const MWWorld::Ptr &item, int count); + static const int Category_Weapon = (1<<1); static const int Category_Apparel = (1<<2); static const int Category_Misc = (1<<3); From ac33ff94827188d2623a042120ad51874ae7253b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 4 Oct 2017 22:37:08 +0400 Subject: [PATCH 497/521] Move onDropItem() check to item models --- apps/openmw/mwgui/container.cpp | 24 ++-------------- apps/openmw/mwgui/containeritemmodel.cpp | 34 +++++++++++++++++++++-- apps/openmw/mwgui/containeritemmodel.hpp | 5 +++- apps/openmw/mwgui/inventoryitemmodel.cpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.hpp | 3 +- apps/openmw/mwgui/itemmodel.cpp | 14 ++++++++-- apps/openmw/mwgui/itemmodel.hpp | 7 +++-- apps/openmw/mwgui/pickpocketitemmodel.cpp | 12 +++++++- apps/openmw/mwgui/pickpocketitemmodel.hpp | 1 + apps/openmw/mwgui/sortfilteritemmodel.cpp | 7 ++++- apps/openmw/mwgui/sortfilteritemmodel.hpp | 3 +- 11 files changed, 79 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index be3cb1522..3fa07b070 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -100,28 +100,10 @@ namespace MWGui void ContainerWindow::dropItem() { - if (mPtr.getTypeName() == typeid(ESM::Container).name()) - { - // check container organic flag - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mFlags & ESM::Container::Organic) - { - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}"); - return; - } - - // check that we don't exceed container capacity - MWWorld::Ptr item = mDragAndDrop->mItem.mBase; - float weight = item.getClass().getWeight(item) * mDragAndDrop->mDraggedCount; - if (mPtr.getClass().getCapacity(mPtr) < mPtr.getClass().getEncumbrance(mPtr) + weight) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}"); - return; - } - } + bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount); - mDragAndDrop->drop(mModel, mItemView); + if (success) + mDragAndDrop->drop(mModel, mItemView); } void ContainerWindow::onBackgroundSelected() diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index ee89f1350..ef7aa8215 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/actorutil.hpp" @@ -185,8 +186,37 @@ void ContainerItemModel::update() } } } +bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) const +{ + if (mItemSources.empty()) + return false; + + MWWorld::Ptr target = mItemSources[0]; -bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + if (target.getTypeName() != typeid(ESM::Container).name()) + return true; + + // check container organic flag + MWWorld::LiveCellRef* ref = target.get(); + if (ref->mBase->mFlags & ESM::Container::Organic) + { + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage2}"); + return false; + } + + // check that we don't exceed container capacity + float weight = item.getClass().getWeight(item) * count; + if (target.getClass().getCapacity(target) < target.getClass().getEncumbrance(target) + weight) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}"); + return false; + } + + return true; +} + +bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { if (mItemSources.empty()) return false; @@ -196,7 +226,7 @@ bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) // Looting a dead corpse is considered OK if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead()) return true; - + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, target, count); diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index a0dbc2cf9..fb57096ef 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -18,6 +18,10 @@ namespace MWGui ContainerItemModel (const MWWorld::Ptr& source); virtual bool allowedToUseItems() const; + + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); @@ -26,7 +30,6 @@ namespace MWGui virtual void removeItem (const ItemStack& item, size_t count); virtual void update(); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: std::vector mItemSources; diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index b807a58f4..aed08feb1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -124,7 +124,7 @@ bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const // Looting a dead corpse is considered OK if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) return true; - + MWWorld::Ptr player = MWMechanics::getPlayer(); MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count); diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index 95afeb5d4..c5ca80eed 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -15,6 +15,8 @@ namespace MWGui virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); @@ -22,7 +24,6 @@ namespace MWGui virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel); virtual void update(); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; protected: MWWorld::Ptr mActor; diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 5a6afdf02..25dce728a 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -129,7 +129,12 @@ namespace MWGui return true; } - bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + { + return true; + } + + bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { return true; } @@ -203,7 +208,12 @@ namespace MWGui mSourceModel = sourceModel; } - bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + { + return mSourceModel->onDropItem (item, count); + } + + bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { return mSourceModel->onTakeItem (item, count); } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index c4a3a03e8..78c646e33 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -75,7 +75,8 @@ namespace MWGui /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count); + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; private: ItemModel(const ItemModel&); @@ -92,10 +93,12 @@ namespace MWGui bool allowedToUseItems() const; + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); virtual ModelIndex getIndex (ItemStack item); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count); /// @note Takes ownership of the passed pointer. void setSourceModel(ItemModel* sourceModel); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index e610854c1..ba8fd7d75 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -4,6 +4,7 @@ #include #include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwworld/class.hpp" @@ -80,12 +81,21 @@ namespace MWGui bool PickpocketItemModel::allowedToInsertItems() const { - // don't allow "reverse pickpocket" (yet) + // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) + return false; + } + + bool PickpocketItemModel::onDropItem(const MWWorld::Ptr &item, int count) + { + // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) return false; } bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { + if (mActor.getClass().getCreatureStats(mActor).getKnockedDown()) + return mSourceModel->onTakeItem(item, count); + MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mActor); if (pickpocket.pick(item, count)) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index ad8788da7..a759cd993 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -18,6 +18,7 @@ namespace MWGui virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); virtual bool allowedToInsertItems() const; + virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; protected: diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 932f362fb..15c7fbfcb 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -311,7 +311,12 @@ namespace MWGui std::sort(mItems.begin(), mItems.end(), cmp); } - bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + { + return mSourceModel->onDropItem (item, count); + } + + bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const { return mSourceModel->onTakeItem (item, count); } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index e99726b0f..fa8d836b5 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -29,7 +29,8 @@ namespace MWGui /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } - bool onTakeItem(const MWWorld::Ptr &item, int count); + bool onDropItem(const MWWorld::Ptr &item, int count) const; + bool onTakeItem(const MWWorld::Ptr &item, int count) const; static const int Category_Weapon = (1<<1); static const int Category_Apparel = (1<<2); From 3694b6ec90369c9e070ac785d08a3a6496afadfd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 4 Oct 2017 23:26:06 +0400 Subject: [PATCH 498/521] Move onClose() check to item models --- apps/openmw/mwgui/container.cpp | 24 +------------------ apps/openmw/mwgui/container.hpp | 2 -- apps/openmw/mwgui/containeritemmodel.cpp | 4 ++-- apps/openmw/mwgui/containeritemmodel.hpp | 4 ++-- apps/openmw/mwgui/inventoryitemmodel.cpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.hpp | 2 +- apps/openmw/mwgui/itemmodel.cpp | 17 ++++++++----- apps/openmw/mwgui/itemmodel.hpp | 12 ++++++---- apps/openmw/mwgui/pickpocketitemmodel.cpp | 29 +++++++++++++++++++++-- apps/openmw/mwgui/pickpocketitemmodel.hpp | 7 ++++-- apps/openmw/mwgui/sortfilteritemmodel.cpp | 13 ++++++---- apps/openmw/mwgui/sortfilteritemmodel.hpp | 5 ++-- 12 files changed, 70 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 3fa07b070..03c7b54be 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -12,9 +12,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/actorutil.hpp" #include "countdialog.hpp" #include "inventorywindow.hpp" @@ -33,7 +31,6 @@ namespace MWGui ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : WindowBase("openmw_container_window.layout") , mDragAndDrop(dragAndDrop) - , mPickpocketDetected(false) , mSortModel(NULL) , mModel(NULL) , mSelectedItem(-1) @@ -114,7 +111,6 @@ namespace MWGui void ContainerWindow::setPtr(const MWWorld::Ptr& container) { - mPickpocketDetected = false; mPtr = container; bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); @@ -159,24 +155,7 @@ namespace MWGui { WindowBase::onClose(); - if (dynamic_cast(mModel) - // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) - && !MWBase::Environment::get().getWindowManager()->containsMode(GM_Container) - // If it was already detected while taking an item, no need to check now - && !mPickpocketDetected - ) - { - MWWorld::Ptr player = MWMechanics::getPlayer(); - MWMechanics::Pickpocket pickpocket(player, mPtr); - if (pickpocket.finish()) - { - MWBase::Environment::get().getMechanicsManager()->commitCrime( - player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - mPickpocketDetected = true; - return; - } - } + mModel->onClose(); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) @@ -252,7 +231,6 @@ namespace MWGui bool ContainerWindow::onTakeItem(const ItemStack &item, int count) { - // TODO: mPickpocketDetected = true; return mModel->onTakeItem(item.mBase, count); } diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 50c69da3b..cf02d165d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -44,8 +44,6 @@ namespace MWGui private: DragAndDrop* mDragAndDrop; - bool mPickpocketDetected; - MWGui::ItemView* mItemView; SortFilterItemModel* mSortModel; ItemModel* mModel; diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index ef7aa8215..8e42b3ebc 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -186,7 +186,7 @@ void ContainerItemModel::update() } } } -bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) const +bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) { if (mItemSources.empty()) return false; @@ -216,7 +216,7 @@ bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count) const return true; } -bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const +bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { if (mItemSources.empty()) return false; diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index fb57096ef..e8d1c5328 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -19,8 +19,8 @@ namespace MWGui virtual bool allowedToUseItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); virtual ItemStack getItem (ModelIndex index); virtual ModelIndex getIndex (ItemStack item); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index aed08feb1..c9f55d352 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -119,7 +119,7 @@ void InventoryItemModel::update() } } -bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const +bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { // Looting a dead corpse is considered OK if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()) diff --git a/apps/openmw/mwgui/inventoryitemmodel.hpp b/apps/openmw/mwgui/inventoryitemmodel.hpp index c5ca80eed..38730bd4d 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.hpp +++ b/apps/openmw/mwgui/inventoryitemmodel.hpp @@ -15,7 +15,7 @@ namespace MWGui virtual ModelIndex getIndex (ItemStack item); virtual size_t getItemCount(); - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 25dce728a..c59bc8bf4 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -129,12 +129,12 @@ namespace MWGui return true; } - bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) { return true; } - bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { return true; } @@ -208,13 +208,18 @@ namespace MWGui mSourceModel = sourceModel; } - bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + void ProxyItemModel::onClose() { - return mSourceModel->onDropItem (item, count); + mSourceModel->onClose(); } - bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count) { - return mSourceModel->onTakeItem (item, count); + return mSourceModel->onDropItem(item, count); + } + + bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem(item, count); } } diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index 78c646e33..d50718e5d 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -75,8 +75,11 @@ namespace MWGui /// Is the player allowed to insert items into this model? (default true) virtual bool allowedToInsertItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual void onClose() + { + } + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); private: ItemModel(const ItemModel&); @@ -93,8 +96,9 @@ namespace MWGui bool allowedToUseItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual void onClose(); + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual void removeItem (const ItemStack& item, size_t count); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index ba8fd7d75..b073ef73f 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -17,7 +17,7 @@ namespace MWGui { PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& actor, ItemModel *sourceModel, bool hideItems) - : mActor(actor) + : mActor(actor), mPickpocketDetected(false) { MWWorld::Ptr player = MWMechanics::getPlayer(); mSourceModel = sourceModel; @@ -91,11 +91,35 @@ namespace MWGui return false; } - bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + void PickpocketItemModel::onClose() + { + // Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened) + if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Container) + // If it was already detected while taking an item, no need to check now + || mPickpocketDetected) + return; + + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWMechanics::Pickpocket pickpocket(player, mActor); + if (pickpocket.finish()) + { + MWBase::Environment::get().getMechanicsManager()->commitCrime( + player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + mPickpocketDetected = true; + } + } + + bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count) { if (mActor.getClass().getCreatureStats(mActor).getKnockedDown()) return mSourceModel->onTakeItem(item, count); + return stealItem(item, count); + } + + bool PickpocketItemModel::stealItem(const MWWorld::Ptr &item, int count) + { MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::Pickpocket pickpocket(player, mActor); if (pickpocket.pick(item, count)) @@ -103,6 +127,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->commitCrime( player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + mPickpocketDetected = true; return false; } else diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index a759cd993..9aa686c39 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -18,11 +18,14 @@ namespace MWGui virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); virtual bool allowedToInsertItems() const; - virtual bool onDropItem(const MWWorld::Ptr &item, int count) const; - virtual bool onTakeItem(const MWWorld::Ptr &item, int count) const; + virtual void onClose(); + virtual bool onDropItem(const MWWorld::Ptr &item, int count); + virtual bool onTakeItem(const MWWorld::Ptr &item, int count); protected: MWWorld::Ptr mActor; + bool mPickpocketDetected; + bool stealItem(const MWWorld::Ptr &item, int count); private: std::vector mHiddenItems; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 15c7fbfcb..1ee3cf631 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -311,13 +311,18 @@ namespace MWGui std::sort(mItems.begin(), mItems.end(), cmp); } - bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count) const + void SortFilterItemModel::onClose() { - return mSourceModel->onDropItem (item, count); + mSourceModel->onClose(); } - bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) const + bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count) { - return mSourceModel->onTakeItem (item, count); + return mSourceModel->onDropItem(item, count); + } + + bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count) + { + return mSourceModel->onTakeItem(item, count); } } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index fa8d836b5..98da8d8c9 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -29,8 +29,9 @@ namespace MWGui /// Use ItemStack::Type for sorting? void setSortByType(bool sort) { mSortByType = sort; } - bool onDropItem(const MWWorld::Ptr &item, int count) const; - bool onTakeItem(const MWWorld::Ptr &item, int count) const; + void onClose(); + bool onDropItem(const MWWorld::Ptr &item, int count); + bool onTakeItem(const MWWorld::Ptr &item, int count); static const int Category_Weapon = (1<<1); static const int Category_Apparel = (1<<2); From 69a56eaea3fee303e3ef58d58d5ca6bd43668143 Mon Sep 17 00:00:00 2001 From: rexelion Date: Fri, 10 Nov 2017 10:44:53 +0000 Subject: [PATCH 499/521] don't initialise rangeAttackOfTarget --- apps/openmw/mwmechanics/aicombat.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6e3268831..07fb455f3 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -491,7 +491,6 @@ namespace MWMechanics void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) { // get the range of the target's weapon - float rangeAttackOfTarget = 0.f; MWWorld::Ptr targetWeapon = MWWorld::Ptr(); const MWWorld::Class& targetClass = target.getClass(); @@ -505,7 +504,7 @@ namespace MWMechanics } bool isRangedCombat = false; - rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); + float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); if (mMovement.mPosition[0] || mMovement.mPosition[1]) { From b9baee51d556f5e4555fb227292a850cd8b51525 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:47:14 +0100 Subject: [PATCH 500/521] Fix overlapping widgets in trade window layout (Fixes #4205) --- files/mygui/openmw_trade_window.layout | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index d1f31c475..ebfe9b30f 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -53,18 +53,17 @@ - - - - - + + + + - + - + From 1afbf99f74c8a5b4c0aedad91ff20f3d3529fee4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 21:48:11 +0100 Subject: [PATCH 501/521] Make movement keys not function in text input mode --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a5bb93b6c..5aa795c10 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -176,6 +176,8 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + if (SDL_IsTextInputActive()) + return; MyGUI::KeyCode key; switch (action) { From b06512a60d9f020cdd8d9f44fe6ef76f216eb9dd Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:02:43 +0100 Subject: [PATCH 502/521] Fix error message that referred to the wrong file (Bug #4159) --- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/animation.hpp | 7 ++++--- apps/openmw/mwrender/creatureanimation.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.cpp | 12 ++++++------ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 90b69de8e..a1aa24871 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -536,7 +536,7 @@ namespace MWRender return mKeyframes->mTextKeys; } - void Animation::addAnimSource(const std::string &model) + void Animation::addAnimSource(const std::string &model, const std::string& baseModel) { std::string kfname = model; Misc::StringUtils::lowerCaseInPlace(kfname); @@ -565,7 +565,7 @@ namespace MWRender NodeMap::const_iterator found = nodeMap.find(bonename); if (found == nodeMap.end()) { - std::cerr << "Warning: addAnimSource: can't find bone '" + bonename << "' in " << model << " (referenced by " << kfname << ")" << std::endl; + std::cerr << "Warning: addAnimSource: can't find bone '" + bonename << "' in " << baseModel << " (referenced by " << kfname << ")" << std::endl; continue; } @@ -1668,7 +1668,7 @@ namespace MWRender { setObjectRoot(model, false, false, false); if (animated) - addAnimSource(model); + addAnimSource(model, model); if (!ptr.getClass().getEnchantment(ptr).empty()) addGlow(mObjectRoot, getEnchantmentColor(ptr)); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5aec80f5d..8ac78babc 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -309,11 +309,12 @@ protected: */ void setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature); - /** Adds the keyframe controllers in the specified model as a new animation source. Note that the .nif - * file extension will be replaced with .kf. + /** Adds the keyframe controllers in the specified model as a new animation source. * @note Later added animation sources have the highest priority when it comes to finding a particular animation. + * @param model The file to add the keyframes for. Note that the .nif file extension will be replaced with .kf. + * @param baseModel The filename of the mObjectRoot, only used for error messages. */ - void addAnimSource(const std::string &model); + void addAnimSource(const std::string &model, const std::string& baseModel); /** Adds an additional light to the given node using the specified ESM record. */ void addExtraLight(osg::ref_ptr parent, const ESM::Light *light); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 735c0b66d..827b576c3 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -33,8 +33,8 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr, setObjectRoot(model, false, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + addAnimSource("meshes\\xbase_anim.nif", model); + addAnimSource(model, model); } } @@ -51,8 +51,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const setObjectRoot(model, true, false, true); if((ref->mBase->mFlags&ESM::Creature::Bipedal)) - addAnimSource("meshes\\xbase_anim.nif"); - addAnimSource(model); + addAnimSource("meshes\\xbase_anim.nif", model); + addAnimSource(model, model); mPtr.getClass().getInventoryStore(mPtr).setInvListener(this, mPtr); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ece57c273..08e376f08 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -482,25 +482,25 @@ void NpcAnimation::updateNpcBase() { const std::string base = "meshes\\xbase_anim.nif"; if (smodel != base) - addAnimSource(base); + addAnimSource(base, smodel); - addAnimSource(smodel); + addAnimSource(smodel, smodel); if(!isWerewolf) { if(mNpc->mModel.length() > 0) - addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS())); + addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()), smodel); if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\xargonian_swimkna.nif"); + addAnimSource("meshes\\xargonian_swimkna.nif", smodel); } } else { const std::string base = "meshes\\xbase_anim.1st.nif"; if (smodel != base) - addAnimSource(base); + addAnimSource(base, smodel); - addAnimSource(smodel); + addAnimSource(smodel, smodel); mObjectRoot->setNodeMask(Mask_FirstPerson); mObjectRoot->addCullCallback(new OverrideFieldOfViewCallback(mFirstPersonFieldOfView)); From a5adc5b018fa76a39e5a3a41aba4f5fcc8ab049d Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:09:24 +0100 Subject: [PATCH 503/521] Add NPC base skeleton files to the optimizer blacklist (Fixes #4159) --- components/resource/scenemanager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 9c5a2a14e..03b850fac 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -432,13 +432,18 @@ namespace Resource bool canOptimize(const std::string& filename) { - // xmesh.nif can not be optimized because there are keyframes added in post size_t slashpos = filename.find_last_of("\\/"); if (slashpos != std::string::npos && slashpos+1 < filename.size()) { std::string basename = filename.substr(slashpos+1); + // xmesh.nif can not be optimized because there are keyframes added in post if (!basename.empty() && basename[0] == 'x') return false; + + // NPC skeleton files can not be optimized because of keyframes added in post + // (most of them are usually named like 'xbase_anim.nif' anyway, but not all of them :( ) + if (basename.compare(0, 9, "base_anim") == 0 || basename.compare(0, 4, "skin") == 0) + return false; } // For spell VFX, DummyXX nodes must remain intact. Not adding those to reservedNames to avoid being overly cautious - instead, decide on filename From f1aeb416ece36dbc37cd41138cc37bf6517cc5f4 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Fri, 10 Nov 2017 22:54:04 +0000 Subject: [PATCH 504/521] Disable Activate key when textinput is active (Bug #4151) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5aa795c10..9ef5033f0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1113,7 +1113,10 @@ namespace MWInput void InputManager::activate() { if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + { + if (!SDL_IsTextInputActive()) + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0); + } else if (mControlSwitch["playercontrols"]) mPlayer->activate(); } From a02124f884018ab23d6d78538f6b2222ebaefd6c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 5 Oct 2017 11:12:43 +0400 Subject: [PATCH 505/521] Handle item owners during pickpocketing --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwgui/pickpocketitemmodel.cpp | 11 ++++++++-- .../mwmechanics/mechanicsmanagerimp.cpp | 22 ++++++++++++++----- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 398439ad8..7a33d6e57 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -140,7 +140,7 @@ namespace MWBase /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, - int count) = 0; + int count, bool alarm = true) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. @@ -250,7 +250,6 @@ namespace MWBase virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; - virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0; virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index b073ef73f..4c32eafcd 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -7,6 +7,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/pickpocket.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" @@ -76,7 +77,6 @@ namespace MWGui void PickpocketItemModel::removeItem (const ItemStack &item, size_t count) { ProxyItemModel::removeItem(item, count); - /// \todo check if player is detected } bool PickpocketItemModel::allowedToInsertItems() const @@ -115,7 +115,14 @@ namespace MWGui if (mActor.getClass().getCreatureStats(mActor).getKnockedDown()) return mSourceModel->onTakeItem(item, count); - return stealItem(item, count); + bool success = stealItem(item, count); + if (success) + { + MWWorld::Ptr player = MWMechanics::getPlayer(); + MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count, false); + } + + return success; } bool PickpocketItemModel::stealItem(const MWWorld::Ptr &item, int count) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2c7b6a500..a4e258ada 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1024,7 +1024,7 @@ namespace MWMechanics } void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, - int count) + int count, bool alarm) { if (ptr != getPlayer()) return; @@ -1053,19 +1053,29 @@ namespace MWMechanics return; Owner owner; - owner.first = ownerCellRef->getOwner(); owner.second = false; - if (owner.first.empty()) + if (!container.isEmpty() && container.getClass().isActor()) { - owner.first = ownerCellRef->getFaction(); - owner.second = true; + // "container" is an actor inventory, so just take actor's ID + owner.first = ownerCellRef->getRefId(); } + else + { + owner.first = ownerCellRef->getOwner(); + if (owner.first.empty()) + { + owner.first = ownerCellRef->getFaction(); + owner.second = true; + } + } + Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; - commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); + if (alarm) + commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index ee4cf28af..baee5233e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -135,7 +135,7 @@ namespace MWMechanics /// Utility to check if taking this item is illegal and calling commitCrime if so /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, - int count); + int count, bool alarm = true); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); /// Attempt sleeping in a bed. If this is illegal, call commitCrime. From 99517d83ea2116577c5f893b723c019fc6645b5b Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 10 Nov 2017 09:43:22 +0400 Subject: [PATCH 506/521] Bound items detection refactoring --- apps/openmw/mwbase/mechanicsmanager.hpp | 1 + apps/openmw/mwgui/itemmodel.cpp | 34 +--------------- .../mwmechanics/mechanicsmanagerimp.cpp | 39 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 + 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 7a33d6e57..5fb3bd400 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -238,6 +238,7 @@ namespace MWBase /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; + virtual bool isBoundItem(const MWWorld::Ptr& item) = 0; virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; /// Turn actor into werewolf or normal form. diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index c59bc8bf4..834c351dc 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -9,6 +9,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" namespace MWGui { @@ -23,38 +24,7 @@ namespace MWGui if (base.getClass().getEnchantment(base) != "") mFlags |= Flag_Enchanted; - static std::set boundItemIDCache; - - // If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's for some reason - if (boundItemIDCache.empty()) - { - // Build a list of known bound item ID's - const MWWorld::Store &gameSettings = MWBase::Environment::get().getWorld()->getStore().get(); - - for (MWWorld::Store::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration) - { - const ESM::GameSetting ¤tSetting = *currentIteration; - std::string currentGMSTID = currentSetting.mId; - Misc::StringUtils::lowerCaseInPlace(currentGMSTID); - - // Don't bother checking this GMST if it's not a sMagicBound* one. - const std::string& toFind = "smagicbound"; - if (currentGMSTID.compare(0, toFind.length(), toFind) != 0) - continue; - - // All sMagicBound* GMST's should be of type string - std::string currentGMSTValue = currentSetting.getString(); - Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); - - boundItemIDCache.insert(currentGMSTValue); - } - } - - // Perform bound item check and assign the Flag_Bound bit if it passes - std::string tempItemID = base.getCellRef().getRefId(); - Misc::StringUtils::lowerCaseInPlace(tempItemID); - - if (boundItemIDCache.count(tempItemID) != 0) + if (MWBase::Environment::get().getMechanicsManager()->isBoundItem(base)) mFlags |= Flag_Bound; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index a4e258ada..92031b80b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -840,6 +840,45 @@ namespace MWMechanics mAI = true; } + bool MechanicsManager::isBoundItem(const MWWorld::Ptr& item) + { + static std::set boundItemIDCache; + + // If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's for some reason + if (boundItemIDCache.empty()) + { + // Build a list of known bound item ID's + const MWWorld::Store &gameSettings = MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration) + { + const ESM::GameSetting ¤tSetting = *currentIteration; + std::string currentGMSTID = currentSetting.mId; + Misc::StringUtils::lowerCaseInPlace(currentGMSTID); + + // Don't bother checking this GMST if it's not a sMagicBound* one. + const std::string& toFind = "smagicbound"; + if (currentGMSTID.compare(0, toFind.length(), toFind) != 0) + continue; + + // All sMagicBound* GMST's should be of type string + std::string currentGMSTValue = currentSetting.getString(); + Misc::StringUtils::lowerCaseInPlace(currentGMSTValue); + + boundItemIDCache.insert(currentGMSTValue); + } + } + + // Perform bound item check and assign the Flag_Bound bit if it passes + std::string tempItemID = item.getCellRef().getRefId(); + Misc::StringUtils::lowerCaseInPlace(tempItemID); + + if (boundItemIDCache.count(tempItemID) != 0) + return true; + + return false; + } + bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) { if (target.isEmpty()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index baee5233e..bf3b7c79c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -204,6 +204,8 @@ namespace MWMechanics /// Has the player stolen this item from the given owner? virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); + virtual bool isBoundItem(const MWWorld::Ptr& item); + /// @return is \a ptr allowed to take/use \a target or is it a crime? virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim); From 03f129b53c97a5032c5862606c0d0f93a40abc38 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 11 Nov 2017 11:54:18 +0400 Subject: [PATCH 507/521] remove redundant allowedToInsertItems() function from ItemModel --- apps/openmw/mwgui/container.cpp | 7 +++---- apps/openmw/mwgui/itemmodel.cpp | 5 ----- apps/openmw/mwgui/itemmodel.hpp | 3 --- apps/openmw/mwgui/pickpocketitemmodel.cpp | 6 ------ apps/openmw/mwgui/pickpocketitemmodel.hpp | 1 - 5 files changed, 3 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 03c7b54be..444eaff85 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -52,10 +52,9 @@ namespace MWGui void ContainerWindow::onItemSelected(int index) { - if (mDragAndDrop->mIsOnDragAndDrop) + if (mDragAndDrop->mIsOnDragAndDrop && mModel) { - if (mModel && mModel->allowedToInsertItems()) - dropItem(); + dropItem(); return; } @@ -105,7 +104,7 @@ namespace MWGui void ContainerWindow::onBackgroundSelected() { - if (mDragAndDrop->mIsOnDragAndDrop && mModel && mModel->allowedToInsertItems()) + if (mDragAndDrop->mIsOnDragAndDrop && mModel) dropItem(); } diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 834c351dc..e3f38a54c 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -94,11 +94,6 @@ namespace MWGui return true; } - bool ItemModel::allowedToInsertItems() const - { - return true; - } - bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count) { return true; diff --git a/apps/openmw/mwgui/itemmodel.hpp b/apps/openmw/mwgui/itemmodel.hpp index d50718e5d..e8e348a8a 100644 --- a/apps/openmw/mwgui/itemmodel.hpp +++ b/apps/openmw/mwgui/itemmodel.hpp @@ -72,9 +72,6 @@ namespace MWGui /// Is the player allowed to use items from this item model? (default true) virtual bool allowedToUseItems() const; - - /// Is the player allowed to insert items into this model? (default true) - virtual bool allowedToInsertItems() const; virtual void onClose() { } diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 4c32eafcd..e85715e87 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -79,12 +79,6 @@ namespace MWGui ProxyItemModel::removeItem(item, count); } - bool PickpocketItemModel::allowedToInsertItems() const - { - // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) - return false; - } - bool PickpocketItemModel::onDropItem(const MWWorld::Ptr &item, int count) { // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0) diff --git a/apps/openmw/mwgui/pickpocketitemmodel.hpp b/apps/openmw/mwgui/pickpocketitemmodel.hpp index 9aa686c39..83caf2ffd 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.hpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.hpp @@ -17,7 +17,6 @@ namespace MWGui virtual size_t getItemCount(); virtual void update(); virtual void removeItem (const ItemStack& item, size_t count); - virtual bool allowedToInsertItems() const; virtual void onClose(); virtual bool onDropItem(const MWWorld::Ptr &item, int count); virtual bool onTakeItem(const MWWorld::Ptr &item, int count); From f0649849b87be452acbab3307a145992c16f0101 Mon Sep 17 00:00:00 2001 From: rexelion Date: Sat, 11 Nov 2017 12:00:23 +0000 Subject: [PATCH 508/521] changed variable name to be more descriptive --- apps/openmw/mwmechanics/aicombat.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 07fb455f3..ee1013fe4 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -503,8 +503,8 @@ namespace MWMechanics targetWeapon = *weaponSlot; } - bool isRangedCombat = false; - float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(isRangedCombat); + bool targetUsesRanged = false; + float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(targetUsesRanged); if (mMovement.mPosition[0] || mMovement.mPosition[1]) { @@ -524,16 +524,17 @@ namespace MWMechanics } } - // Below behavior for backing up during ranged combat differs from vanilla. - // Vanilla is observed as backing up only as far as fCombatDistance or - // opponent's weapon range, or not backing up if opponent is also using a ranged weapon + // Backing up behaviour + // Actor backs up slightly further away than opponent's weapon range + // (in vanilla - only as far as oponent's weapon range), + // or not at all if opponent is using a ranged weapon if (isDistantCombat) { // actor should not back up into water if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f)) return; - if (!isRangedCombat && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon + if (!targetUsesRanged && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon mMovement.mPosition[1] = -1; } } From 8c0dcd8b2b8276f2030bd00053540febe7df6874 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 11 Nov 2017 19:46:59 +0400 Subject: [PATCH 509/521] Do not track a nearest actor during combat and pursue (bug #4179) --- apps/openmw/mwmechanics/actors.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a144911c5..ce8ad8f66 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1230,8 +1230,13 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; + MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + // Unconsious actor can not track target - if (!iter->first.getClass().getCreatureStats(iter->first).getKnockedDown()) + // Also actors in combat and pursue mode do not bother to headtrack + if (!stats.getKnockedDown() && + !stats.getAiSequence().isInCombat() && + !stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue)) { for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) { @@ -1239,8 +1244,9 @@ namespace MWMechanics continue; updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); } - iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } + + iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget); } if (iter->first.getClass().isNpc() && iter->first != player) From 6e4f6c4bd5b5b7e8be7573693ad39f9111b7a65f Mon Sep 17 00:00:00 2001 From: Grigorii Latyshev Date: Mon, 13 Nov 2017 21:36:55 +0100 Subject: [PATCH 510/521] Change abs to std::abs --- apps/openmw/mwmechanics/aipursue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 27d4ab0cb..fd8b5752a 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -55,7 +55,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte float pathTolerance = 100.0; if (pathTo(actor, dest, duration, pathTolerance) && - abs(dest.mZ - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction + std::abs(dest.mZ - aPos.pos[2]) < pathTolerance) // check the true distance in case the target is far away in Z-direction { target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; From 5a93b6a324f0bcf5c4ac7a644288616bf5f35f9f Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:29:01 +0100 Subject: [PATCH 511/521] Enable word-wrapping for the console history --- files/mygui/openmw_console.layout | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index 103cdcf14..a58327a48 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -13,6 +13,7 @@ + From 7c5d2a1ac4d41720d34c51574bfd67c7c98bdba8 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:29:50 +0100 Subject: [PATCH 512/521] Update dialogue topics list after result script is run Regression from 0.42. --- apps/openmw/mwgui/dialogue.cpp | 14 +++++++++++++- apps/openmw/mwgui/dialogue.hpp | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a7ae85ea..14bbe81ef 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -45,6 +45,11 @@ namespace MWGui mWindow->addResponse(title, text, mNeedMargin); } + void updateTopics() + { + mWindow->updateTopics(); + } + private: DialogueWindow* mWindow; bool mNeedMargin; @@ -91,6 +96,7 @@ namespace MWGui type = MWBase::MechanicsManager::PT_Bribe1000; MWBase::Environment::get().getDialogueManager()->persuade(type, mCallback.get()); + mCallback->updateTopics(); setVisible(false); } @@ -395,6 +401,8 @@ namespace MWGui else if (topic == gmst.find("sRepair")->getString()) MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr); } + else + updateTopics(); } } @@ -432,7 +440,9 @@ namespace MWGui setTitle(mPtr.getClass().getName(mPtr)); - updateTopicsPane(); + updateTopics(); + updateTopicsPane(); // force update for new services + updateDisposition(); restock(); } @@ -620,11 +630,13 @@ namespace MWGui void DialogueWindow::onTopicActivated(const std::string &topicId) { MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId, mCallback.get()); + updateTopics(); } void DialogueWindow::onChoiceActivated(int id) { MWBase::Environment::get().getDialogueManager()->questionAnswered(id, mCallback.get()); + updateTopics(); } void DialogueWindow::onGoodbyeActivated() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 277032513..2538602c6 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -131,8 +131,9 @@ namespace MWGui void onFrame(float dt); void clear() { resetReference(); } - protected: void updateTopics(); + + protected: void updateTopicsPane(); bool isCompanion(const MWWorld::Ptr& actor); bool isCompanion(); From c36d250044228b2af0b46324ccf4adbd2ff278f2 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:30:21 +0100 Subject: [PATCH 513/521] Parse dialogue text for keywords after the resultscript runs (Fixes #4210) --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 88e65e535..1f6de04e5 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -77,6 +77,7 @@ namespace MWDialogue void DialogueManager::parseText (const std::string& text) { + updateActorKnownTopics(); std::vector hypertext = HyperTextParser::parseHyperText(text); for (std::vector::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok) @@ -145,18 +146,13 @@ namespace MWDialogue // TODO play sound } - // first topics update so that parseText knows the keywords to highlight - updateActorKnownTopics(); - - parseText (info->mResponse); MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); callback->addResponse("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript, mActor); mLastTopic = it->mId; - // update topics again to accommodate changes resulting from executeScript - updateActorKnownTopics(); + parseText (info->mResponse); return true; } @@ -252,8 +248,6 @@ namespace MWDialogue const ESM::DialInfo* info = filter.search(dialogue, true); if (info) { - parseText (info->mResponse); - std::string title; if (dialogue.mType==ESM::Dialogue::Persuasion) { @@ -292,6 +286,8 @@ namespace MWDialogue executeScript (info->mResultScript, mActor); + parseText (info->mResponse); + mLastTopic = topic; } } From 60fba7acd83f13e38465f23fec13c631818c7574 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Wed, 15 Nov 2017 16:43:36 +0100 Subject: [PATCH 514/521] Fix reorder warning --- apps/openmw/mwmechanics/character.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6de18fe62..016d88289 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,8 +196,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener float mSecondsOfSwimming; float mSecondsOfRunning; - float mTimeUntilWake; - MWWorld::ConstPtr mHeadTrackTarget; float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning @@ -206,6 +204,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener bool mAttackingOrSpell; + float mTimeUntilWake; + void setAttackTypeBasedOnMovement(); void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); From 36f4f0ef85ffe74ab27fabe68f02f7c569cc1559 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Thu, 16 Nov 2017 17:56:44 +0100 Subject: [PATCH 515/521] Don't increase simulationTime while the game is minimized (Fixes #4211) --- apps/openmw/engine.cpp | 23 +++++++++++------------ apps/openmw/engine.hpp | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3e5ab7ce6..e2b63232d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -79,12 +79,14 @@ void OMW::Engine::executeLocalScripts() } } -void OMW::Engine::frame(float frametime) +bool OMW::Engine::frame(float frametime) { try { mStartTick = mViewer->getStartTick(); + mEnvironment.setFrameDuration(frametime); + // update input mEnvironment.getInputManager()->update(frametime, false); @@ -92,7 +94,7 @@ void OMW::Engine::frame(float frametime) // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) if (!mEnvironment.getInputManager()->isWindowVisible()) - return; + return false; // sound if (mUseSound) @@ -187,8 +189,9 @@ void OMW::Engine::frame(float frametime) } catch (const std::exception& e) { - std::cerr << "Error in framelistener: " << e.what() << std::endl; + std::cerr << "Error in frame: " << e.what() << std::endl; } + return true; } OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) @@ -686,17 +689,9 @@ void OMW::Engine::go() frameTimer.setStartTick(); dt = std::min(dt, 0.2); - bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); - if (!guiActive) - simulationTime += dt; - mViewer->advance(simulationTime); - mEnvironment.setFrameDuration(dt); - - frame(dt); - - if (!mEnvironment.getInputManager()->isWindowVisible()) + if (!frame(dt)) { OpenThreads::Thread::microSleep(5000); continue; @@ -709,6 +704,10 @@ void OMW::Engine::go() mEnvironment.getWorld()->updateWindowManager(); mViewer->renderingTraversals(); + + bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); + if (!guiActive) + simulationTime += dt; } mEnvironment.limitFrameRate(frameTimer.time_s()); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index bf144bfed..2fff91c7e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -118,7 +118,7 @@ namespace OMW void executeLocalScripts(); - void frame (float dt); + bool frame (float dt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); From ea2bbce68a6c70d3cfb3de187ba73bb99e6c9187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 18 Nov 2017 19:27:09 +0100 Subject: [PATCH 516/521] Fix memory leak in WindowManager --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ccdd6916c..4992716aa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -530,6 +530,7 @@ namespace MWGui delete mDragAndDrop; delete mSoulgemDialog; delete mCursorManager; + delete mToolTips; cleanupGarbage(); From f896c9acb63b9d6fb1e2274baf21e5beab0057b7 Mon Sep 17 00:00:00 2001 From: jbo-85 Date: Sun, 19 Nov 2017 11:56:24 +0100 Subject: [PATCH 517/521] Fix search paths in FindSDL2.cmake to find SDL2 built from source --- cmake/FindSDL2.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 25105f1e2..4f2be8c42 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -70,10 +70,10 @@ endif() libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h HINTS $ENV{SDL2DIR} - PATH_SUFFIXES include SDL2 + PATH_SUFFIXES include SDL2 include/SDL2 FIND_LIBRARY SDL2 HINTS $ENV{SDL2DIR} - PATH_SUFFIXES ${_sdl_lib_suffix} + PATH_SUFFIXES lib ${_sdl_lib_suffix} ) libfind_version_n_header(SDL2 NAMES SDL_version.h DEFINES SDL_MAJOR_VERSION SDL_MINOR_VERSION SDL_PATCHLEVEL) @@ -85,7 +85,7 @@ IF(NOT SDL2_BUILDING_LIBRARY AND NOT APPLE) libfind_pkg_detect(SDL2MAIN sdl2 FIND_LIBRARY SDL2main HINTS $ENV{SDL2DIR} - PATH_SUFFIXES ${_sdl_lib_suffix} + PATH_SUFFIXES lib ${_sdl_lib_suffix} ) set(SDL2MAIN_FIND_QUIETLY TRUE) libfind_process(SDL2MAIN) From 60d0c83cca7664a5d300db0004d5b45eda1dcbc0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 20 Nov 2017 17:39:28 +0400 Subject: [PATCH 518/521] Handle 128px Tx_menubook_topics textures --- apps/openmw/mwgui/journalwindow.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 30a440b58..3fbe44f95 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -203,9 +203,20 @@ namespace int cancelLeft = getWidget(CancelBTN)->getPosition().left; int cancelRight = getWidget(CancelBTN)->getPosition().left + getWidget(CancelBTN)->getSize().width; - getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); getWidget(QuestsBTN)->setPosition(cancelRight, getWidget(QuestsBTN)->getPosition().top); + // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. + // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. + if (getWidget(TopicsBTN)->getSize().width == 64) + { + getWidget(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + else + { + int questLeft = getWidget(QuestsBTN)->getPosition().left; + getWidget(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget(TopicsBTN)->getPosition().top); + } + mQuestMode = false; mAllQuests = false; mOptionsMode = false; From 9fda3b6db479b61a5e52c4cdce7208bdabac72a7 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:11:28 +0100 Subject: [PATCH 519/521] Fix NumericEditBox behavior broken by switch to std::stoi For some reason stoi doesn't throw an error for '1foo' while 'foo1' does. Now the edit box flat out rejects any non-digit key events. --- components/widgets/numericeditbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/widgets/numericeditbox.cpp b/components/widgets/numericeditbox.cpp index 6e884a091..ee2c30a7b 100644 --- a/components/widgets/numericeditbox.cpp +++ b/components/widgets/numericeditbox.cpp @@ -87,7 +87,7 @@ namespace Gui setValue(std::max(mValue-1, mMinValue)); eventValueChanged(mValue); } - else + else if (character == 0 || (character >= '0' && character <= '9')) Base::onKeyButtonPressed(key, character); } From a3f821cdcd60cf7ad333c3b0af0042424e7c27e1 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:28:51 +0100 Subject: [PATCH 520/521] Disable keyboard for trade +/- buttons For one, because their RepeatClick handler breaks the keyboard function, and because its redundant anyway (just press Up/Down arrow with the edit box focused to do the same thing) --- files/mygui/openmw_trade_window.layout | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index ebfe9b30f..4e2fc6e6d 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -43,9 +43,11 @@ + + From cc3c27f2418cd50ad7930d701c793d0d2bfda679 Mon Sep 17 00:00:00 2001 From: scrawl <720642+scrawl@users.noreply.github.com> Date: Mon, 20 Nov 2017 23:55:15 +0100 Subject: [PATCH 521/521] Clean up layout files to use Spacer class --- files/mygui/openmw_alchemy_window.layout | 4 +--- files/mygui/openmw_chargen_birth.layout | 4 +--- files/mygui/openmw_chargen_class.layout | 4 +--- files/mygui/openmw_chargen_create_class.layout | 4 +--- files/mygui/openmw_chargen_race.layout | 4 +--- files/mygui/openmw_chargen_review.layout | 4 +--- files/mygui/openmw_edit_effect.layout | 4 +--- files/mygui/openmw_edit_note.layout | 4 +--- files/mygui/openmw_enchanting_dialog.layout | 8 ++------ files/mygui/openmw_levelup_dialog.layout | 4 +--- files/mygui/openmw_recharge_dialog.layout | 4 +--- files/mygui/openmw_repair.layout | 4 +--- files/mygui/openmw_spellcreation_dialog.layout | 4 +--- files/mygui/openmw_tooltips.layout | 8 ++------ files/mygui/openmw_wait_dialog.layout | 4 +--- 15 files changed, 17 insertions(+), 51 deletions(-) diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index 8a1bf1347..a8e5431fb 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -76,9 +76,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index d93249c03..a137d83d1 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -17,9 +17,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index d875fae22..98c8e4fde 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -74,9 +74,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index e2920c742..c04cfe064 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -75,9 +75,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 04bd9cc53..31f0436d5 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -76,9 +76,7 @@ - - - + diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index 1099fcd3b..927296fad 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -112,9 +112,7 @@ - - - + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 376e87efa..c2429d24b 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -94,9 +94,7 @@ - - - + diff --git a/files/mygui/openmw_edit_note.layout b/files/mygui/openmw_edit_note.layout index 7039c719e..edf53bde7 100644 --- a/files/mygui/openmw_edit_note.layout +++ b/files/mygui/openmw_edit_note.layout @@ -16,9 +16,7 @@ - - - + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 6a08e6fd0..ed3cfb03e 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -36,9 +36,7 @@ - - - + @@ -141,9 +139,7 @@ - - - + diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 66855373a..7849d507f 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -156,9 +156,7 @@ - - - + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index 200d345e3..626039065 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -27,9 +27,7 @@ - - - + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index abc429594..bf58b6c81 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -34,9 +34,7 @@ - - - + diff --git a/files/mygui/openmw_spellcreation_dialog.layout b/files/mygui/openmw_spellcreation_dialog.layout index e14674ad6..e7c27655d 100644 --- a/files/mygui/openmw_spellcreation_dialog.layout +++ b/files/mygui/openmw_spellcreation_dialog.layout @@ -68,9 +68,7 @@ - - - + diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index c038066f1..bdc224ecd 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -103,9 +103,7 @@ - - - + @@ -122,9 +120,7 @@ - - - + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 4bc60ceb4..b02db3764 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -26,9 +26,7 @@ - - - +